[PATCH 5/7] mshv: Pass pfns array explicitly through processing chain
From: Stanislav Kinsburskii
Date: Wed Apr 01 2026 - 18:13:47 EST
The current implementation relies on accessing region->pfns directly
within the pfn processing chain, making it difficult to use these
handlers with alternative pfn sources. This tight coupling limits
flexibility when processing pfns from different locations, such as
temporary arrays or external sources.
By threading the pfns pointer through the entire processing chain
(mshv_region_process_range, mshv_region_process_chunk, and all
handlers), we decouple the processing logic from the storage location.
This enables future enhancements like processing pfns from multiple
sources or implementing more sophisticated memory management strategies
without duplicating the core processing logic.
No functional change intended.
Signed-off-by: Stanislav Kinsburskii <skinsburskii@xxxxxxxxxxxxxxxxxxx>
---
drivers/hv/mshv_regions.c | 61 +++++++++++++++++++++++++++------------------
1 file changed, 37 insertions(+), 24 deletions(-)
diff --git a/drivers/hv/mshv_regions.c b/drivers/hv/mshv_regions.c
index a92381219758..120ce2588501 100644
--- a/drivers/hv/mshv_regions.c
+++ b/drivers/hv/mshv_regions.c
@@ -22,7 +22,7 @@
typedef int (*pfn_handler_t)(struct mshv_region *region, u32 flags,
u64 pfn_offset, u64 pfn_count,
- bool huge_page);
+ unsigned long *pfns, bool huge_page);
static const struct mmu_interval_notifier_ops mshv_region_mni_ops;
@@ -84,6 +84,7 @@ static int mshv_chunk_stride(struct page *page,
static long mshv_region_process_pfns(struct mshv_region *region,
u32 flags,
u64 pfn_offset, u64 pfn_count,
+ unsigned long *pfns,
pfn_handler_t handler)
{
u64 gfn = region->start_gfn + pfn_offset;
@@ -91,7 +92,7 @@ static long mshv_region_process_pfns(struct mshv_region *region,
unsigned long pfn;
int stride, ret;
- pfn = region->mreg_pfns[pfn_offset];
+ pfn = pfns[pfn_offset];
if (!pfn_valid(pfn))
return -EINVAL;
@@ -101,7 +102,7 @@ static long mshv_region_process_pfns(struct mshv_region *region,
/* Start at stride since the first stride is validated */
for (count = stride; count < pfn_count ; count += stride) {
- pfn = region->mreg_pfns[pfn_offset + count];
+ pfn = pfns[pfn_offset + count];
/* Break if current pfn is invalid */
if (!pfn_valid(pfn))
@@ -114,7 +115,7 @@ static long mshv_region_process_pfns(struct mshv_region *region,
break;
}
- ret = handler(region, flags, pfn_offset, count, stride > 1);
+ ret = handler(region, flags, pfn_offset, count, pfns, stride > 1);
if (ret)
return ret;
@@ -138,11 +139,12 @@ static long mshv_region_process_pfns(struct mshv_region *region,
static long mshv_region_process_hole(struct mshv_region *region,
u32 flags,
u64 pfn_offset, u64 pfn_count,
+ unsigned long *pfns,
pfn_handler_t handler)
{
long ret;
- ret = handler(region, flags, pfn_offset, pfn_count, 0);
+ ret = handler(region, flags, pfn_offset, pfn_count, pfns, 0);
if (ret)
return ret;
@@ -152,15 +154,16 @@ static long mshv_region_process_hole(struct mshv_region *region,
static long mshv_region_process_chunk(struct mshv_region *region,
u32 flags,
u64 pfn_offset, u64 pfn_count,
+ unsigned long *pfns,
pfn_handler_t handler)
{
- if (pfn_valid(region->mreg_pfns[pfn_offset]))
+ if (pfn_valid(pfns[pfn_offset]))
return mshv_region_process_pfns(region, flags,
- pfn_offset, pfn_count,
+ pfn_offset, pfn_count, pfns,
handler);
else
return mshv_region_process_hole(region, flags,
- pfn_offset, pfn_count,
+ pfn_offset, pfn_count, pfns,
handler);
}
@@ -170,12 +173,13 @@ static long mshv_region_process_chunk(struct mshv_region *region,
* @flags : Flags to pass to the handler.
* @pfn_offset: Offset into the region's PFNs array to start processing.
* @pfn_count : Number of PFNs to process.
+ * @pfns : Pointer to an array of PFNs corresponding to the region.
* @handler : Callback function to handle each chunk of contiguous
* valid PFNs.
*
- * Iterates over the specified range of PFNs in @region, skipping
- * invalid PFNs. For each contiguous chunk of valid PFNS, invokes
- * @handler via mshv_region_process_pfns.
+ * Iterates over the specified range of PFNs, skipping invalid PFNs.
+ * For each contiguous chunk of valid PFNS, invokes @handler via
+ * mshv_region_process_pfns.
*
* Note: The @handler callback must be able to handle PFNs backed by both
* normal and huge pages.
@@ -185,6 +189,7 @@ static long mshv_region_process_chunk(struct mshv_region *region,
static int mshv_region_process_range(struct mshv_region *region,
u32 flags,
u64 pfn_offset, u64 pfn_count,
+ unsigned long *pfns,
pfn_handler_t handler)
{
u64 start, end;
@@ -207,15 +212,14 @@ static int mshv_region_process_range(struct mshv_region *region,
* Accumulate contiguous pfns with the same validity
* (valid or not).
*/
- if (pfn_valid(region->mreg_pfns[start]) ==
- pfn_valid(region->mreg_pfns[end])) {
+ if (pfn_valid(pfns[start]) == pfn_valid(pfns[end])) {
end++;
continue;
}
ret = mshv_region_process_chunk(region, flags,
start, end - start,
- handler);
+ pfns, handler);
if (ret < 0)
return ret;
@@ -224,7 +228,7 @@ static int mshv_region_process_range(struct mshv_region *region,
ret = mshv_region_process_chunk(region, flags,
start, end - start,
- handler);
+ pfns, handler);
if (ret < 0)
return ret;
@@ -289,16 +293,17 @@ struct mshv_region *mshv_region_create(enum mshv_region_type type,
static int mshv_region_chunk_share(struct mshv_region *region,
u32 flags,
u64 pfn_offset, u64 pfn_count,
+ unsigned long *pfns,
bool huge_page)
{
- if (!pfn_valid(region->mreg_pfns[pfn_offset]))
+ if (!pfn_valid(pfns[pfn_offset]))
return -EINVAL;
if (huge_page)
flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE;
return hv_call_modify_spa_host_access(region->partition->pt_id,
- region->mreg_pfns + pfn_offset,
+ pfns + pfn_offset,
pfn_count,
HV_MAP_GPA_READABLE |
HV_MAP_GPA_WRITABLE,
@@ -311,22 +316,24 @@ static int mshv_region_share(struct mshv_region *region)
return mshv_region_process_range(region, flags,
0, region->nr_pfns,
+ region->mreg_pfns,
mshv_region_chunk_share);
}
static int mshv_region_chunk_unshare(struct mshv_region *region,
u32 flags,
u64 pfn_offset, u64 pfn_count,
+ unsigned long *pfns,
bool huge_page)
{
- if (!pfn_valid(region->mreg_pfns[pfn_offset]))
+ if (!pfn_valid(pfns[pfn_offset]))
return -EINVAL;
if (huge_page)
flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE;
return hv_call_modify_spa_host_access(region->partition->pt_id,
- region->mreg_pfns + pfn_offset,
+ pfns + pfn_offset,
pfn_count, 0,
flags, false);
}
@@ -337,12 +344,14 @@ static int mshv_region_unshare(struct mshv_region *region)
return mshv_region_process_range(region, flags,
0, region->nr_pfns,
+ region->mreg_pfns,
mshv_region_chunk_unshare);
}
static int mshv_region_chunk_remap(struct mshv_region *region,
u32 flags,
u64 pfn_offset, u64 pfn_count,
+ unsigned long *pfns,
bool huge_page)
{
/*
@@ -350,7 +359,7 @@ static int mshv_region_chunk_remap(struct mshv_region *region,
* hypervisor track dirty pages, enabling precopy live
* migration.
*/
- if (!pfn_valid(region->mreg_pfns[pfn_offset]))
+ if (!pfn_valid(pfns[pfn_offset]))
flags = HV_MAP_GPA_NO_ACCESS;
if (huge_page)
@@ -359,15 +368,17 @@ static int mshv_region_chunk_remap(struct mshv_region *region,
return hv_call_map_ram_pfns(region->partition->pt_id,
region->start_gfn + pfn_offset,
pfn_count, flags,
- region->mreg_pfns + pfn_offset);
+ pfns + pfn_offset);
}
static int mshv_region_remap_pfns(struct mshv_region *region,
u32 map_flags,
- u64 pfn_offset, u64 pfn_count)
+ u64 pfn_offset, u64 pfn_count,
+ unsigned long *pfns)
{
return mshv_region_process_range(region, map_flags,
pfn_offset, pfn_count,
+ pfns,
mshv_region_chunk_remap);
}
@@ -376,7 +387,8 @@ static int mshv_region_map(struct mshv_region *region)
u32 map_flags = region->hv_map_flags;
return mshv_region_remap_pfns(region, map_flags,
- 0, region->nr_pfns);
+ 0, region->nr_pfns,
+ region->mreg_pfns);
}
static void mshv_region_invalidate_pfns(struct mshv_region *region,
@@ -645,7 +657,8 @@ static int mshv_region_collect_and_map(struct mshv_region *region,
}
ret = mshv_region_remap_pfns(region, region->hv_map_flags,
- pfn_offset, pfn_count);
+ pfn_offset, pfn_count,
+ region->mreg_pfns);
mutex_unlock(®ion->mreg_mutex);
out: