Skip to content

Commit

Permalink
x86/xen: fix balloon target initialization for PVH dom0
Browse files Browse the repository at this point in the history
PVH dom0 re-uses logic from PV dom0, in which RAM ranges not assigned to
dom0 are re-used as scratch memory to map foreign and grant pages.  Such
logic relies on reporting those unpopulated ranges as RAM to Linux, and
mark them as reserved.  This way Linux creates the underlying page
structures required for metadata management.

Such approach works fine on PV because the initial balloon target is
calculated using specific Xen data, that doesn't take into account the
memory type changes described above.  However on HVM and PVH the initial
balloon target is calculated using get_num_physpages(), and that function
does take into account the unpopulated RAM regions used as scratch space
for remote domain mappings.

This leads to PVH dom0 having an incorrect initial balloon target, which
causes malfunction (excessive memory freeing) of the balloon driver if the
dom0 memory target is later adjusted from the toolstack.

Fix this by using xen_released_pages to account for any pages that are part
of the memory map, but are already unpopulated when the balloon driver is
initialized.  This accounts for any regions used for scratch remote
mappings.  Note on x86 xen_released_pages definition is moved to
enlighten.c so it's uniformly available for all Xen-enabled builds.

Take the opportunity to unify PV with PVH/HVM guests regarding the usage of
get_num_physpages(), as that avoids having to add different logic for PV vs
PVH in both balloon_add_regions() and arch_xen_unpopulated_init().

Much like a6aa4eb, the code in this changeset should have been part of
38620fc.

Fixes: a6aa4eb ('xen/x86: add extra pages to unpopulated-alloc if available')
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Cc: stable@vger.kernel.org
Signed-off-by: Juergen Gross <jgross@suse.com>
Message-ID: <20250407082838.65495-1-roger.pau@citrix.com>
  • Loading branch information
Roger Pau Monne authored and Juergen Gross committed Apr 7, 2025
1 parent 0f2946b commit 87af633
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 13 deletions.
10 changes: 10 additions & 0 deletions arch/x86/xen/enlighten.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ EXPORT_SYMBOL(xen_start_flags);
*/
struct shared_info *HYPERVISOR_shared_info = &xen_dummy_shared_info;

/* Number of pages released from the initial allocation. */
unsigned long xen_released_pages;

static __ref void xen_get_vendor(void)
{
init_cpu_devs();
Expand Down Expand Up @@ -466,6 +469,13 @@ int __init arch_xen_unpopulated_init(struct resource **res)
xen_free_unpopulated_pages(1, &pg);
}

/*
* Account for the region being in the physmap but unpopulated.
* The value in xen_released_pages is used by the balloon
* driver to know how much of the physmap is unpopulated and
* set an accurate initial memory target.
*/
xen_released_pages += xen_extra_mem[i].n_pfns;
/* Zero so region is not also added to the balloon driver. */
xen_extra_mem[i].n_pfns = 0;
}
Expand Down
3 changes: 0 additions & 3 deletions arch/x86/xen/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@

#define GB(x) ((uint64_t)(x) * 1024 * 1024 * 1024)

/* Number of pages released from the initial allocation. */
unsigned long xen_released_pages;

/* Memory map would allow PCI passthrough. */
bool xen_pv_pci_possible;

Expand Down
34 changes: 24 additions & 10 deletions drivers/xen/balloon.c
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ void xen_free_ballooned_pages(unsigned int nr_pages, struct page **pages)
}
EXPORT_SYMBOL(xen_free_ballooned_pages);

static void __init balloon_add_regions(void)
static int __init balloon_add_regions(void)
{
unsigned long start_pfn, pages;
unsigned long pfn, extra_pfn_end;
Expand All @@ -702,26 +702,38 @@ static void __init balloon_add_regions(void)
for (pfn = start_pfn; pfn < extra_pfn_end; pfn++)
balloon_append(pfn_to_page(pfn));

balloon_stats.total_pages += extra_pfn_end - start_pfn;
/*
* Extra regions are accounted for in the physmap, but need
* decreasing from current_pages to balloon down the initial
* allocation, because they are already accounted for in
* total_pages.
*/
if (extra_pfn_end - start_pfn >= balloon_stats.current_pages) {
WARN(1, "Extra pages underflow current target");
return -ERANGE;
}
balloon_stats.current_pages -= extra_pfn_end - start_pfn;
}

return 0;
}

static int __init balloon_init(void)
{
struct task_struct *task;
int rc;

if (!xen_domain())
return -ENODEV;

pr_info("Initialising balloon driver\n");

#ifdef CONFIG_XEN_PV
balloon_stats.current_pages = xen_pv_domain()
? min(xen_start_info->nr_pages - xen_released_pages, max_pfn)
: get_num_physpages();
#else
balloon_stats.current_pages = get_num_physpages();
#endif
if (xen_released_pages >= get_num_physpages()) {
WARN(1, "Released pages underflow current target");
return -ERANGE;
}

balloon_stats.current_pages = get_num_physpages() - xen_released_pages;
balloon_stats.target_pages = balloon_stats.current_pages;
balloon_stats.balloon_low = 0;
balloon_stats.balloon_high = 0;
Expand All @@ -738,7 +750,9 @@ static int __init balloon_init(void)
register_sysctl_init("xen/balloon", balloon_table);
#endif

balloon_add_regions();
rc = balloon_add_regions();
if (rc)
return rc;

task = kthread_run(balloon_thread, NULL, "xen-balloon");
if (IS_ERR(task)) {
Expand Down

0 comments on commit 87af633

Please sign in to comment.