MSHV currently faults movable memory regions by taking mmap_read_lock()
around hmm_range_fault(). That prevents the fault path from handling VMAs
whose fault handlers need to drop mmap_lock, such as userfaultfd-backed
mappings.

Use hmm_range_fault_unlocked_timeout() instead. Passing a timeout of 0
preserves MSHV's existing unbounded retry behavior while letting the HMM
helper own mmap_lock acquisition and refresh range->notifier_seq internally
before walking the range. After the fault succeeds, MSHV still takes
mreg_mutex and checks mmu_interval_read_retry() before installing the pages
into the region, so the existing invalidation synchronization is preserved.

Fold the small fault-and-lock helper into mshv_region_range_fault(), since
the remaining retry path is just the standard "fault, take the driver lock,
check the interval notifier sequence" pattern.

Signed-off-by: Stanislav Kinsburskii <[email protected]>
---
 drivers/hv/mshv_regions.c |   54 ++++++++-------------------------------------
 1 file changed, 10 insertions(+), 44 deletions(-)

diff --git a/drivers/hv/mshv_regions.c b/drivers/hv/mshv_regions.c
index 6d65e5b42152..dddaade31b5d 100644
--- a/drivers/hv/mshv_regions.c
+++ b/drivers/hv/mshv_regions.c
@@ -381,46 +381,6 @@ int mshv_region_get(struct mshv_mem_region *region)
        return kref_get_unless_zero(&region->mreg_refcount);
 }
 
-/**
- * mshv_region_hmm_fault_and_lock - Handle HMM faults and lock the memory 
region
- * @region: Pointer to the memory region structure
- * @range: Pointer to the HMM range structure
- *
- * This function performs the following steps:
- * 1. Reads the notifier sequence for the HMM range.
- * 2. Acquires a read lock on the memory map.
- * 3. Handles HMM faults for the specified range.
- * 4. Releases the read lock on the memory map.
- * 5. If successful, locks the memory region mutex.
- * 6. Verifies if the notifier sequence has changed during the operation.
- *    If it has, releases the mutex and returns -EBUSY to match with
- *    hmm_range_fault() return code for repeating.
- *
- * Return: 0 on success, a negative error code otherwise.
- */
-static int mshv_region_hmm_fault_and_lock(struct mshv_mem_region *region,
-                                         struct hmm_range *range)
-{
-       int ret;
-
-       range->notifier_seq = mmu_interval_read_begin(range->notifier);
-       mmap_read_lock(region->mreg_mni.mm);
-       ret = hmm_range_fault(range);
-       mmap_read_unlock(region->mreg_mni.mm);
-       if (ret)
-               return ret;
-
-       mutex_lock(&region->mreg_mutex);
-
-       if (mmu_interval_read_retry(range->notifier, range->notifier_seq)) {
-               mutex_unlock(&region->mreg_mutex);
-               cond_resched();
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
 /**
  * mshv_region_range_fault - Handle memory range faults for a given region.
  * @region: Pointer to the memory region structure.
@@ -452,13 +412,19 @@ static int mshv_region_range_fault(struct mshv_mem_region 
*region,
        range.start = region->start_uaddr + page_offset * HV_HYP_PAGE_SIZE;
        range.end = range.start + page_count * HV_HYP_PAGE_SIZE;
 
-       do {
-               ret = mshv_region_hmm_fault_and_lock(region, &range);
-       } while (ret == -EBUSY);
-
+again:
+       ret = hmm_range_fault_unlocked_timeout(&range, 0);
        if (ret)
                goto out;
 
+       mutex_lock(&region->mreg_mutex);
+
+       if (mmu_interval_read_retry(range.notifier, range.notifier_seq)) {
+               mutex_unlock(&region->mreg_mutex);
+               cond_resched();
+               goto again;
+       }
+
        for (i = 0; i < page_count; i++)
                region->mreg_pages[page_offset + i] = hmm_pfn_to_page(pfns[i]);
 



Reply via email to