From nobody Wed Feb 11 01:25:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 56B2936EA98; Tue, 27 Jan 2026 19:31:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769542294; cv=none; b=DE8HjDDmNTVK71HM51sFYSH56jss0gVwEtR+b6cEf7QkZYFInirq34VPlYlCcdRPlrgPmMrJn7bV/NqzcvdaaCPMeSoMio1X1mRWVC6yvtIzxRj30EtzwMUOhp5yegBf/f6TN9wR+BOojfuOVEFL6VTqyFYul9DWMK6BqZBlonI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769542294; c=relaxed/simple; bh=Z7I33Hc39huXt1KMAEv+ORYc+prBLTGLG9GW3dkBprM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=korIdqBcwmri/+I5K0zI/hmlDhmgo/WWFwb2YCaPZFjccvBN3LH1Dmk7/K7yEuEXDv8Z3djgQPdtRBj82ba1QyITOClGF7BAuwMUZT5m6J9aZvrnc5wnBsnDQ/dwx0B8LhZrbyYJWEWJYK2Wqbx0OO/AeYijEovOOwQyTe1zzfY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ER3jWOY0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ER3jWOY0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 773CEC19425; Tue, 27 Jan 2026 19:31:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1769542294; bh=Z7I33Hc39huXt1KMAEv+ORYc+prBLTGLG9GW3dkBprM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ER3jWOY07iJPn8qyjNDfRFyRgYxyWuJjiSMp41SKhB+56SWGzeoPq6P1kW90+cWm2 QTgYAemvCk1w7t5MUfY/l0AkuHfpYBmxwUxPvAWGQI5l5EHWj6aTOFV/Mchq0bEU1C GOG2+qDG6uH2kXDzBlf4UO9UjRz8htNgAuMPwMN0aahfUJeQTxTlfEXYNXD30QDooW GIQamzOkF/J2WRu+6WATk/bFSXVaEhzYGRMmf6YewptxAR1UuZgiZRX7f8snoWqCcS hqMRCqk877/SG5QpuI75iQgPpzMJR/b+46TGplSy9dBIwKC6NM543/hW0GLCkk9KJW IoFmt7fkcyLwQ== From: Mike Rapoport To: linux-mm@kvack.org Cc: Andrea Arcangeli , Andrew Morton , Axel Rasmussen , Baolin Wang , David Hildenbrand , Hugh Dickins , James Houghton , "Liam R. Howlett" , Lorenzo Stoakes , Michal Hocko , Mike Rapoport , Muchun Song , Nikita Kalyazin , Oscar Salvador , Paolo Bonzini , Peter Xu , Sean Christopherson , Shuah Khan , Suren Baghdasaryan , Vlastimil Babka , linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH RFC 17/17] KVM: selftests: test userfaultfd missing for guest_memfd Date: Tue, 27 Jan 2026 21:29:36 +0200 Message-ID: <20260127192936.1250096-18-rppt@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260127192936.1250096-1-rppt@kernel.org> References: <20260127192936.1250096-1-rppt@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Nikita Kalyazin The test demonstrates that a missing userfaultfd event in guest_memfd can be resolved via a UFFDIO_COPY ioctl. Signed-off-by: Nikita Kalyazin Signed-off-by: Mike Rapoport (Microsoft) --- .../testing/selftests/kvm/guest_memfd_test.c | 80 ++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing= /selftests/kvm/guest_memfd_test.c index 7612819e340a..f77e70d22175 100644 --- a/tools/testing/selftests/kvm/guest_memfd_test.c +++ b/tools/testing/selftests/kvm/guest_memfd_test.c @@ -439,6 +439,82 @@ static void test_uffd_minor(int fd, size_t total_size) close(uffd); } =20 +static void test_uffd_missing(int fd, size_t total_size) +{ + struct uffdio_register uffd_reg; + struct uffdio_copy uffd_copy; + struct uffd_msg msg; + struct fault_args args; + pthread_t fault_thread; + void *mem, *buf =3D NULL; + int uffd, ret; + off_t offset =3D page_size; + void *fault_addr; + const char test_val =3D 0xab; + + ret =3D posix_memalign(&buf, page_size, total_size); + TEST_ASSERT_EQ(ret, 0); + memset(buf, test_val, total_size); + + uffd =3D syscall(__NR_userfaultfd, O_CLOEXEC); + TEST_ASSERT(uffd !=3D -1, "userfaultfd creation should succeed"); + + struct uffdio_api uffdio_api =3D { + .api =3D UFFD_API, + .features =3D 0, + }; + ret =3D ioctl(uffd, UFFDIO_API, &uffdio_api); + TEST_ASSERT(ret !=3D -1, "ioctl(UFFDIO_API) should succeed"); + + mem =3D mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + TEST_ASSERT(mem !=3D MAP_FAILED, "mmap should succeed"); + + uffd_reg.range.start =3D (unsigned long)mem; + uffd_reg.range.len =3D total_size; + uffd_reg.mode =3D UFFDIO_REGISTER_MODE_MISSING; + ret =3D ioctl(uffd, UFFDIO_REGISTER, &uffd_reg); + TEST_ASSERT(ret !=3D -1, "ioctl(UFFDIO_REGISTER) should succeed"); + + fault_addr =3D mem + offset; + args.addr =3D fault_addr; + + ret =3D pthread_create(&fault_thread, NULL, fault_thread_fn, &args); + TEST_ASSERT(ret =3D=3D 0, "pthread_create should succeed"); + + ret =3D read(uffd, &msg, sizeof(msg)); + TEST_ASSERT(ret !=3D -1, "read from userfaultfd should succeed"); + TEST_ASSERT(msg.event =3D=3D UFFD_EVENT_PAGEFAULT, "event type should be = pagefault"); + TEST_ASSERT((void *)(msg.arg.pagefault.address & ~(page_size - 1)) =3D=3D= fault_addr, + "pagefault should occur at expected address"); + TEST_ASSERT(!(msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WP), + "pagefault should not be write-protect"); + + uffd_copy.dst =3D (unsigned long)fault_addr; + uffd_copy.src =3D (unsigned long)(buf + offset); + uffd_copy.len =3D page_size; + uffd_copy.mode =3D 0; + ret =3D ioctl(uffd, UFFDIO_COPY, &uffd_copy); + TEST_ASSERT(ret !=3D -1, "ioctl(UFFDIO_COPY) should succeed"); + + /* Wait for the faulting thread to complete - this provides the memory ba= rrier */ + ret =3D pthread_join(fault_thread, NULL); + TEST_ASSERT(ret =3D=3D 0, "pthread_join should succeed"); + + /* + * Now it's safe to check args.value - the thread has completed + * and memory is synchronized + */ + TEST_ASSERT(args.value =3D=3D test_val, + "memory should contain the value that was copied"); + TEST_ASSERT(*(char *)(mem + offset) =3D=3D test_val, + "no further fault is expected"); + + ret =3D munmap(mem, total_size); + TEST_ASSERT(!ret, "munmap should succeed"); + free(buf); + close(uffd); +} + static void test_guest_memfd_flags(struct kvm_vm *vm) { uint64_t valid_flags =3D vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS); @@ -494,8 +570,10 @@ static void __test_guest_memfd(struct kvm_vm *vm, uint= 64_t flags) gmem_test(fallocate, vm, flags); gmem_test(invalid_punch_hole, vm, flags); =20 - if (flags & GUEST_MEMFD_FLAG_INIT_SHARED) + if (flags & GUEST_MEMFD_FLAG_INIT_SHARED) { gmem_test(uffd_minor, vm, flags); + gmem_test(uffd_missing, vm, flags); + } } =20 static void test_guest_memfd(unsigned long vm_type) --=20 2.51.0