Skip to content

Commit 87af633

Browse files
roygerjgross1
authored andcommitted
x86/xen: fix balloon target initialization for PVH dom0
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>
1 parent 0f2946b commit 87af633

File tree

3 files changed

+34
-13
lines changed

3 files changed

+34
-13
lines changed

arch/x86/xen/enlighten.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ EXPORT_SYMBOL(xen_start_flags);
7070
*/
7171
struct shared_info *HYPERVISOR_shared_info = &xen_dummy_shared_info;
7272

73+
/* Number of pages released from the initial allocation. */
74+
unsigned long xen_released_pages;
75+
7376
static __ref void xen_get_vendor(void)
7477
{
7578
init_cpu_devs();
@@ -466,6 +469,13 @@ int __init arch_xen_unpopulated_init(struct resource **res)
466469
xen_free_unpopulated_pages(1, &pg);
467470
}
468471

472+
/*
473+
* Account for the region being in the physmap but unpopulated.
474+
* The value in xen_released_pages is used by the balloon
475+
* driver to know how much of the physmap is unpopulated and
476+
* set an accurate initial memory target.
477+
*/
478+
xen_released_pages += xen_extra_mem[i].n_pfns;
469479
/* Zero so region is not also added to the balloon driver. */
470480
xen_extra_mem[i].n_pfns = 0;
471481
}

arch/x86/xen/setup.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@
3737

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

40-
/* Number of pages released from the initial allocation. */
41-
unsigned long xen_released_pages;
42-
4340
/* Memory map would allow PCI passthrough. */
4441
bool xen_pv_pci_possible;
4542

drivers/xen/balloon.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ void xen_free_ballooned_pages(unsigned int nr_pages, struct page **pages)
679679
}
680680
EXPORT_SYMBOL(xen_free_ballooned_pages);
681681

682-
static void __init balloon_add_regions(void)
682+
static int __init balloon_add_regions(void)
683683
{
684684
unsigned long start_pfn, pages;
685685
unsigned long pfn, extra_pfn_end;
@@ -702,26 +702,38 @@ static void __init balloon_add_regions(void)
702702
for (pfn = start_pfn; pfn < extra_pfn_end; pfn++)
703703
balloon_append(pfn_to_page(pfn));
704704

705-
balloon_stats.total_pages += extra_pfn_end - start_pfn;
705+
/*
706+
* Extra regions are accounted for in the physmap, but need
707+
* decreasing from current_pages to balloon down the initial
708+
* allocation, because they are already accounted for in
709+
* total_pages.
710+
*/
711+
if (extra_pfn_end - start_pfn >= balloon_stats.current_pages) {
712+
WARN(1, "Extra pages underflow current target");
713+
return -ERANGE;
714+
}
715+
balloon_stats.current_pages -= extra_pfn_end - start_pfn;
706716
}
717+
718+
return 0;
707719
}
708720

709721
static int __init balloon_init(void)
710722
{
711723
struct task_struct *task;
724+
int rc;
712725

713726
if (!xen_domain())
714727
return -ENODEV;
715728

716729
pr_info("Initialising balloon driver\n");
717730

718-
#ifdef CONFIG_XEN_PV
719-
balloon_stats.current_pages = xen_pv_domain()
720-
? min(xen_start_info->nr_pages - xen_released_pages, max_pfn)
721-
: get_num_physpages();
722-
#else
723-
balloon_stats.current_pages = get_num_physpages();
724-
#endif
731+
if (xen_released_pages >= get_num_physpages()) {
732+
WARN(1, "Released pages underflow current target");
733+
return -ERANGE;
734+
}
735+
736+
balloon_stats.current_pages = get_num_physpages() - xen_released_pages;
725737
balloon_stats.target_pages = balloon_stats.current_pages;
726738
balloon_stats.balloon_low = 0;
727739
balloon_stats.balloon_high = 0;
@@ -738,7 +750,9 @@ static int __init balloon_init(void)
738750
register_sysctl_init("xen/balloon", balloon_table);
739751
#endif
740752

741-
balloon_add_regions();
753+
rc = balloon_add_regions();
754+
if (rc)
755+
return rc;
742756

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

0 commit comments

Comments
 (0)