[PATCH RFC v2 46/50] samples/kvm: Implement get_pfn provider operation

From: Ackerley Tng via B4 Relay

Date: Thu Oct 22 2026 - 19:42:15 EST


From: Ackerley Tng <ackerleytng@xxxxxxxxxx>

Implement the .get_pfn callback in mps_gmem_provider_ops to operate as a
direct PFN provider for guest_memfd.

Implementing .get_pfn satisfies guest_memfd's provider operations
requirement, enabling mem_provider_sample files to be attached as
resource_fd memory providers for guest_memfd.

In mps_gmem_get_pfn(), return the physical frame number corresponding to
the requested index from the CMA reservation, returning -EFAULT if the
page was marked absent via MPS_SET_PRESENT.

Checking test_bit(index, info->absent) is done locklessly without
holding info->lock:
- test_bit() is an atomic memory read.
- Locklessness prevents lock inversion and deadlocks. In guest_memfd,
the guest page fault path (kvm_gmem_get_pfn()) holds
filemap_invalidate_lock_shared while calling .get_pfn(). Avoiding
info->lock in .get_pfn() ensures no lock inversions exist between
filemap_invalidate_lock and info->lock.
- Similarly, while kvm_gmem_revoke() now takes an explicit pfn and avoids
calling back into .get_pfn(), avoiding info->lock in .get_pfn() keeps
the lookup path completely lock-free and robust.

Signed-off-by: Ackerley Tng <ackerleytng@xxxxxxxxxx>
---
samples/kvm/mem_provider_sample.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/samples/kvm/mem_provider_sample.c b/samples/kvm/mem_provider_sample.c
index d9e57484c3933..a43c76d2259e7 100644
--- a/samples/kvm/mem_provider_sample.c
+++ b/samples/kvm/mem_provider_sample.c
@@ -132,9 +132,29 @@ static void mps_gmem_release(void *provider)
fput(resource_file);
}

+static int mps_gmem_get_pfn(void *provider, pgoff_t index, unsigned long *pfn,
+ int *max_order)
+{
+ struct file *resource_file = provider;
+ struct mps_info *info = resource_file->private_data;
+
+ if (index >= info->npages)
+ return -EINVAL;
+
+ if (test_bit(index, info->absent))
+ return -EFAULT;
+
+ *pfn = info->base_pfn + index;
+ if (max_order)
+ *max_order = 0;
+
+ return 0;
+}
+
static const struct guest_memfd_provider_operations mps_gmem_provider_ops = {
.attach = mps_gmem_attach,
.release = mps_gmem_release,
+ .get_pfn = mps_gmem_get_pfn,
};

static const struct file_operations mps_file_fops = {

--
2.56.0.257.gf7497c7d27-goog