[RFC PATCH 15/18] KVM: guest_memfd: Add KVM Userfault support

From: James Houghton
Date: Wed Jul 10 2024 - 19:47:10 EST


We now have to pass our struct kvm into __kvm_gmem_get_pfn to know if a
gfn is userfault-enabled or not.

For faults on userfault-enabled gfns, indicate this to the caller by
setting *pfn to KVM_PFN_ERR_USERFAULT. Architectures may use this to
know to return a userfault to userspace, though they should be careful
to set a value for *pfn before calling (e.g. KVM_PFN_ERR_FAULT).

While we're at it, set *pfn to KVM_PFN_ERR_HWPOISON for accesses to
poisoned gfns.

Signed-off-by: James Houghton <jthoughton@xxxxxxxxxx>
---
virt/kvm/guest_memfd.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 9148b9679bb1..ba7a981e3396 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -542,8 +542,9 @@ void kvm_gmem_unbind(struct kvm_memory_slot *slot)
fput(file);
}

-static int __kvm_gmem_get_pfn(struct file *file, struct kvm_memory_slot *slot,
- gfn_t gfn, kvm_pfn_t *pfn, int *max_order, bool prepare)
+static int __kvm_gmem_get_pfn(struct kvm *kvm, struct file *file,
+ struct kvm_memory_slot *slot, gfn_t gfn, kvm_pfn_t *pfn,
+ int *max_order, bool prepare)
{
pgoff_t index = gfn - slot->base_gfn + slot->gmem.pgoff;
struct kvm_gmem *gmem = file->private_data;
@@ -551,6 +552,11 @@ static int __kvm_gmem_get_pfn(struct file *file, struct kvm_memory_slot *slot,
struct page *page;
int r;

+ if (gfn_has_userfault(kvm, gfn)) {
+ *pfn = KVM_PFN_ERR_USERFAULT;
+ return -EFAULT;
+ }
+
if (file != slot->gmem.file) {
WARN_ON_ONCE(slot->gmem.file);
return -EFAULT;
@@ -567,6 +573,7 @@ static int __kvm_gmem_get_pfn(struct file *file, struct kvm_memory_slot *slot,
return PTR_ERR(folio);

if (folio_test_hwpoison(folio)) {
+ *pfn = KVM_PFN_ERR_HWPOISON;
folio_unlock(folio);
folio_put(folio);
return -EHWPOISON;
@@ -594,7 +601,7 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
if (!file)
return -EFAULT;

- r = __kvm_gmem_get_pfn(file, slot, gfn, pfn, max_order, true);
+ r = __kvm_gmem_get_pfn(kvm, file, slot, gfn, pfn, max_order, true);
fput(file);
return r;
}
@@ -634,7 +641,8 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long
break;
}

- ret = __kvm_gmem_get_pfn(file, slot, gfn, &pfn, &max_order, false);
+ ret = __kvm_gmem_get_pfn(kvm, file, slot, gfn, &pfn,
+ &max_order, false);
if (ret)
break;

--
2.45.2.993.g49e7a77208-goog