From nobody Sun Feb 8 14:10:22 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 375852701B1 for ; Tue, 7 Oct 2025 22:14:57 +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=1759875299; cv=none; b=g9DsIBop7AsdpVx9V5bByZF4oc71VD1Zqpdb9rdTt/ym9xiSD+ZrSmNPSfE7vyv9Lqs8DvA5gi9c3upSC6cbhVXlD51A/1HF1XDa+j4KwjjIB6uTTJ16EiI+DZvo+4rkTTY/3iUCr48dc+txCj+hqvqC1td6zMYtheDrjQ7Jwq0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759875299; c=relaxed/simple; bh=CDrOrMNO9l5cLoWd98CveZ7KTkfm+YOe4TpGJ/Wt4fA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=taofAPGM4A4hoyolH/CjDHg3t9x2RU9FUKvimNtQTVjzY3uJIA0n+wXoKn3vIgPN49jt/33C0GWyMqn4eNgUlEqrnGsFZi7jLHeY5U7w0mAtASBkxCDuwK99IfIfjbh5Bg3t5yQoVPT6PCH0/xWiiGbqyMwDZoOLyztaBCnmcys= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=FLWPwpq8; 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--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="FLWPwpq8" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-3304def7909so6405222a91.3 for ; Tue, 07 Oct 2025 15:14:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759875296; x=1760480096; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=pq3jKNyKi/1WXgeEr4Kt/LxPicRmmT3+M3Z6Wud5iC8=; b=FLWPwpq8qHzErasoo0s+GiCDnuNienIoDh3KHs2K9VzAVAtpG8pMjwLOlOO4PbKkA+ HZbw51XqkuHfXX7Jr6XQsgtq6a3Klbx+IKrhcepWh/MengsZhfuqLhcklu1SnSW7+XzF Bk2X/EtNrU0cAAccKOgXNxF1T64b/LZq8+L89c6lxTsUc5VtR5bWXl4CqM+DdWOm0JzV FYaSOq/Bo8hQ8ghkMbaJc68C4urD6ZH/lE1aDj6FkLwhVLbzKMmhEilHKglQyaaX53k9 hqjvrMKyI1UFXFqQjB7stZINuWSlXVzkkrf82pfbhxpHZ3tQxoJDTzNYZf5+bp1kVXOT zJiQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759875296; x=1760480096; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=pq3jKNyKi/1WXgeEr4Kt/LxPicRmmT3+M3Z6Wud5iC8=; b=BL2Fch+U9Ys2dJR/GLC67k2tOMDqJCdDIth3jAYaGvmmo+hMJUUgojuVZfUsrtUBLq CTQlfPNjY7k6mGD5tTE5w5n16RJKw1+atw0WVZRuLphvhj8oG4oAfvXkKdevtbC01P+o U6gJFTSEP7RxjbnE6iv+/PqIEWhAjP21LfzHOTAfhgccZO3sHS1Zu92fC/FoVWj9J5OI gPC+PqinjzP3wlfWgkaP0pzefxO37wB7pgFEpF3QtOmgwXPdsHmi4nqQruj/YnH+ubXf Adjm+2y8CQIJp1lsRuNHhs328gRNfsnpitfm7hc9YrP7j6b+cHtSRJApON8ATWzNJllr ybMQ== X-Forwarded-Encrypted: i=1; AJvYcCX2h9LFhhI0fxFWq37f1IprQnAJIuP2Z1QgJCTGvpXGo7dw5Nwv69u5J4N+6JZ9+X48FAtuH0B3ihXx3J4=@vger.kernel.org X-Gm-Message-State: AOJu0YxJ9pI77SPSd4gb5Zu9j4P58SIna70puDeVoEUbDg//dt9tSrzW 6SaALQOh4VEc3GE+Afg+SFWn5ZiXBryE+NUZwv8cJCIVbHwZPPj4uE11Ia1qiyIFGHAM1Xs+sVo qyp/5UQ== X-Google-Smtp-Source: AGHT+IFr1z+OHs2pqkHxNhtbO8xQGrGNQletDRxpDZROHoK8rGfdZgYkQaGuDGapxPz1ninSCtdpRZhLQBs= X-Received: from pjbmw12.prod.google.com ([2002:a17:90b:4d0c:b0:329:b272:45a7]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:1b4c:b0:327:9e88:7714 with SMTP id 98e67ed59e1d1-33b513ebf89mr1315059a91.37.1759875296568; Tue, 07 Oct 2025 15:14:56 -0700 (PDT) Reply-To: Sean Christopherson Date: Tue, 7 Oct 2025 15:14:19 -0700 In-Reply-To: <20251007221420.344669-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20251007221420.344669-1-seanjc@google.com> X-Mailer: git-send-email 2.51.0.710.ga91ca5db03-goog Message-ID: <20251007221420.344669-12-seanjc@google.com> Subject: [PATCH v12 11/12] KVM: selftests: Add guest_memfd tests for mmap and NUMA policy support From: Sean Christopherson To: Marc Zyngier , Oliver Upton , Paolo Bonzini , Sean Christopherson Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-kernel@vger.kernel.org, David Hildenbrand , Fuad Tabba , Ackerley Tng , Shivank Garg , Ashish Kalra , Vlastimil Babka Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Shivank Garg Add tests for NUMA memory policy binding and NUMA aware allocation in guest_memfd. This extends the existing selftests by adding proper validation for: - KVM GMEM set_policy and get_policy() vm_ops functionality using mbind() and get_mempolicy() - NUMA policy application before and after memory allocation Run the NUMA mbind() test with and without INIT_SHARED, as KVM should allow doing mbind(), madvise(), etc. on guest-private memory, e.g. so that userspace can set NUMA policy for CoCo VMs. Run the NUMA allocation test only for INIT_SHARED, i.e. if the host can't fault-in memory (via direct access, madvise(), etc.) as move_pages() returns -ENOENT if the page hasn't been faulted in (walks the host page tables to find the associated folio) Signed-off-by: Shivank Garg Tested-by: Ashish Kalra [sean: don't skip entire test when running on non-NUMA system, test mbind() with private memory, provide more info in assert messages] Signed-off-by: Sean Christopherson --- .../testing/selftests/kvm/guest_memfd_test.c | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing= /selftests/kvm/guest_memfd_test.c index e7d9aeb418d3..618c937f3c90 100644 --- a/tools/testing/selftests/kvm/guest_memfd_test.c +++ b/tools/testing/selftests/kvm/guest_memfd_test.c @@ -19,6 +19,7 @@ #include =20 #include "kvm_util.h" +#include "numaif.h" #include "test_util.h" #include "ucall_common.h" =20 @@ -75,6 +76,101 @@ static void test_mmap_supported(int fd, size_t total_si= ze) kvm_munmap(mem, total_size); } =20 +static void test_mbind(int fd, size_t total_size) +{ + const unsigned long nodemask_0 =3D 1; /* nid: 0 */ + unsigned long nodemask =3D 0; + unsigned long maxnode =3D 8; + int policy; + char *mem; + int ret; + + if (!is_multi_numa_node_system()) + return; + + mem =3D kvm_mmap(total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd); + + /* Test MPOL_INTERLEAVE policy */ + kvm_mbind(mem, page_size * 2, MPOL_INTERLEAVE, &nodemask_0, maxnode, 0); + kvm_get_mempolicy(&policy, &nodemask, maxnode, mem, MPOL_F_ADDR); + TEST_ASSERT(policy =3D=3D MPOL_INTERLEAVE && nodemask =3D=3D nodemask_0, + "Wanted MPOL_INTERLEAVE (%u) and nodemask 0x%lx, got %u and 0x%lx", + MPOL_INTERLEAVE, nodemask_0, policy, nodemask); + + /* Test basic MPOL_BIND policy */ + kvm_mbind(mem + page_size * 2, page_size * 2, MPOL_BIND, &nodemask_0, max= node, 0); + kvm_get_mempolicy(&policy, &nodemask, maxnode, mem + page_size * 2, MPOL_= F_ADDR); + TEST_ASSERT(policy =3D=3D MPOL_BIND && nodemask =3D=3D nodemask_0, + "Wanted MPOL_BIND (%u) and nodemask 0x%lx, got %u and 0x%lx", + MPOL_BIND, nodemask_0, policy, nodemask); + + /* Test MPOL_DEFAULT policy */ + kvm_mbind(mem, total_size, MPOL_DEFAULT, NULL, 0, 0); + kvm_get_mempolicy(&policy, &nodemask, maxnode, mem, MPOL_F_ADDR); + TEST_ASSERT(policy =3D=3D MPOL_DEFAULT && !nodemask, + "Wanted MPOL_DEFAULT (%u) and nodemask 0x0, got %u and 0x%lx", + MPOL_DEFAULT, policy, nodemask); + + /* Test with invalid policy */ + ret =3D mbind(mem, page_size, 999, &nodemask_0, maxnode, 0); + TEST_ASSERT(ret =3D=3D -1 && errno =3D=3D EINVAL, + "mbind with invalid policy should fail with EINVAL"); + + kvm_munmap(mem, total_size); +} + +static void test_numa_allocation(int fd, size_t total_size) +{ + unsigned long node0_mask =3D 1; /* Node 0 */ + unsigned long node1_mask =3D 2; /* Node 1 */ + unsigned long maxnode =3D 8; + void *pages[4]; + int status[4]; + char *mem; + int i; + + if (!is_multi_numa_node_system()) + return; + + mem =3D kvm_mmap(total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd); + + for (i =3D 0; i < 4; i++) + pages[i] =3D (char *)mem + page_size * i; + + /* Set NUMA policy after allocation */ + memset(mem, 0xaa, page_size); + kvm_mbind(pages[0], page_size, MPOL_BIND, &node0_mask, maxnode, 0); + kvm_fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, page_siz= e); + + /* Set NUMA policy before allocation */ + kvm_mbind(pages[0], page_size * 2, MPOL_BIND, &node1_mask, maxnode, 0); + kvm_mbind(pages[2], page_size * 2, MPOL_BIND, &node0_mask, maxnode, 0); + memset(mem, 0xaa, total_size); + + /* Validate if pages are allocated on specified NUMA nodes */ + kvm_move_pages(0, 4, pages, NULL, status, 0); + TEST_ASSERT(status[0] =3D=3D 1, "Expected page 0 on node 1, got it on nod= e %d", status[0]); + TEST_ASSERT(status[1] =3D=3D 1, "Expected page 1 on node 1, got it on nod= e %d", status[1]); + TEST_ASSERT(status[2] =3D=3D 0, "Expected page 2 on node 0, got it on nod= e %d", status[2]); + TEST_ASSERT(status[3] =3D=3D 0, "Expected page 3 on node 0, got it on nod= e %d", status[3]); + + /* Punch hole for all pages */ + kvm_fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, total_si= ze); + + /* Change NUMA policy nodes and reallocate */ + kvm_mbind(pages[0], page_size * 2, MPOL_BIND, &node0_mask, maxnode, 0); + kvm_mbind(pages[2], page_size * 2, MPOL_BIND, &node1_mask, maxnode, 0); + memset(mem, 0xaa, total_size); + + kvm_move_pages(0, 4, pages, NULL, status, 0); + TEST_ASSERT(status[0] =3D=3D 0, "Expected page 0 on node 0, got it on nod= e %d", status[0]); + TEST_ASSERT(status[1] =3D=3D 0, "Expected page 1 on node 0, got it on nod= e %d", status[1]); + TEST_ASSERT(status[2] =3D=3D 1, "Expected page 2 on node 1, got it on nod= e %d", status[2]); + TEST_ASSERT(status[3] =3D=3D 1, "Expected page 3 on node 1, got it on nod= e %d", status[3]); + + kvm_munmap(mem, total_size); +} + static void test_fault_sigbus(int fd, size_t accessible_size, size_t map_s= ize) { const char val =3D 0xaa; @@ -273,11 +369,13 @@ static void __test_guest_memfd(struct kvm_vm *vm, uin= t64_t flags) if (flags & GUEST_MEMFD_FLAG_INIT_SHARED) { gmem_test(mmap_supported, vm, flags); gmem_test(fault_overflow, vm, flags); + gmem_test(numa_allocation, vm, flags); } else { gmem_test(fault_private, vm, flags); } =20 gmem_test(mmap_cow, vm, flags); + gmem_test(mbind, vm, flags); } else { gmem_test(mmap_not_supported, vm, flags); } --=20 2.51.0.710.ga91ca5db03-goog