static unsigned long handle_pg_range()

in hv_balloon.c [845:926]


static unsigned long handle_pg_range(unsigned long pg_start,
					unsigned long pg_count)
{
	unsigned long start_pfn = pg_start;
	unsigned long pfn_cnt = pg_count;
	unsigned long size;
	struct hv_hotadd_state *has;
	unsigned long pgs_ol = 0;
	unsigned long old_covered_state;
	unsigned long res = 0, flags;

	pr_debug("Hot adding %lu pages starting at pfn 0x%lx.\n", pg_count,
		pg_start);

	spin_lock_irqsave(&dm_device.ha_lock, flags);
	list_for_each_entry(has, &dm_device.ha_region_list, list) {
		/*
		 * If the pfn range we are dealing with is not in the current
		 * "hot add block", move on.
		 */
		if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn)
			continue;

		old_covered_state = has->covered_end_pfn;

		if (start_pfn < has->ha_end_pfn) {
			/*
			 * This is the case where we are backing pages
			 * in an already hot added region. Bring
			 * these pages online first.
			 */
			pgs_ol = has->ha_end_pfn - start_pfn;
			if (pgs_ol > pfn_cnt)
				pgs_ol = pfn_cnt;

			has->covered_end_pfn +=  pgs_ol;
			pfn_cnt -= pgs_ol;
			/*
			 * Check if the corresponding memory block is already
			 * online. It is possible to observe struct pages still
			 * being uninitialized here so check section instead.
			 * In case the section is online we need to bring the
			 * rest of pfns (which were not backed previously)
			 * online too.
			 */
			if (start_pfn > has->start_pfn &&
			    online_section_nr(pfn_to_section_nr(start_pfn)))
				hv_bring_pgs_online(has, start_pfn, pgs_ol);

		}

		if ((has->ha_end_pfn < has->end_pfn) && (pfn_cnt > 0)) {
			/*
			 * We have some residual hot add range
			 * that needs to be hot added; hot add
			 * it now. Hot add a multiple of
			 * of HA_CHUNK that fully covers the pages
			 * we have.
			 */
			size = (has->end_pfn - has->ha_end_pfn);
			if (pfn_cnt <= size) {
				size = ((pfn_cnt / HA_CHUNK) * HA_CHUNK);
				if (pfn_cnt % HA_CHUNK)
					size += HA_CHUNK;
			} else {
				pfn_cnt = size;
			}
			spin_unlock_irqrestore(&dm_device.ha_lock, flags);
			hv_mem_hot_add(has->ha_end_pfn, size, pfn_cnt, has);
			spin_lock_irqsave(&dm_device.ha_lock, flags);
		}
		/*
		 * If we managed to online any pages that were given to us,
		 * we declare success.
		 */
		res = has->covered_end_pfn - old_covered_state;
		break;
	}
	spin_unlock_irqrestore(&dm_device.ha_lock, flags);

	return res;
}