* [PATCH v2 0/2] Fix error handling for async_pf
@ 2026-10-20 17:58 Christian Borntraeger
2026-10-20 17:58 ` [PATCH v2 1/2] KVM: Set up async page faults only for faults that need to wait Christian Borntraeger
2026-10-20 17:58 ` [PATCH v2 2/2] KVM: selftests: Test that KVM_RUN fails for unresolvable host faults Christian Borntraeger
0 siblings, 2 replies; 10+ messages in thread
From: Christian Borntraeger @ 2026-10-20 17:58 UTC (permalink / raw)
To: Janosch Frank, Claudio Imbrenda, Paolo Bonzini,
Sean Christopherson
Cc: KVM, Christian Borntraeger, linux-s390, Shuah Khan
Return mapping errors also for async_pf cases. Otherwise guests
will loop forever. Nothing critical just missing error handling.
v1->v2:
- !npages instead of npages == 0 (Sean)
- new block comment (Sean)
- fix testcase to build with 7.3 and 7.4-rc
Christian Borntraeger (2):
KVM: Set up async page faults only for faults that need to wait
KVM: selftests: Test that KVM_RUN fails for unresolvable host faults
tools/testing/selftests/kvm/Makefile.kvm | 1 +
.../selftests/kvm/faultin_sigbus_test.c | 169 ++++++++++++++++++
virt/kvm/kvm_main.c | 3 +-
3 files changed, 172 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/kvm/faultin_sigbus_test.c
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 1/2] KVM: Set up async page faults only for faults that need to wait
2026-10-20 17:58 [PATCH v2 0/2] Fix error handling for async_pf Christian Borntraeger
@ 2026-10-20 17:58 ` Christian Borntraeger
2026-10-20 18:02 ` sashiko-bot
2026-10-22 2:23 ` Sean Christopherson
2026-10-20 17:58 ` [PATCH v2 2/2] KVM: selftests: Test that KVM_RUN fails for unresolvable host faults Christian Borntraeger
1 sibling, 2 replies; 10+ messages in thread
From: Christian Borntraeger @ 2026-10-20 17:58 UTC (permalink / raw)
To: Janosch Frank, Claudio Imbrenda, Paolo Bonzini,
Sean Christopherson
Cc: KVM, Christian Borntraeger, linux-s390, Shuah Khan
hva_to_pfn() checks a FOLL_NOWAIT gup() for EINTR, EAGAIN and EHWPOISON.
There might be others like -EFAULT for VM_FAULT_SIGBUS. For those other
errors, reporting KVM_PFN_ERR_NEEDS_IO would be wrong as it triggers an
async_pf resulting in endless retries.
Return KVM_PFN_ERR_NEEDS_IO only if gup() returned 0 pages and report
the error otherwise.
Fixes: 0857b9e95c1a ("KVM: Enable async page fault processing")
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
virt/kvm/kvm_main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 5a782849521c..7b6172810f34 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -3047,7 +3047,8 @@ kvm_pfn_t hva_to_pfn(struct kvm_follow_pfn *kfp)
if (r < 0)
pfn = KVM_PFN_ERR_FAULT;
} else {
- if ((kfp->flags & FOLL_NOWAIT) &&
+ /* Note, GUP returns '0' if retry is needed. */
+ if (!npages && (kfp->flags & FOLL_NOWAIT) &&
vma_is_valid(vma, kfp->flags & FOLL_WRITE))
pfn = KVM_PFN_ERR_NEEDS_IO;
else
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 2/2] KVM: selftests: Test that KVM_RUN fails for unresolvable host faults
2026-10-20 17:58 [PATCH v2 0/2] Fix error handling for async_pf Christian Borntraeger
2026-10-20 17:58 ` [PATCH v2 1/2] KVM: Set up async page faults only for faults that need to wait Christian Borntraeger
@ 2026-10-20 17:58 ` Christian Borntraeger
2026-10-20 18:09 ` sashiko-bot
2026-10-22 18:18 ` Sean Christopherson
1 sibling, 2 replies; 10+ messages in thread
From: Christian Borntraeger @ 2026-10-20 17:58 UTC (permalink / raw)
To: Janosch Frank, Claudio Imbrenda, Paolo Bonzini,
Sean Christopherson
Cc: KVM, Christian Borntraeger, linux-s390, Shuah Khan
Add a test in which the guest writes to a shmem-backed memslot beyond
the end of the file. KVM_RUN must fail with -EFAULT.
On x86 the guest enables interrupts, and on s390 the test sets up
pfault, so that KVM could handle the fault with an asynchronous page
fault. If KVM mistakes the error for a fault that needs I/O, the vCPU
retries the access forever, and the test fails after a timeout.
The test is not built for LoongArch, which handles a failed mapping as
an MMIO access.
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
tools/testing/selftests/kvm/Makefile.kvm | 1 +
.../selftests/kvm/faultin_sigbus_test.c | 169 ++++++++++++++++++
2 files changed, 170 insertions(+)
create mode 100644 tools/testing/selftests/kvm/faultin_sigbus_test.c
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 68bcec3d0070..24fdfc3e0eba 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -59,6 +59,7 @@ TEST_PROGS_x86 += x86/nx_huge_pages_test.sh
# Compiled test targets valid on all architectures with libkvm support
TEST_GEN_PROGS_COMMON = demand_paging_test
TEST_GEN_PROGS_COMMON += dirty_log_test
+TEST_GEN_PROGS_COMMON += faultin_sigbus_test
TEST_GEN_PROGS_COMMON += guest_print_test
TEST_GEN_PROGS_COMMON += irqfd_test
TEST_GEN_PROGS_COMMON += kvm_binary_stats_test
diff --git a/tools/testing/selftests/kvm/faultin_sigbus_test.c b/tools/testing/selftests/kvm/faultin_sigbus_test.c
new file mode 100644
index 000000000000..9394b04efcd6
--- /dev/null
+++ b/tools/testing/selftests/kvm/faultin_sigbus_test.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * A guest access to memory whose host mapping cannot be faulted in (here: a
+ * shmem page beyond EOF, i.e. SIGBUS) must make KVM_RUN fail with -EFAULT.
+ *
+ * On architectures with asynchronous page faults, KVM first tries to fault
+ * the page in without waiting (FOLL_NOWAIT) and hands the fault to a worker
+ * if that would need I/O. The error must not be mistaken for "needs I/O",
+ * otherwise the vCPU retries the access forever and KVM_RUN never returns.
+ * The architecture hooks below make sure that the async path is actually
+ * possible, i.e. that the error would be misclassified if KVM got it wrong.
+ */
+#include <signal.h>
+#include <unistd.h>
+#include <linux/sizes.h>
+#include <linux/stringify.h>
+
+#include "kvm_util.h"
+#include "processor.h"
+#include "test_util.h"
+#include "ucall_common.h"
+
+#define TEST_SLOT 10
+#define TEST_SIZE SZ_1M
+#define TIMEOUT_SECS 10
+
+#ifdef __s390x__
+#define __LC_EXT_NEW_PSW 0x1b0
+#define __LC_SAVED_PSW 0x200 /* free for the OS */
+#define __LC_WAIT_PSW 0x210 /* free for the OS */
+#define PSW_MASK_EXT 0x0100000000000000ULL
+#define PSW_MASK_DAT 0x0400000000000000ULL
+#define PSW_MASK_WAIT 0x0002000000000000ULL
+#define CR0_SERVICE_SIGNAL_SUBMASK BIT_ULL(63 - 54)
+
+/*
+ * Handle pfault like Linux does: on the init interrupt (ext cpu address
+ * 0x0600) remember the interrupted PSW and wait until the done interrupt
+ * (0x0680), then retry the access. A guest that retried at once would
+ * fill up KVM's queue of async page faults and get the synchronous fault
+ * path. Runs with DAT off, so lowcore is addressed by real addresses:
+ * 0x84 is the ext cpu address, 0x130 the ext old PSW. Done differs from
+ * init only in bit 0x80 of 0x85, test it like Linux tests PF_COMPLETE.
+ */
+extern char ext_int_handler[];
+asm(".pushsection .text\n"
+ "ext_int_handler:\n"
+ " tm 0x85,0x80\n"
+ " jo 1f\n"
+ " mvc " __stringify(__LC_SAVED_PSW) "(16),0x130\n"
+ " lpswe " __stringify(__LC_WAIT_PSW) "\n"
+ "1: lpswe " __stringify(__LC_SAVED_PSW) "\n"
+ ".popsection\n");
+
+static void arch_enable_async_pf(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
+{
+ u64 *lowcore = addr_gpa2hva(vm, 0);
+ struct kvm_sregs sregs;
+ gva_t token_gva;
+ gpa_t handler;
+ int flic;
+
+ flic = kvm_create_device(vm, KVM_DEV_TYPE_FLIC);
+ kvm_device_attr_set(flic, KVM_DEV_FLIC_APF_ENABLE, 0, NULL);
+
+ /* The DIAG 0x258 handshake, with masks that match any guest PSW. */
+ token_gva = vm_alloc_page(vm);
+ vcpu_set_reg(vcpu, KVM_REG_S390_PFTOKEN, addr_gva2gpa(vm, token_gva));
+ vcpu_set_reg(vcpu, KVM_REG_S390_PFSELECT, 0);
+ vcpu_set_reg(vcpu, KVM_REG_S390_PFCOMPARE, 0);
+
+ vcpu_sregs_get(vcpu, &sregs);
+ sregs.crs[0] |= CR0_SERVICE_SIGNAL_SUBMASK;
+ vcpu_sregs_set(vcpu, &sregs);
+ vcpu->run->psw_mask |= PSW_MASK_EXT;
+
+ handler = addr_gva2gpa(vm, (gva_t)ext_int_handler);
+ lowcore[__LC_EXT_NEW_PSW / 8] = vcpu->run->psw_mask &
+ ~(PSW_MASK_EXT | PSW_MASK_DAT);
+ lowcore[__LC_EXT_NEW_PSW / 8 + 1] = handler;
+ lowcore[__LC_WAIT_PSW / 8] = (vcpu->run->psw_mask & ~PSW_MASK_DAT) |
+ PSW_MASK_WAIT;
+ lowcore[__LC_WAIT_PSW / 8 + 1] = handler;
+}
+#else
+/* x86 needs guest interrupts on, see guest_code(); nothing to do elsewhere. */
+static void arch_enable_async_pf(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
+{
+}
+#endif
+
+static void guest_code(u64 gva, u64 size)
+{
+#ifdef __x86_64__
+ /* KVM does async #PF, or its halt fallback, only with IRQs enabled. */
+ sti_nop();
+#endif
+ /* Within EOF: must work, proves that the mapping is set up right. */
+ WRITE_ONCE(*(u64 *)gva, 1);
+ GUEST_SYNC(0);
+
+ /* Beyond EOF: KVM_RUN must fail with -EFAULT. */
+ WRITE_ONCE(*(u64 *)(gva + size - sizeof(u64)), 1);
+ GUEST_FAIL("Store beyond EOF succeeded");
+}
+
+static void sig_alarm(int sig)
+{
+}
+
+int main(void)
+{
+ struct sigaction sa = { .sa_handler = sig_alarm }; /* no SA_RESTART */
+ struct userspace_mem_region *region;
+ struct kvm_vcpu *vcpu;
+ struct kvm_vm *vm;
+ struct ucall uc;
+ gpa_t gpa;
+ gva_t gva;
+ u64 npages;
+ int r;
+
+ vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+
+ /* After slot 0 and the page that some architectures use for ucalls. */
+ region = memslot2region(vm, 0);
+ gpa = align_up(region->region.guest_phys_addr +
+ region->region.memory_size + vm->page_size, TEST_SIZE);
+ npages = TEST_SIZE / vm->page_size;
+
+ vm_userspace_mem_region_add(vm, VM_MEM_SRC_SHMEM, gpa, TEST_SLOT,
+ npages, 0);
+ region = memslot2region(vm, TEST_SLOT);
+ /* Only the first host page is backed, everything behind it is SIGBUS. */
+ TEST_ASSERT(!ftruncate(region->fd, getpagesize()), "ftruncate() failed");
+
+ gva = vm_unused_gva_gap(vm, TEST_SIZE, KVM_UTIL_MIN_VADDR);
+ virt_map(vm, gva, gpa, npages);
+ vcpu_args_set(vcpu, 2, gva, TEST_SIZE);
+
+ arch_enable_async_pf(vm, vcpu);
+
+ vcpu_run(vcpu);
+ switch (get_ucall(vcpu, &uc)) {
+ case UCALL_SYNC:
+ break;
+ case UCALL_ABORT:
+ REPORT_GUEST_ASSERT(uc);
+ break;
+ default:
+ TEST_FAIL("Unexpected ucall %lu", uc.cmd);
+ }
+ TEST_ASSERT_EQ(*(u64 *)region->host_mem, 1);
+
+ TEST_ASSERT(!sigaction(SIGALRM, &sa, NULL), "sigaction() failed");
+ alarm(TIMEOUT_SECS);
+ r = __vcpu_run(vcpu);
+ alarm(0);
+
+ TEST_ASSERT(!(r == -1 && errno == EINTR),
+ "KVM_RUN did not return within %d seconds: the fault on the SIGBUS page is retried forever",
+ TIMEOUT_SECS);
+ TEST_ASSERT(r == -1 && errno == EFAULT,
+ "Expected KVM_RUN to fail with EFAULT, got r = %d, errno = %d (%s), exit reason %s",
+ r, errno, strerror(errno), exit_reason_str(vcpu->run->exit_reason));
+
+ kvm_vm_free(vm);
+ return 0;
+}
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] KVM: Set up async page faults only for faults that need to wait
2026-10-20 17:58 ` [PATCH v2 1/2] KVM: Set up async page faults only for faults that need to wait Christian Borntraeger
@ 2026-10-20 18:02 ` sashiko-bot
2026-10-22 2:23 ` Sean Christopherson
1 sibling, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-10-20 18:02 UTC (permalink / raw)
To: Christian Borntraeger
Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev
> hva_to_pfn() checks a FOLL_NOWAIT gup() for EINTR, EAGAIN and EHWPOISON.
> There might be others like -EFAULT for VM_FAULT_SIGBUS. For those other
> errors, reporting KVM_PFN_ERR_NEEDS_IO would be wrong as it triggers an
> async_pf resulting in endless retries.
>
> Return KVM_PFN_ERR_NEEDS_IO only if gup() returned 0 pages and report
> the error otherwise.
>
> Fixes: 0857b9e95c1a ("KVM: Enable async page fault processing")
> Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020175818.375700-1-borntraeger@linux.ibm.com?part=1
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] KVM: selftests: Test that KVM_RUN fails for unresolvable host faults
2026-10-20 17:58 ` [PATCH v2 2/2] KVM: selftests: Test that KVM_RUN fails for unresolvable host faults Christian Borntraeger
@ 2026-10-20 18:09 ` sashiko-bot
2026-10-22 18:18 ` Sean Christopherson
1 sibling, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-10-20 18:09 UTC (permalink / raw)
To: Christian Borntraeger
Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev
> Add a test in which the guest writes to a shmem-backed memslot beyond
> the end of the file. KVM_RUN must fail with -EFAULT.
>
> On x86 the guest enables interrupts, and on s390 the test sets up
> pfault, so that KVM could handle the fault with an asynchronous page
> fault. If KVM mistakes the error for a fault that needs I/O, the vCPU
> retries the access forever, and the test fails after a timeout.
>
> The test is not built for LoongArch, which handles a failed mapping as
> an MMIO access.
>
> Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020175818.375700-1-borntraeger@linux.ibm.com?part=2
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] KVM: Set up async page faults only for faults that need to wait
2026-10-20 17:58 ` [PATCH v2 1/2] KVM: Set up async page faults only for faults that need to wait Christian Borntraeger
2026-10-20 18:02 ` sashiko-bot
@ 2026-10-22 2:23 ` Sean Christopherson
1 sibling, 0 replies; 10+ messages in thread
From: Sean Christopherson @ 2026-10-22 2:23 UTC (permalink / raw)
To: Christian Borntraeger
Cc: Janosch Frank, Claudio Imbrenda, Paolo Bonzini, KVM, linux-s390,
Shuah Khan
On Tue, Oct 20, 2026, Christian Borntraeger wrote:
> hva_to_pfn() checks a FOLL_NOWAIT gup() for EINTR, EAGAIN and EHWPOISON.
> There might be others like -EFAULT for VM_FAULT_SIGBUS. For those other
> errors, reporting KVM_PFN_ERR_NEEDS_IO would be wrong as it triggers an
> async_pf resulting in endless retries.
>
> Return KVM_PFN_ERR_NEEDS_IO only if gup() returned 0 pages and report
> the error otherwise.
>
> Fixes: 0857b9e95c1a ("KVM: Enable async page fault processing")
> Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
> ---
Reviewed-by: Sean Christopherson <seanjc@google.com>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] KVM: selftests: Test that KVM_RUN fails for unresolvable host faults
2026-10-20 17:58 ` [PATCH v2 2/2] KVM: selftests: Test that KVM_RUN fails for unresolvable host faults Christian Borntraeger
2026-10-20 18:09 ` sashiko-bot
@ 2026-10-22 18:18 ` Sean Christopherson
2026-10-23 12:35 ` Christian Borntraeger
1 sibling, 1 reply; 10+ messages in thread
From: Sean Christopherson @ 2026-10-22 18:18 UTC (permalink / raw)
To: Christian Borntraeger
Cc: Janosch Frank, Claudio Imbrenda, Paolo Bonzini, KVM, linux-s390,
Shuah Khan
On Tue, Oct 20, 2026, Christian Borntraeger wrote:
> Add a test in which the guest writes to a shmem-backed memslot beyond
> the end of the file. KVM_RUN must fail with -EFAULT.
>
> On x86 the guest enables interrupts, and on s390 the test sets up
> pfault, so that KVM could handle the fault with an asynchronous page
> fault. If KVM mistakes the error for a fault that needs I/O, the vCPU
> retries the access forever, and the test fails after a timeout.
>
> The test is not built for LoongArch, which handles a failed mapping as
> an MMIO access.
>
> Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
> ---
> tools/testing/selftests/kvm/Makefile.kvm | 1 +
> .../selftests/kvm/faultin_sigbus_test.c | 169 ++++++++++++++++++
The "sigbus" part of this is confusing, because there is never actually a sigbus.
Kinda silly, but maybe faultin_efault_test?
> +static void arch_enable_async_pf(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
> +{
...
> +}
> +#else
> +/* x86 needs guest interrupts on, see guest_code(); nothing to do elsewhere. */
> +static void arch_enable_async_pf(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
Nit, maybe arch_enable_host_async_pf()? Because x86 has PV async #PFs, where
instead of scheduling a worker task in the host, KVM (conditionally) reflects
the #PF into the guest so that the guest can schedule in a different task. A
lot of people, myself included, see "async #PF" and think of the PV version first,
e.g. I initially was looking for the PV side of things here.
> +#endif
> +
> +static void guest_code(u64 gva, u64 size)
> +{
> +#ifdef __x86_64__
> + /* KVM does async #PF, or its halt fallback, only with IRQs enabled. */
> + sti_nop();
> +#endif
> + /* Within EOF: must work, proves that the mapping is set up right. */
> + WRITE_ONCE(*(u64 *)gva, 1);
> + GUEST_SYNC(0);
> +
> + /* Beyond EOF: KVM_RUN must fail with -EFAULT. */
> + WRITE_ONCE(*(u64 *)(gva + size - sizeof(u64)), 1);
> + GUEST_FAIL("Store beyond EOF succeeded");
> +}
> +
> +static void sig_alarm(int sig)
> +{
> +}
...
> + TEST_ASSERT(!sigaction(SIGALRM, &sa, NULL), "sigaction() failed");
> + alarm(TIMEOUT_SECS);
> + r = __vcpu_run(vcpu);
> + alarm(0);
> +
> + TEST_ASSERT(!(r == -1 && errno == EINTR),
> + "KVM_RUN did not return within %d seconds: the fault on the SIGBUS page is retried forever",
> + TIMEOUT_SECS);
Rather than assert on EINTR, what if we have sig_alarm() explicitly TEST_FAIL()?
That way readers don't have to piece together that the EINTR is coming from the
alarm, and there's less chance of the test somehow getting a false pass because
KVM manages to morph the signal into EFAULT. That would also allow using the
single-underscore _vcpu_run(), though I don't know if that's actually a good idea.
E.g.
diff --git a/tools/testing/selftests/kvm/faultin_sigbus_test.c b/tools/testing/selftests/kvm/faultin_sigbus_test.c
index 9394b04efcd6..9d90c32f3c6a 100644
--- a/tools/testing/selftests/kvm/faultin_sigbus_test.c
+++ b/tools/testing/selftests/kvm/faultin_sigbus_test.c
@@ -106,6 +106,7 @@ static void guest_code(u64 gva, u64 size)
static void sig_alarm(int sig)
{
+ TEST_FAIL("%d second timeout expired before KVM_RUN hit -EFAULT", TIMEOUT_SECS);
}
int main(void)
@@ -154,12 +155,9 @@ int main(void)
TEST_ASSERT(!sigaction(SIGALRM, &sa, NULL), "sigaction() failed");
alarm(TIMEOUT_SECS);
- r = __vcpu_run(vcpu);
+ r = _vcpu_run(vcpu);
alarm(0);
- TEST_ASSERT(!(r == -1 && errno == EINTR),
- "KVM_RUN did not return within %d seconds: the fault on the SIGBUS page is retried forever",
- TIMEOUT_SECS);
TEST_ASSERT(r == -1 && errno == EFAULT,
"Expected KVM_RUN to fail with EFAULT, got r = %d, errno = %d (%s), exit reason %s",
r, errno, strerror(errno), exit_reason_str(vcpu->run->exit_reason));
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] KVM: selftests: Test that KVM_RUN fails for unresolvable host faults
2026-10-22 18:18 ` Sean Christopherson
@ 2026-10-23 12:35 ` Christian Borntraeger
2026-10-23 14:05 ` [PATCH v3 " Christian Borntraeger
0 siblings, 1 reply; 10+ messages in thread
From: Christian Borntraeger @ 2026-10-23 12:35 UTC (permalink / raw)
To: Sean Christopherson
Cc: Janosch Frank, Claudio Imbrenda, Paolo Bonzini, KVM, linux-s390,
Shuah Khan
Am 22.10.26 um 20:18 schrieb Sean Christopherson:
> On Tue, Oct 20, 2026, Christian Borntraeger wrote:
>> Add a test in which the guest writes to a shmem-backed memslot beyond
>> the end of the file. KVM_RUN must fail with -EFAULT.
>>
>> On x86 the guest enables interrupts, and on s390 the test sets up
>> pfault, so that KVM could handle the fault with an asynchronous page
>> fault. If KVM mistakes the error for a fault that needs I/O, the vCPU
>> retries the access forever, and the test fails after a timeout.
>>
>> The test is not built for LoongArch, which handles a failed mapping as
>> an MMIO access.
>>
>> Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
>> ---
>> tools/testing/selftests/kvm/Makefile.kvm | 1 +
>> .../selftests/kvm/faultin_sigbus_test.c | 169 ++++++++++++++++++
>
> The "sigbus" part of this is confusing, because there is never actually a sigbus.
> Kinda silly, but maybe faultin_efault_test?
Its Friday, so lets ask the British people and let them vote for Faulty_McFaultFace.c? ;-)
Just kidding, what about async_pf_error_test.c ?
>
>> +static void arch_enable_async_pf(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
>> +{
>
> ...
>
>> +}
>> +#else
>> +/* x86 needs guest interrupts on, see guest_code(); nothing to do elsewhere. */
>> +static void arch_enable_async_pf(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
>
> Nit, maybe arch_enable_host_async_pf()? Because x86 has PV async #PFs, where
Can do, I will follow your guidance as you have the x86 view.
>> +
>> + TEST_ASSERT(!(r == -1 && errno == EINTR),
>> + "KVM_RUN did not return within %d seconds: the fault on the SIGBUS page is retried forever",
>> + TIMEOUT_SECS);
>
> Rather than assert on EINTR, what if we have sig_alarm() explicitly TEST_FAIL()?
> That way readers don't have to piece together that the EINTR is coming from the
> alarm, and there's less chance of the test somehow getting a false pass because
> KVM manages to morph the signal into EFAULT. That would also allow using the
I will have a try. Thanks for the feedback.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 2/2] KVM: selftests: Test that KVM_RUN fails for unresolvable host faults
2026-10-23 12:35 ` Christian Borntraeger
@ 2026-10-23 14:05 ` Christian Borntraeger
2026-10-23 15:06 ` Sean Christopherson
0 siblings, 1 reply; 10+ messages in thread
From: Christian Borntraeger @ 2026-10-23 14:05 UTC (permalink / raw)
To: seanjc; +Cc: borntraeger, frankja, imbrenda, kvm, linux-s390, pbonzini, shuah
Add a test in which the guest writes to a shmem-backed memslot beyond
the end of the file. KVM_RUN must fail with -EFAULT.
On x86 the guest enables interrupts, and on s390 the test sets up
pfault, so that KVM could handle the fault with an asynchronous page
fault. If KVM mistakes the error for a fault that needs I/O, the vCPU
retries the access forever, and the test fails after a timeout.
The test is not built for LoongArch, which handles a failed mapping as
an MMIO access.
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
I went with Seans name proposal
v2->v3:
- renames as suggested by Sean
- test fail on alarm
tools/testing/selftests/kvm/Makefile.kvm | 1 +
.../selftests/kvm/faultin_efault_test.c | 168 ++++++++++++++++++
2 files changed, 169 insertions(+)
create mode 100644 tools/testing/selftests/kvm/faultin_efault_test.c
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 3cb35a6963d51..2043ee38dacc1 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -63,6 +63,7 @@ TEST_PROGS_x86 += x86/nx_huge_pages_test.sh
# Compiled test targets valid on all architectures with libkvm support
TEST_GEN_PROGS_COMMON = demand_paging_test
TEST_GEN_PROGS_COMMON += dirty_log_test
+TEST_GEN_PROGS_COMMON += faultin_efault_test
TEST_GEN_PROGS_COMMON += guest_print_test
TEST_GEN_PROGS_COMMON += irqfd_test
TEST_GEN_PROGS_COMMON += kvm_binary_stats_test
diff --git a/tools/testing/selftests/kvm/faultin_efault_test.c b/tools/testing/selftests/kvm/faultin_efault_test.c
new file mode 100644
index 0000000000000..12fab9a46a93d
--- /dev/null
+++ b/tools/testing/selftests/kvm/faultin_efault_test.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * A guest access to memory whose host mapping cannot be faulted in (here: a
+ * shmem page beyond EOF) must make KVM_RUN fail with -EFAULT.
+ *
+ * On architectures with asynchronous page faults, KVM first tries to fault
+ * the page in without waiting (FOLL_NOWAIT) and hands the fault to a worker
+ * if that would need I/O. The error must not be mistaken for "needs I/O",
+ * otherwise the vCPU retries the access forever and KVM_RUN never returns.
+ * The architecture hooks below make sure that the async path is actually
+ * possible, i.e. that the error would be misclassified if KVM got it wrong.
+ */
+#include <signal.h>
+#include <unistd.h>
+#include <linux/sizes.h>
+#include <linux/stringify.h>
+
+#include "kvm_util.h"
+#include "processor.h"
+#include "test_util.h"
+#include "ucall_common.h"
+
+#define TEST_SLOT 10
+#define TEST_SIZE SZ_1M
+#define TIMEOUT_SECS 10
+
+#ifdef __s390x__
+#define __LC_EXT_NEW_PSW 0x1b0
+#define __LC_SAVED_PSW 0x200 /* free for the OS */
+#define __LC_WAIT_PSW 0x210 /* free for the OS */
+#define PSW_MASK_EXT 0x0100000000000000ULL
+#define PSW_MASK_DAT 0x0400000000000000ULL
+#define PSW_MASK_WAIT 0x0002000000000000ULL
+#define CR0_SERVICE_SIGNAL_SUBMASK BIT_ULL(63 - 54)
+
+/*
+ * Handle pfault like Linux does: on the init interrupt (ext cpu address
+ * 0x0600) remember the interrupted PSW and wait until the done interrupt
+ * (0x0680), then retry the access. A guest that retried at once would
+ * fill up KVM's queue of async page faults and get the synchronous fault
+ * path. Runs with DAT off, so lowcore is addressed by real addresses:
+ * 0x84 is the ext cpu address, 0x130 the ext old PSW. Done differs from
+ * init only in bit 0x80 of 0x85, test it like Linux tests PF_COMPLETE.
+ */
+extern char ext_int_handler[];
+asm(".pushsection .text\n"
+ "ext_int_handler:\n"
+ " tm 0x85,0x80\n"
+ " jo 1f\n"
+ " mvc " __stringify(__LC_SAVED_PSW) "(16),0x130\n"
+ " lpswe " __stringify(__LC_WAIT_PSW) "\n"
+ "1: lpswe " __stringify(__LC_SAVED_PSW) "\n"
+ ".popsection\n");
+
+static void arch_enable_host_async_pf(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
+{
+ u64 *lowcore = addr_gpa2hva(vm, 0);
+ struct kvm_sregs sregs;
+ gva_t token_gva;
+ gpa_t handler;
+ int flic;
+
+ flic = kvm_create_device(vm, KVM_DEV_TYPE_FLIC);
+ kvm_device_attr_set(flic, KVM_DEV_FLIC_APF_ENABLE, 0, NULL);
+
+ /* The DIAG 0x258 handshake, with masks that match any guest PSW. */
+ token_gva = vm_alloc_page(vm);
+ vcpu_set_reg(vcpu, KVM_REG_S390_PFTOKEN, addr_gva2gpa(vm, token_gva));
+ vcpu_set_reg(vcpu, KVM_REG_S390_PFSELECT, 0);
+ vcpu_set_reg(vcpu, KVM_REG_S390_PFCOMPARE, 0);
+
+ vcpu_sregs_get(vcpu, &sregs);
+ sregs.crs[0] |= CR0_SERVICE_SIGNAL_SUBMASK;
+ vcpu_sregs_set(vcpu, &sregs);
+ vcpu->run->psw_mask |= PSW_MASK_EXT;
+
+ handler = addr_gva2gpa(vm, (gva_t)ext_int_handler);
+ lowcore[__LC_EXT_NEW_PSW / 8] = vcpu->run->psw_mask &
+ ~(PSW_MASK_EXT | PSW_MASK_DAT);
+ lowcore[__LC_EXT_NEW_PSW / 8 + 1] = handler;
+ lowcore[__LC_WAIT_PSW / 8] = (vcpu->run->psw_mask & ~PSW_MASK_DAT) |
+ PSW_MASK_WAIT;
+ lowcore[__LC_WAIT_PSW / 8 + 1] = handler;
+}
+#else
+/* x86 needs guest interrupts on, see guest_code(); nothing to do elsewhere. */
+static void arch_enable_host_async_pf(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
+{
+}
+#endif
+
+static void guest_code(u64 gva, u64 size)
+{
+#ifdef __x86_64__
+ /* KVM does async #PF, or its halt fallback, only with IRQs enabled. */
+ sti_nop();
+#endif
+ /* Within EOF: must work, proves that the mapping is set up right. */
+ WRITE_ONCE(*(u64 *)gva, 1);
+ GUEST_SYNC(0);
+
+ /* Beyond EOF: KVM_RUN must fail with -EFAULT. */
+ WRITE_ONCE(*(u64 *)(gva + size - sizeof(u64)), 1);
+ GUEST_FAIL("Store beyond EOF succeeded");
+}
+
+static void sig_alarm(int sig)
+{
+ TEST_FAIL("KVM_RUN did not return within %d seconds, the fault is retried forever",
+ TIMEOUT_SECS);
+}
+
+int main(void)
+{
+ struct sigaction sa = { .sa_handler = sig_alarm };
+ struct userspace_mem_region *region;
+ struct kvm_vcpu *vcpu;
+ struct kvm_vm *vm;
+ struct ucall uc;
+ gpa_t gpa;
+ gva_t gva;
+ u64 npages;
+ int r;
+
+ vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+
+ /* After slot 0 and the page that some architectures use for ucalls. */
+ region = memslot2region(vm, 0);
+ gpa = align_up(region->region.guest_phys_addr +
+ region->region.memory_size + vm->page_size, TEST_SIZE);
+ npages = TEST_SIZE / vm->page_size;
+
+ vm_userspace_mem_region_add(vm, VM_MEM_SRC_SHMEM, gpa, TEST_SLOT,
+ npages, 0);
+ region = memslot2region(vm, TEST_SLOT);
+ /* Only the first host page is backed, everything behind it is beyond EOF. */
+ TEST_ASSERT(!ftruncate(region->fd, getpagesize()), "ftruncate() failed");
+
+ gva = vm_unused_gva_gap(vm, TEST_SIZE, KVM_UTIL_MIN_VADDR);
+ virt_map(vm, gva, gpa, npages);
+ vcpu_args_set(vcpu, 2, gva, TEST_SIZE);
+
+ arch_enable_host_async_pf(vm, vcpu);
+
+ vcpu_run(vcpu);
+ switch (get_ucall(vcpu, &uc)) {
+ case UCALL_SYNC:
+ break;
+ case UCALL_ABORT:
+ REPORT_GUEST_ASSERT(uc);
+ break;
+ default:
+ TEST_FAIL("Unexpected ucall %lu", uc.cmd);
+ }
+ TEST_ASSERT_EQ(*(u64 *)region->host_mem, 1);
+
+ TEST_ASSERT(!sigaction(SIGALRM, &sa, NULL), "sigaction() failed");
+ alarm(TIMEOUT_SECS);
+ r = _vcpu_run(vcpu);
+ alarm(0);
+
+ TEST_ASSERT(r == -1 && errno == EFAULT,
+ "Expected KVM_RUN to fail with EFAULT, got r = %d, errno = %d (%s), exit reason %s",
+ r, errno, strerror(errno), exit_reason_str(vcpu->run->exit_reason));
+
+ kvm_vm_free(vm);
+ return 0;
+}
--
2.56.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v3 2/2] KVM: selftests: Test that KVM_RUN fails for unresolvable host faults
2026-10-23 14:05 ` [PATCH v3 " Christian Borntraeger
@ 2026-10-23 15:06 ` Sean Christopherson
0 siblings, 0 replies; 10+ messages in thread
From: Sean Christopherson @ 2026-10-23 15:06 UTC (permalink / raw)
To: Christian Borntraeger; +Cc: frankja, imbrenda, kvm, linux-s390, pbonzini, shuah
On Fri, Oct 23, 2026, Christian Borntraeger wrote:
> Add a test in which the guest writes to a shmem-backed memslot beyond
> the end of the file. KVM_RUN must fail with -EFAULT.
>
> On x86 the guest enables interrupts, and on s390 the test sets up
> pfault, so that KVM could handle the fault with an asynchronous page
> fault. If KVM mistakes the error for a fault that needs I/O, the vCPU
> retries the access forever, and the test fails after a timeout.
>
> The test is not built for LoongArch, which handles a failed mapping as
> an MMIO access.
>
> Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
> ---
> I went with Seans name proposal
Aww, bummer. If you posted a faulty_mcfault_face_test, I would absolutely apply
that and force Paolo to tell me no :-)
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-10-23 15:06 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-20 17:58 [PATCH v2 0/2] Fix error handling for async_pf Christian Borntraeger
2026-10-20 17:58 ` [PATCH v2 1/2] KVM: Set up async page faults only for faults that need to wait Christian Borntraeger
2026-10-20 18:02 ` sashiko-bot
2026-10-22 2:23 ` Sean Christopherson
2026-10-20 17:58 ` [PATCH v2 2/2] KVM: selftests: Test that KVM_RUN fails for unresolvable host faults Christian Borntraeger
2026-10-20 18:09 ` sashiko-bot
2026-10-22 18:18 ` Sean Christopherson
2026-10-23 12:35 ` Christian Borntraeger
2026-10-23 14:05 ` [PATCH v3 " Christian Borntraeger
2026-10-23 15:06 ` Sean Christopherson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox