This is a precursor and cleanup patch. - Introduce mshv_partition_destroy_region() to encapsulate memory region cleanup, including: - Removing the region from the partition's list - Regaining access for encrypted partitions - Unmapping only mapped pages for efficiency - Evicting and freeing the region
- Update mshv_unmap_user_memory() to call mshv_partition_destroy_region() instead of duplicating cleanup logic. - Update destroy_partition() to use mshv_partition_destroy_region() for all regions, removing the previous inlined cleanup loop. These changes eliminate code duplication, ensure consistent cleanup, and improve maintainability for both unmap and partition destruction paths. Signed-off-by: Stanislav Kinsburskii <[email protected]> --- drivers/hv/mshv_root_main.c | 83 ++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c index 5ed6bce334417..c0f6023e459c2 100644 --- a/drivers/hv/mshv_root_main.c +++ b/drivers/hv/mshv_root_main.c @@ -1386,13 +1386,59 @@ mshv_map_user_memory(struct mshv_partition *partition, return ret; } +static void mshv_partition_destroy_region(struct mshv_mem_region *region) +{ + struct mshv_partition *partition = region->partition; + u64 page_offset, page_count; + u32 unmap_flags = 0; + int ret; + + hlist_del(®ion->hnode); + + if (mshv_partition_encrypted(partition)) { + ret = mshv_partition_region_share(region); + if (ret) { + pt_err(partition, + "Failed to regain access to memory, unpinning user pages will fail and crash the host error: %d\n", + ret); + return; + } + } + + if (region->flags.large_pages) + unmap_flags |= HV_UNMAP_GPA_LARGE_PAGE; + + /* + * Unmap only the mapped pages to optimize performance, + * especially for large memory regions. + */ + for (page_offset = 0; page_offset < region->nr_pages; page_offset += page_count) { + page_count = 1; + if (!region->pages[page_offset]) + continue; + + for (; page_count < region->nr_pages - page_offset; page_count++) { + if (!region->pages[page_offset + page_count]) + break; + } + + /* ignore unmap failures and continue as process may be exiting */ + hv_call_unmap_gpa_pages(partition->pt_id, + region->start_gfn + page_offset, + page_count, unmap_flags); + } + + mshv_region_evict(region); + + vfree(region); +} + /* Called for unmapping both the guest ram and the mmio space */ static long mshv_unmap_user_memory(struct mshv_partition *partition, struct mshv_user_mem_region mem) { struct mshv_mem_region *region; - u32 unmap_flags = 0; if (!(mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP))) return -EINVAL; @@ -1407,18 +1453,7 @@ mshv_unmap_user_memory(struct mshv_partition *partition, region->nr_pages != HVPFN_DOWN(mem.size)) return -EINVAL; - hlist_del(®ion->hnode); - - if (region->flags.large_pages) - unmap_flags |= HV_UNMAP_GPA_LARGE_PAGE; - - /* ignore unmap failures and continue as process may be exiting */ - hv_call_unmap_gpa_pages(partition->pt_id, region->start_gfn, - region->nr_pages, unmap_flags); - - mshv_region_evict(region); - - vfree(region); + mshv_partition_destroy_region(region); return 0; } @@ -1754,8 +1789,8 @@ static void destroy_partition(struct mshv_partition *partition) { struct mshv_vp *vp; struct mshv_mem_region *region; - int i, ret; struct hlist_node *n; + int i; if (refcount_read(&partition->pt_ref_count)) { pt_err(partition, @@ -1815,25 +1850,9 @@ static void destroy_partition(struct mshv_partition *partition) remove_partition(partition); - /* Remove regions, regain access to the memory and unpin the pages */ hlist_for_each_entry_safe(region, n, &partition->pt_mem_regions, - hnode) { - hlist_del(®ion->hnode); - - if (mshv_partition_encrypted(partition)) { - ret = mshv_partition_region_share(region); - if (ret) { - pt_err(partition, - "Failed to regain access to memory, unpinning user pages will fail and crash the host error: %d\n", - ret); - return; - } - } - - mshv_region_evict(region); - - vfree(region); - } + hnode) + mshv_partition_destroy_region(region); /* Withdraw and free all pages we deposited */ hv_call_withdraw_memory(U64_MAX, NUMA_NO_NODE, partition->pt_id);
