in hv_balloon.c [785:843]
static int pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
{
struct hv_hotadd_state *has;
struct hv_hotadd_gap *gap;
unsigned long residual, new_inc;
int ret = 0;
unsigned long flags;
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;
/*
* If the current start pfn is not where the covered_end
* is, create a gap and update covered_end_pfn.
*/
if (has->covered_end_pfn != start_pfn) {
gap = kzalloc(sizeof(struct hv_hotadd_gap), GFP_ATOMIC);
if (!gap) {
ret = -ENOMEM;
break;
}
INIT_LIST_HEAD(&gap->list);
gap->start_pfn = has->covered_end_pfn;
gap->end_pfn = start_pfn;
list_add_tail(&gap->list, &has->gap_list);
has->covered_end_pfn = start_pfn;
}
/*
* If the current hot add-request extends beyond
* our current limit; extend it.
*/
if ((start_pfn + pfn_cnt) > has->end_pfn) {
residual = (start_pfn + pfn_cnt - has->end_pfn);
/*
* Extend the region by multiples of HA_CHUNK.
*/
new_inc = (residual / HA_CHUNK) * HA_CHUNK;
if (residual % HA_CHUNK)
new_inc += HA_CHUNK;
has->end_pfn += new_inc;
}
ret = 1;
break;
}
spin_unlock_irqrestore(&dm_device.ha_lock, flags);
return ret;
}