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(&region->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(&region->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(&region->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);



Reply via email to