From nobody Wed Feb 11 05:18:02 2026 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2D74E333736 for ; Fri, 17 Oct 2025 20:13:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760731988; cv=none; b=To23QUtS9pw0wIRiwyXU6AGnDjhl+JIsb7A0svZiaD4BGR6Ezk/r599fCTDw8XGKmd0eEQGSaoAKLYVmOv1jH13V+1ylWUplZi1eaxR7u9bMh6D05upKUU7iGN/s9p4ZAGW5LuJaKIbLpJd5sh9mJsoXdI75gdQaeNqq+HhpZuU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760731988; c=relaxed/simple; bh=MiQqTE+C1miYIfErLQ9MJa4Tj7vuiF7vlo8w+BkmP38=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=aGgbiWOpjAFl4gU59RrLkaGXIxOAICqH1NfPFzslUgoibweYp3dMCDrwJo4DD7spcxIegJS0aJ9ig5q7TCBH7THmVuZtOptoZqgqh3pTheNEWloavRHorbqn5EY5+5ChomaWcxnldyEfXBxPTZiMr88ZHoaDnnZ8UsQ2d7NBGI8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--ackerleytng.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=RgZW/sIu; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--ackerleytng.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="RgZW/sIu" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-33baef12edaso2230508a91.0 for ; Fri, 17 Oct 2025 13:13:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1760731980; x=1761336780; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=YGBR8ThL9h1g6JtPgOVB6QJAz8D14GRCTcht+yz9Ebg=; b=RgZW/sIuHiT0zSMOH+eEf6MLsJDjLN2ruR2F/BVeClBSA/STx4cqHcjG8Xo0Y+8Iv3 DH23cmLraUQVwBqI0eQTBe59hKCkwcTiqBT2gszqlwhj5R4LHkQZeiOcpYthkUzGGyEe vlvffcPLlxvrP/vG0DYwJfGHni4ondyDsrDYOFp3H5xKGw+HMoRi7IEuNFWPa4KHTZqr X1yVr4pR9cYiyZR54JtS2vrmJYzHxujoOFNX7TGMd26AqWa7eemisHVQwnLuEGYN/VpW DHEbYfbe8fVd9DjLk4RYxVRkBRGRgC2GAZefmJYQnWEVwrcskbxM2hvvAeriluui5SIU /www== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1760731980; x=1761336780; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=YGBR8ThL9h1g6JtPgOVB6QJAz8D14GRCTcht+yz9Ebg=; b=Fj0ibG8RYd571KInCZzSnph8P1ac24lX0k85W1hRa+nioy8zItY3oE9pa5DjuoSD4R C72cOd1J3/iYNfihEfbu2LiLnv+RvvpJ0kYU0vrl0F5Umm2PGmMlgZna3YOzxqg252Rd g1Omyl3nlOJ4o1+5KQuYuftkl0Bbsrgx/VsXsJlCviAVAVQy9gUAglF/OkK5OzbIbYd1 JFOB+G+iaxiTq/eGfXO+tnt0ICOefpuoJT8auxMoUhEy7TrA5ddujfXEwRjmLQYgH8o2 QeCzQxfRX507Y4C2n9PI74EQpTtOS2yf0w/rRxasV1decRrMyk90LlnYFvHZnEm5sbk7 wCNQ== X-Forwarded-Encrypted: i=1; AJvYcCV0CQjHMm7SPg978c0mTet3PDjLFkUjlINg7yXzc9qqGZwOEYcHbCSMNGyUE26k6rH4/LVc+x2EZptzQ9E=@vger.kernel.org X-Gm-Message-State: AOJu0YzfybFMAjE2NllpvCc5ueaZpOD4wZcVjAogMRyF9ZbOSzHAWf/N s0ET7RJVh4kBNGezvZ4o85usjAv6vuESlHcO9Cp5/I5mZjSbUtr4CHrsvuu4947gbBmu5kEHBLP H0BY6dN/l6lI4W7feV5zpfihkoA== X-Google-Smtp-Source: AGHT+IGdmlTsq6lbztVMRjjyO56iRkVOugKmnUTTc7HxcXV8zgK0D164prISKUum078Iz7YNEFORelYEVoqF+X0ffQ== X-Received: from pjbga16.prod.google.com ([2002:a17:90b:390:b0:329:7dfc:f4e1]) (user=ackerleytng job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:4b0f:b0:33b:6612:67e1 with SMTP id 98e67ed59e1d1-33bcf8fa20fmr5503758a91.29.1760731980245; Fri, 17 Oct 2025 13:13:00 -0700 (PDT) Date: Fri, 17 Oct 2025 13:12:00 -0700 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.51.0.858.gf9c4a03a3a-goog Message-ID: <023edad5cdfc155a125e30bb3d61aab3fbf6d986.1760731772.git.ackerleytng@google.com> Subject: [RFC PATCH v1 19/37] KVM: selftests: guest_memfd: Test basic single-page conversion flow From: Ackerley Tng To: cgroups@vger.kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, linux-trace-kernel@vger.kernel.org, x86@kernel.org Cc: ackerleytng@google.com, akpm@linux-foundation.org, binbin.wu@linux.intel.com, bp@alien8.de, brauner@kernel.org, chao.p.peng@intel.com, chenhuacai@kernel.org, corbet@lwn.net, dave.hansen@intel.com, dave.hansen@linux.intel.com, david@redhat.com, dmatlack@google.com, erdemaktas@google.com, fan.du@intel.com, fvdl@google.com, haibo1.xu@intel.com, hannes@cmpxchg.org, hch@infradead.org, hpa@zytor.com, hughd@google.com, ira.weiny@intel.com, isaku.yamahata@intel.com, jack@suse.cz, james.morse@arm.com, jarkko@kernel.org, jgg@ziepe.ca, jgowans@amazon.com, jhubbard@nvidia.com, jroedel@suse.de, jthoughton@google.com, jun.miao@intel.com, kai.huang@intel.com, keirf@google.com, kent.overstreet@linux.dev, liam.merwick@oracle.com, maciej.wieczor-retman@intel.com, mail@maciej.szmigiero.name, maobibo@loongson.cn, mathieu.desnoyers@efficios.com, maz@kernel.org, mhiramat@kernel.org, mhocko@kernel.org, mic@digikod.net, michael.roth@amd.com, mingo@redhat.com, mlevitsk@redhat.com, mpe@ellerman.id.au, muchun.song@linux.dev, nikunj@amd.com, nsaenz@amazon.es, oliver.upton@linux.dev, palmer@dabbelt.com, pankaj.gupta@amd.com, paul.walmsley@sifive.com, pbonzini@redhat.com, peterx@redhat.com, pgonda@google.com, prsampat@amd.com, pvorel@suse.cz, qperret@google.com, richard.weiyang@gmail.com, rick.p.edgecombe@intel.com, rientjes@google.com, rostedt@goodmis.org, roypat@amazon.co.uk, rppt@kernel.org, seanjc@google.com, shakeel.butt@linux.dev, shuah@kernel.org, steven.price@arm.com, steven.sistare@oracle.com, suzuki.poulose@arm.com, tabba@google.com, tglx@linutronix.de, thomas.lendacky@amd.com, vannapurve@google.com, vbabka@suse.cz, viro@zeniv.linux.org.uk, vkuznets@redhat.com, wei.w.wang@intel.com, will@kernel.org, willy@infradead.org, wyihan@google.com, xiaoyao.li@intel.com, yan.y.zhao@intel.com, yilun.xu@intel.com, yuzenghui@huawei.com, zhiquan1.li@intel.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a selftest for the guest_memfd memory attribute conversion ioctls. The test starts the guest_memfd as all-private (the default state), and verifies the basic flow of converting a single page to shared and then back to private. Add infrastructure that supports extensions to other conversion flow tests. This infrastructure will be used in upcoming patches for other conversion tests. Signed-off-by: Ackerley Tng Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../kvm/guest_memfd_conversions_test.c | 207 ++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 tools/testing/selftests/kvm/guest_memfd_conversions_tes= t.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 148d427ff24be..ddc1bdd51b834 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -141,6 +141,7 @@ TEST_GEN_PROGS_x86 +=3D access_tracking_perf_test TEST_GEN_PROGS_x86 +=3D coalesced_io_test TEST_GEN_PROGS_x86 +=3D dirty_log_perf_test TEST_GEN_PROGS_x86 +=3D guest_memfd_test +TEST_GEN_PROGS_x86 +=3D guest_memfd_conversions_test TEST_GEN_PROGS_x86 +=3D hardware_disable_test TEST_GEN_PROGS_x86 +=3D memslot_modification_stress_test TEST_GEN_PROGS_x86 +=3D memslot_perf_test diff --git a/tools/testing/selftests/kvm/guest_memfd_conversions_test.c b/t= ools/testing/selftests/kvm/guest_memfd_conversions_test.c new file mode 100644 index 0000000000000..e0370e92e1b24 --- /dev/null +++ b/tools/testing/selftests/kvm/guest_memfd_conversions_test.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, Google LLC. + */ +#include +#include + +#include +#include +#include + +#include "kvm_util.h" +#include "kselftest_harness.h" +#include "test_util.h" +#include "ucall_common.h" + +FIXTURE(gmem_conversions) { + struct kvm_vcpu *vcpu; + int gmem_fd; + /* HVA of the first byte of the memory mmap()-ed from gmem_fd. */ + char *mem; +}; + +typedef FIXTURE_DATA(gmem_conversions) test_data_t; + +FIXTURE_SETUP(gmem_conversions) { } + +static uint64_t page_size; + +static void guest_do_rmw(void); +#define GUEST_MEMFD_SHARING_TEST_GVA 0x90000000ULL + +/* + * Defer setup until the individual test is invoked so that tests can spec= ify + * the number of pages and flags for the guest_memfd instance. + */ +static void gmem_conversions_do_setup(test_data_t *t, int nr_pages, + int gmem_flags) +{ + const struct vm_shape shape =3D { + .mode =3D VM_MODE_DEFAULT, + .type =3D KVM_X86_SW_PROTECTED_VM, + }; + /* + * Use high GPA above APIC_DEFAULT_PHYS_BASE to avoid clashing with + * APIC_DEFAULT_PHYS_BASE. + */ + const uint64_t gpa =3D SZ_4G; + const uint32_t slot =3D 1; + struct kvm_vm *vm; + + vm =3D __vm_create_shape_with_one_vcpu(shape, &t->vcpu, nr_pages, guest_d= o_rmw); + + vm_mem_add(vm, VM_MEM_SRC_SHMEM, gpa, slot, nr_pages, + KVM_MEM_GUEST_MEMFD, -1, 0, gmem_flags); + + t->gmem_fd =3D kvm_slot_to_fd(vm, slot); + t->mem =3D addr_gpa2hva(vm, gpa); + virt_map(vm, GUEST_MEMFD_SHARING_TEST_GVA, gpa, nr_pages); +} + +static void gmem_conversions_do_teardown(test_data_t *t) +{ + /* No need to close gmem_fd, it's owned by the VM structure. */ + kvm_vm_free(t->vcpu->vm); +} + +FIXTURE_TEARDOWN(gmem_conversions) +{ + gmem_conversions_do_teardown(self); +} + +/* + * In these test definition macros, __nr_pages and nr_pages is used to set= up + * the total number of pages in the guest_memfd under test. This will be + * available in the test definitions as nr_pages. + */ + +#define __GMEM_CONVERSION_TEST(test, __nr_pages, flags) \ +static void __gmem_conversions_##test(test_data_t *t, int nr_pages); \ + \ +TEST_F(gmem_conversions, test) \ +{ \ + gmem_conversions_do_setup(self, __nr_pages, flags); \ + __gmem_conversions_##test(self, __nr_pages); \ +} \ +static void __gmem_conversions_##test(test_data_t *t, int nr_pages) \ + +#define GMEM_CONVERSION_TEST(test, __nr_pages, flags) \ + __GMEM_CONVERSION_TEST(test, __nr_pages, (flags) | GUEST_MEMFD_FLAG_MMAP) + +#define __GMEM_CONVERSION_TEST_INIT_PRIVATE(test, __nr_pages) \ + GMEM_CONVERSION_TEST(test, __nr_pages, 0) + +#define GMEM_CONVERSION_TEST_INIT_PRIVATE(test) \ + __GMEM_CONVERSION_TEST_INIT_PRIVATE(test, 1) + +struct guest_check_data { + void *mem; + char expected_val; + char write_val; +}; +static struct guest_check_data guest_data; + +static void guest_do_rmw(void) +{ + for (;;) { + char *mem =3D READ_ONCE(guest_data.mem); + + GUEST_ASSERT_EQ(READ_ONCE(*mem), READ_ONCE(guest_data.expected_val)); + WRITE_ONCE(*mem, READ_ONCE(guest_data.write_val)); + + GUEST_SYNC(0); + } +} + +static void run_guest_do_rmw(struct kvm_vcpu *vcpu, loff_t pgoff, + char expected_val, char write_val) +{ + struct ucall uc; + int r; + + guest_data.mem =3D (void *)GUEST_MEMFD_SHARING_TEST_GVA + pgoff * page_si= ze; + guest_data.expected_val =3D expected_val; + guest_data.write_val =3D write_val; + sync_global_to_guest(vcpu->vm, guest_data); + + for (;;) { + r =3D __vcpu_run(vcpu); + if (!r && get_ucall(vcpu, &uc) =3D=3D UCALL_PRINTF) { + REPORT_GUEST_PRINTF(uc); + continue; + } + if (r =3D=3D -1 && errno =3D=3D EINTR) + continue; + break; + } + + TEST_ASSERT_EQ(r, 0); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + case UCALL_SYNC: + break; + case UCALL_PRINTF: + default: + TEST_FAIL("Unexpected ucall %lu", uc.cmd); + } +} + +static void host_do_rmw(char *mem, loff_t pgoff, char expected_val, + char write_val) +{ + TEST_ASSERT_EQ(READ_ONCE(mem[pgoff * page_size]), expected_val); + WRITE_ONCE(mem[pgoff * page_size], write_val); +} + +static void test_private(test_data_t *t, loff_t pgoff, char starting_val, + char write_val) +{ + TEST_EXPECT_SIGBUS(WRITE_ONCE(t->mem[pgoff * page_size], write_val)); + run_guest_do_rmw(t->vcpu, pgoff, starting_val, write_val); + TEST_EXPECT_SIGBUS(READ_ONCE(t->mem[pgoff * page_size])); +} + +static void test_convert_to_private(test_data_t *t, loff_t pgoff, + char starting_val, char write_val) +{ + gmem_set_private(t->gmem_fd, pgoff * page_size, page_size); + test_private(t, pgoff, starting_val, write_val); +} + +static void test_shared(test_data_t *t, loff_t pgoff, char starting_val, + char host_write_val, char write_val) +{ + host_do_rmw(t->mem, pgoff, starting_val, host_write_val); + run_guest_do_rmw(t->vcpu, pgoff, host_write_val, write_val); + TEST_ASSERT_EQ(READ_ONCE(t->mem[pgoff * page_size]), write_val); +} + +static void test_convert_to_shared(test_data_t *t, loff_t pgoff, + char starting_val, char host_write_val, + char write_val) +{ + gmem_set_shared(t->gmem_fd, pgoff * page_size, page_size); + test_shared(t, pgoff, starting_val, host_write_val, write_val); +} + +GMEM_CONVERSION_TEST_INIT_PRIVATE(init_private) +{ + test_private(t, 0, 0, 'A'); + test_convert_to_shared(t, 0, 'A', 'B', 'C'); + test_convert_to_private(t, 0, 'C', 'E'); +} + + +int main(int argc, char *argv[]) +{ + TEST_REQUIRE(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SW_PROTECTED_V= M)); + TEST_REQUIRE(kvm_check_cap(KVM_CAP_GUEST_MEMFD_MEMORY_ATTRIBUTES) & + KVM_MEMORY_ATTRIBUTE_PRIVATE); + + page_size =3D getpagesize(); + + return test_harness_run(argc, argv); +} --=20 2.51.0.858.gf9c4a03a3a-goog