On Tue, 2026-09-01 at 10:28 -0700, Sean Christopherson wrote:
> On Tue, Sep 01, 2026, Shivank Garg wrote:
> > guest_memfd_test assumes that nodes 0 and 1 exist and have memory.
> > is_multi_numa_node_system() only checks that the maximum node ID is
> > nonzero, which is not enough for sparse or memoryless nodes.
> > 
> > Select the required nodes from MPOL_F_MEMS_ALLOWED instead. Use the full
> > nodemask width plus one to mbind(), and let test_mbind() run when only
> > one memory node is available.
> 
> Please split this into at least three patches.
> 
>   1. Refactor guest_memfd_test.c to prepare for using nodes other than 0 and 
> 1.
>   2. Fix test_mbind().
>   3. Fix test_numa_allocation().
>   4. If necessary, do additional cleanups in numaif.h
> 
> As is, this is extremely difficult to review, e.g. without staring intently, I
> can't tell what's refactoring and what's actually a functional change.
> 
Agreed, will split this patch.

> Actually, looking at the xAPIC IPI test more, what you proposed in patch 3 is 
> in
> the general direction of what we want, but needs to be more than just a 
> wrapper
> for get_mempolicy() to be useful.  Specificaly, if it fills the mask *and* 
> returns
> the number of nodes found, then it's more generically useful.  And if we also 
> add
> an API to get the next (exclusive) node, then we can cut down on the amount of
> copy+paste without forcing tests to use the "array of one-bit nodemasks" 
> approach
> that the xAPIC test uses.
> 
> E.g. the below get_numa_node_ids() is basically just copy+paste from the xAPIC
> test, except that it returns an array of nodes instead of an array of 
> nodemasks.
> The fact that you felt compelled to copy+paste instead of adding an API is 
> quite
> telling: using an array of nodemasks/nodes is inflexible and really only 
> works if
> a test wants to target exactly one node.  It's also annoying to extract to a 
> generic
> API without ending up with a brittle API.  E.g. if the API where to take the 
> a mask
> and an array, it would either have to be a macro or take a struct to ensure 
> the
> array can hold all possible masks.
> 
> I'm planning on adding these in the series to also add MAXNODE_FOR_MASK().
> 
> static inline int kvm_get_numa_memory_nodes(unsigned long *nodemask)
> {
>       int r;
> 
>       *nodemask = 0;
> 
>       r = get_mempolicy(NULL, nodemask, MAXNODE_FOR_MASK(*nodemask), 0,
>                         MPOL_F_MEMS_ALLOWED);
>       TEST_ASSERT(!r || errno == ENOSYS || errno == EPERM,
>                   "Unexpected get_mempolicy() failure");
>       return __builtin_popcountl(*nodemask);
> }
> 
> /*
>  * Return the node ID of the next NUMA node in the mask, starting at @from+1.
>  * Guarantees a node is found, and that the found node is not @from.  Pass -1
>  * to find the first node in the mask.
>  */
> static inline int kvm_get_next_numa_node(unsigned long nodemask, int from)
> {
>       const unsigned long nr_bits = BITS_PER_TYPE(nodemask);
>       int to;
> 
>       to = find_next_bit(&nodemask, nr_bits, from + 1);
>       if (to == nr_bits)
>               to = find_next_bit(&nodemask, nr_bits, 0);
> 
>       TEST_ASSERT(to != nr_bits && to != from,
>                   "Unabled to find second NUMA node (from = %d, to = %d)", 
> from, to);
>       return to;
> }
> 
> > The sysfs helpers for finding maxnode are no longer needed.
> 
> This is an observation, not a proper changelog sentence.
> 
> > Signed-off-by: Shivank Garg <[email protected]>
> > ---
> >  tools/testing/selftests/kvm/guest_memfd_test.c | 86 
> > +++++++++++++++++---------
> >  tools/testing/selftests/kvm/include/numaif.h   | 52 ----------------
> >  2 files changed, 58 insertions(+), 80 deletions(-)
> > 
> > diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c 
> > b/tools/testing/selftests/kvm/guest_memfd_test.c
> > index 2233d871a38f..aee80dda6229 100644
> > --- a/tools/testing/selftests/kvm/guest_memfd_test.c
> > +++ b/tools/testing/selftests/kvm/guest_memfd_test.c
> > @@ -76,33 +76,53 @@ static void test_mmap_supported(int fd, size_t 
> > total_size)
> >     kvm_munmap(mem, total_size);
> >  }
> >  
> > +/*
> > + * Fill @nids with the first @nr_nids nodes in the allowed mask.
> > + * Return false if the mask contains fewer than @nr_nids nodes.
> > + */
> > +static bool get_numa_node_ids(int *nids, int nr_nids)
> > +{
> > +   unsigned long nodemask = get_numa_mem_nodes();
> > +   unsigned long nid;
> > +   int nr_found = 0;
> > +
> > +   for_each_set_bit(nid, &nodemask, BITS_PER_TYPE(nodemask)) {
> > +           nids[nr_found++] = nid;
> > +           if (nr_found == nr_nids)
> > +                   return true;
> > +   }
> > +
> > +   return false;
> > +}
> > +
> >  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 = BITS_PER_TYPE(nodemask);
> > +   unsigned long nodemask, bind_nodemask;
> > +   unsigned long maxnode = BITS_PER_TYPE(nodemask) + 1;
> >     int policy;
> >     char *mem;
> > +   int nid;
> >     int ret;
> >  
> > -   if (!is_multi_numa_node_system())
> > +   if (!get_numa_node_ids(&nid, 1))
> 
> This is not functionally equivalent.  The existing test requires multiple NUMA
> nodes, whereas this will now succeed if there's exactly one node.  That could 
> be
> totally fine, but it needs to be isolated and explained in its own patch.

Sure.

Thanks,
Shivank

Reply via email to