* [RFC PATCH] RISC-V: KVM: Enable KVM_MEM_USERFAULT support
@ 2026-07-29 7:08 Bingyu.Xian
2026-07-29 7:25 ` sashiko-bot
0 siblings, 1 reply; 2+ messages in thread
From: Bingyu.Xian @ 2026-07-29 7:08 UTC (permalink / raw)
To: Anup Patel
Cc: Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, kvm-riscv, linux-riscv, linux-kernel,
Quan Zhou, James Houghton, Bingyu Xian
Add support for KVM_MEM_USERFAULT on RISC-V, which allows userspace
VMMs (e.g. QEMU) to handle post-copy live migration via userfaultfd.
The implementation follows the same pattern as x86 and arm64:
1. Force PAGE_SIZE mappings when KVM_MEM_USERFAULT is set on a memslot.
The userfault bitmap is tracked at PAGE_SIZE granularity, so block
mappings must be disabled to ensure every guest page fault reaches
the bitmap check in gstage_page_fault().
2. Check the userfault bitmap in gstage_page_fault() before installing
a G-stage mapping. If the faulting gfn is marked as pending
userspace resolution, prepare a KVM_EXIT_MEMORY_FAULT exit and
return 0 instead of proceeding with the mapping.
3. Advertise KVM_CAP_USERFAULT capability to userspace.
The mmu_notifier invalidation flush on userfault enable guarantees that
we never fault on a page that's already mapped, so the bitmap set bits
can be safely checked without holding the mmu_lock during the lookup.
Builds on the gstage fault path type cleanup ("RISC-V: KVM: Fix
spurious -EEXIST and clean up gstage fault path types"), which is sent
separately as an independent fix.
Depends-on: James Houghton's KVM_MEM_USERFAULT generic series
Link: https://lore.kernel.org/kvm/20260618205753.2600064-1-jthoughton@google.com/
Assisted-by: YuanSheng: deepseek-v4-pro
Co-developed-by: Quan Zhou <zhouquan@iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan@iscas.ac.cn>
Signed-off-by: Bingyu Xian <shanbeeyoo@gmail.com>
---
arch/riscv/kvm/mmu.c | 6 ++++--
arch/riscv/kvm/vcpu_exit.c | 7 +++++++
arch/riscv/kvm/vm.c | 1 +
3 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index d2a06a54be17..c33810b71d89 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -583,7 +583,9 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
else
vma_pageshift = PAGE_SHIFT;
vma_pagesize = 1ULL << vma_pageshift;
- if (logging || (vma->vm_flags & VM_PFNMAP))
+ bool userfault = !!(memslot->flags & KVM_MEM_USERFAULT);
+
+ if (logging || userfault || (vma->vm_flags & VM_PFNMAP))
vma_pagesize = PAGE_SIZE;
else if (is_hugetlb)
vma_pagesize = hugetlb_mapping_size(memslot, hva, vma_pagesize);
@@ -640,7 +642,7 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
* possible. Hugetlb mappings already selected their target size above,
* so do not promote them through the THP helper.
*/
- if (!logging && !is_hugetlb && vma_pagesize == PAGE_SIZE)
+ if (!logging && !userfault && !is_hugetlb && vma_pagesize == PAGE_SIZE)
vma_pagesize = transparent_hugepage_adjust(kvm, memslot, hva, &hfn, &gpa);
if (writable) {
diff --git a/arch/riscv/kvm/vcpu_exit.c b/arch/riscv/kvm/vcpu_exit.c
index 76cceecee5ab..0919e1c8a6ad 100644
--- a/arch/riscv/kvm/vcpu_exit.c
+++ b/arch/riscv/kvm/vcpu_exit.c
@@ -63,6 +63,13 @@ static int gstage_page_fault(struct kvm_vcpu *vcpu, struct kvm_run *run,
};
}
+ if (kvm_slot_userfault_fault(memslot, gfn)) {
+ kvm_prepare_memory_fault_exit(vcpu, fault_addr, PAGE_SIZE,
+ trap->scause == EXC_STORE_GUEST_PAGE_FAULT,
+ trap->scause == EXC_INST_GUEST_PAGE_FAULT, false);
+ return 0;
+ }
+
ret = kvm_riscv_mmu_map(vcpu, memslot, fault_addr, hva,
(trap->scause == EXC_STORE_GUEST_PAGE_FAULT) ? true : false,
&host_map);
diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c
index a9f083feeb76..1bb3918c70da 100644
--- a/arch/riscv/kvm/vm.c
+++ b/arch/riscv/kvm/vm.c
@@ -186,6 +186,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_READONLY_MEM:
case KVM_CAP_MP_STATE:
case KVM_CAP_IMMEDIATE_EXIT:
+ case KVM_CAP_USERFAULT:
case KVM_CAP_SET_GUEST_DEBUG:
r = 1;
break;
--
2.54.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [RFC PATCH] RISC-V: KVM: Enable KVM_MEM_USERFAULT support
2026-07-29 7:08 [RFC PATCH] RISC-V: KVM: Enable KVM_MEM_USERFAULT support Bingyu.Xian
@ 2026-07-29 7:25 ` sashiko-bot
0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-07-29 7:25 UTC (permalink / raw)
To: Bingyu.Xian; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] gstage_page_fault() returns 0 instead of -EFAULT when preparing KVM_EXIT_MEMORY_FAULT, causing ioctl(KVM_RUN) to return 0.
- [High] kvm_prepare_memory_fault_exit() is called with an unaligned guest physical address alongside a PAGE_SIZE length.
- [Low] Mixed declaration and code when declaring the `userfault` variable.
--
--- Patch [1]: [RFC PATCH] RISC-V: KVM: Enable KVM_MEM_USERFAULT support ---
commit 087f35f3e3961e5845e830a76559e809fe2e2d57
Author: Bingyu.Xian <shanbeeyoo@gmail.com>
RISC-V: KVM: Enable KVM_MEM_USERFAULT support
This commit adds support for KVM_MEM_USERFAULT on RISC-V to handle post-copy
live migration via userfaultfd. It forces PAGE_SIZE mappings and checks the
userfault bitmap in gstage_page_fault().
Link: https://lore.kernel.org/kvm/20260618205753.2600064-1-jthoughton@google.com/
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 8a0aa5e0e216e..766f820c27a73 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -583,7 +583,9 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
> else
> vma_pageshift = PAGE_SHIFT;
> vma_pagesize = 1ULL << vma_pageshift;
> - if (logging || (vma->vm_flags & VM_PFNMAP))
> + bool userfault = !!(memslot->flags & KVM_MEM_USERFAULT);
> +
[Severity: Low]
Is there a mixed declaration and code warning introduced here?
In kvm_riscv_mmu_map(), placing the declaration of userfault after the
executable statement vma_pagesize = 1ULL << vma_pageshift; violates the
standard kernel coding style.
Could we move the declaration to the beginning of the block?
> if (logging || userfault || (vma->vm_flags & VM_PFNMAP))
> vma_pagesize = PAGE_SIZE;
[ ... ]
> diff --git a/arch/riscv/kvm/vcpu_exit.c b/arch/riscv/kvm/vcpu_exit.c
> index 6c8530b9f29ed..31fb0b937afcc 100644
> --- a/arch/riscv/kvm/vcpu_exit.c
> +++ b/arch/riscv/kvm/vcpu_exit.c
> @@ -62,6 +62,13 @@ static int gstage_page_fault(struct kvm_vcpu *vcpu, struct kvm_run *run,
> };
> }
>
> + if (kvm_slot_userfault_fault(memslot, gfn)) {
> + kvm_prepare_memory_fault_exit(vcpu, fault_addr, PAGE_SIZE,
[Severity: High]
Are we passing an unaligned guest physical address to
kvm_prepare_memory_fault_exit() here?
The KVM ABI defines the memory fault payload as a region [gpa, gpa + size)
that requires userspace resolution. The fault_addr variable is derived from
the stval register and may be an unaligned byte-granular address.
If fault_addr is unaligned (e.g., 0x1004) and paired with PAGE_SIZE, does it
cause the reported range [0x1004, 0x2004) to erroneously span across two
separate guest pages?
Could this cause the VMM to attempt out-of-bounds or redundant page
resolutions for the adjacent page, leading to migration failures?
> + trap->scause == EXC_STORE_GUEST_PAGE_FAULT,
> + trap->scause == EXC_INST_GUEST_PAGE_FAULT, false);
> + return 0;
[Severity: High]
Should this path return -EFAULT instead of 0?
KVM API documentation requires that KVM_EXIT_MEMORY_FAULT be accompanied by a
-1 return code from the KVM_RUN ioctl, with errno set to EFAULT (or
EHWPOISON).
By returning 0 here in gstage_page_fault(), does kvm_riscv_vcpu_exit()
propagate 0 (success) back to the ioctl handler, and ultimately to userspace?
If the ioctl returns 0, will userspace VMMs like QEMU fail to recognize the
memory fault exit, fall through to the default unhandled exit handler, and
abort the VM?
> + }
> +
> ret = kvm_riscv_mmu_map(vcpu, memslot, fault_addr, hva,
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260729070843.730578-1-shanbeeyoo@gmail.com?part=1
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-29 7:25 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-29 7:08 [RFC PATCH] RISC-V: KVM: Enable KVM_MEM_USERFAULT support Bingyu.Xian
2026-07-29 7:25 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox