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;
}