On 3/3/26 16:23, Stanislav Kinsburskii wrote:
Deposit enough pages up front to avoid guest address space region creation
failures due to low memory. This also speeds up guest creation.
Calculate the required number of pages based on the guest's physical
address space size, rounded up to 1 GB chunks. Even the smallest guests are
assumed to need at least 1 GB worth of deposits. This is because every
guest requires tens of megabytes of deposited pages for hypervisor
overhead, making smaller deposits impractical.
Estimating in 1 GB chunks prevents over-depositing for larger guests while
accepting some over-deposit for smaller ones. This trade-off keeps the
estimate close to actual needs for larger guests.
Also withdraw the deposited pages if address space region creation fails.
Signed-off-by: Stanislav Kinsburskii <[email protected]>
---
drivers/hv/mshv_root_main.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 48c842b6938d..cb5b4505f8eb 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -39,6 +39,7 @@
#define MSHV_PARTITION_DEPOSIT_PAGES (SZ_512K >> PAGE_SHIFT)
#define MSHV_PARTITION_DEPOSIT_PAGES_NESTED (20 * SZ_1M >> PAGE_SHIFT)
#define MSHV_VP_DEPOSIT_PAGES (1 * SZ_1M >> PAGE_SHIFT)
+#define MSHV_1G_DEPOSIT_PAGES (6 * SZ_1M >> PAGE_SHIFT)
MODULE_AUTHOR("Microsoft");
MODULE_LICENSE("GPL");
@@ -1324,6 +1325,18 @@ static int mshv_prepare_pinned_region(struct
mshv_mem_region *region)
return ret;
}
+static u64
+mshv_region_deposit_slat_pages(struct mshv_mem_region *region)
+{
+ u64 region_in_gbs, slat_pages;
+
+ /* SLAT needs 6 MB per 1 GB of address space. */
+ region_in_gbs = DIV_ROUND_UP(region->nr_pages << HV_HYP_PAGE_SHIFT,
SZ_1G);
+ slat_pages = region_in_gbs * MSHV_1G_DEPOSIT_PAGES;
+
+ return slat_pages;
+}
+
/*
* This maps two things: guest RAM and for pci passthru mmio space.
*
@@ -1364,6 +1377,11 @@ mshv_map_user_memory(struct mshv_partition *partition,
if (ret)
return ret;
+ ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id,
+ mshv_region_deposit_slat_pages(region));
+ if (ret)
+ goto free_region;
+
Also, for MSHV_REGION_TYPE_MEM_PINNED, deposit is not needed.
switch (region->mreg_type) {
case MSHV_REGION_TYPE_MEM_PINNED:
ret = mshv_prepare_pinned_region(region);
@@ -1392,7 +1410,7 @@ mshv_map_user_memory(struct mshv_partition *partition,
region->hv_map_flags, ret);
if (ret)
- goto errout;
+ goto withdraw_memory;
spin_lock(&partition->pt_mem_regions_lock);
hlist_add_head(®ion->hnode, &partition->pt_mem_regions);
@@ -1400,7 +1418,10 @@ mshv_map_user_memory(struct mshv_partition *partition,
return 0;
-errout:
+withdraw_memory:
+ hv_call_withdraw_memory(mshv_region_deposit_slat_pages(region),
+ NUMA_NO_NODE, partition->pt_id);
+free_region:
vfree(region);
return ret;
}