[PATCH v3 1/4] KVM: selftests: Prepare guest_memfd_test for arbitrary NUMA nodes

From: Shivank Garg

Date: Mon Sep 07 2026 - 03:42:01 EST


Store the NUMA node IDs used by test_mbind() and
test_numa_allocation(), build nodemasks from those IDs, and use the IDs
when checking move_pages() results. This prepares both tests to select
nodes at runtime instead of assuming nodes 0 and 1.

No functional change intended.

Signed-off-by: Shivank Garg <shivankg@xxxxxxx>
---
tools/testing/selftests/kvm/guest_memfd_test.c | 53 +++++++++++++++++---------
1 file changed, 35 insertions(+), 18 deletions(-)

diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c
index cd5df88bc642..b3bd03167ba8 100644
--- a/tools/testing/selftests/kvm/guest_memfd_test.c
+++ b/tools/testing/selftests/kvm/guest_memfd_test.c
@@ -78,31 +78,35 @@ static void test_mmap_supported(int fd, size_t total_size)

static void test_mbind(int fd, size_t total_size)
{
- const unsigned long nodemask_0 = 1; /* nid: 0 */
unsigned long nodemask = 0;
unsigned long maxnode = MAXNODE_FOR_MASK(nodemask);
+ unsigned long bind_nodemask;
int policy;
char *mem;
+ int nid;
int ret;

if (!is_multi_numa_node_system())
return;

+ nid = 0;
+ bind_nodemask = BIT(nid);
+
mem = 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_mbind(mem, page_size * 2, MPOL_INTERLEAVE, &bind_nodemask, maxnode, 0);
kvm_get_mempolicy(&policy, &nodemask, maxnode, mem, MPOL_F_ADDR);
- TEST_ASSERT(policy == MPOL_INTERLEAVE && nodemask == nodemask_0,
+ TEST_ASSERT(policy == MPOL_INTERLEAVE && nodemask == bind_nodemask,
"Wanted MPOL_INTERLEAVE (%u) and nodemask 0x%lx, got %u and 0x%lx",
- MPOL_INTERLEAVE, nodemask_0, policy, nodemask);
+ MPOL_INTERLEAVE, bind_nodemask, policy, nodemask);

/* Test basic MPOL_BIND policy */
- kvm_mbind(mem + page_size * 2, page_size * 2, MPOL_BIND, &nodemask_0, maxnode, 0);
+ kvm_mbind(mem + page_size * 2, page_size * 2, MPOL_BIND, &bind_nodemask, maxnode, 0);
kvm_get_mempolicy(&policy, &nodemask, maxnode, mem + page_size * 2, MPOL_F_ADDR);
- TEST_ASSERT(policy == MPOL_BIND && nodemask == nodemask_0,
+ TEST_ASSERT(policy == MPOL_BIND && nodemask == bind_nodemask,
"Wanted MPOL_BIND (%u) and nodemask 0x%lx, got %u and 0x%lx",
- MPOL_BIND, nodemask_0, policy, nodemask);
+ MPOL_BIND, bind_nodemask, policy, nodemask);

/* Test MPOL_DEFAULT policy */
kvm_mbind(mem, total_size, MPOL_DEFAULT, NULL, 0, 0);
@@ -112,7 +116,7 @@ static void test_mbind(int fd, size_t total_size)
MPOL_DEFAULT, policy, nodemask);

/* Test with invalid policy */
- ret = mbind(mem, page_size, 999, &nodemask_0, maxnode, 0);
+ ret = mbind(mem, page_size, 999, &bind_nodemask, maxnode, 0);
TEST_ASSERT(ret == -1 && errno == EINVAL,
"mbind with invalid policy should fail with EINVAL");

@@ -121,9 +125,9 @@ static void test_mbind(int fd, size_t total_size)

static void test_numa_allocation(int fd, size_t total_size)
{
- unsigned long node0_mask = 1; /* Node 0 */
- unsigned long node1_mask = 2; /* Node 1 */
+ unsigned long node0_mask, node1_mask;
unsigned long maxnode = 8;
+ int nid0, nid1;
void *pages[4];
int status[4];
char *mem;
@@ -132,6 +136,11 @@ static void test_numa_allocation(int fd, size_t total_size)
if (!is_multi_numa_node_system())
return;

+ nid0 = 0;
+ nid1 = 1;
+ node0_mask = BIT(nid0);
+ node1_mask = BIT(nid1);
+
mem = kvm_mmap(total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);

for (i = 0; i < 4; i++)
@@ -149,10 +158,14 @@ static void test_numa_allocation(int fd, size_t total_size)

/* Validate if pages are allocated on specified NUMA nodes */
kvm_move_pages(0, 4, pages, NULL, status, 0);
- TEST_ASSERT(status[0] == 1, "Expected page 0 on node 1, got it on node %d", status[0]);
- TEST_ASSERT(status[1] == 1, "Expected page 1 on node 1, got it on node %d", status[1]);
- TEST_ASSERT(status[2] == 0, "Expected page 2 on node 0, got it on node %d", status[2]);
- TEST_ASSERT(status[3] == 0, "Expected page 3 on node 0, got it on node %d", status[3]);
+ TEST_ASSERT(status[0] == nid1, "Expected page 0 on node %d, got it on node %d",
+ nid1, status[0]);
+ TEST_ASSERT(status[1] == nid1, "Expected page 1 on node %d, got it on node %d",
+ nid1, status[1]);
+ TEST_ASSERT(status[2] == nid0, "Expected page 2 on node %d, got it on node %d",
+ nid0, status[2]);
+ TEST_ASSERT(status[3] == nid0, "Expected page 3 on node %d, got it on node %d",
+ nid0, status[3]);

/* Punch hole for all pages */
kvm_fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, total_size);
@@ -163,10 +176,14 @@ static void test_numa_allocation(int fd, size_t total_size)
memset(mem, 0xaa, total_size);

kvm_move_pages(0, 4, pages, NULL, status, 0);
- TEST_ASSERT(status[0] == 0, "Expected page 0 on node 0, got it on node %d", status[0]);
- TEST_ASSERT(status[1] == 0, "Expected page 1 on node 0, got it on node %d", status[1]);
- TEST_ASSERT(status[2] == 1, "Expected page 2 on node 1, got it on node %d", status[2]);
- TEST_ASSERT(status[3] == 1, "Expected page 3 on node 1, got it on node %d", status[3]);
+ TEST_ASSERT(status[0] == nid0, "Expected page 0 on node %d, got it on node %d",
+ nid0, status[0]);
+ TEST_ASSERT(status[1] == nid0, "Expected page 1 on node %d, got it on node %d",
+ nid0, status[1]);
+ TEST_ASSERT(status[2] == nid1, "Expected page 2 on node %d, got it on node %d",
+ nid1, status[2]);
+ TEST_ASSERT(status[3] == nid1, "Expected page 3 on node %d, got it on node %d",
+ nid1, status[3]);

kvm_munmap(mem, total_size);
}

--
2.43.0