]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
virnuma: Allow multiple nodes for preferred policy
authorMichal Privoznik <mprivozn@redhat.com>
Fri, 9 Dec 2022 13:41:24 +0000 (14:41 +0100)
committerMichal Privoznik <mprivozn@redhat.com>
Wed, 14 Dec 2022 15:07:04 +0000 (16:07 +0100)
In the past, the preferred policy
(VIR_DOMAIN_NUMATUNE_MEM_PREFERRED) required exactly one (host)
NUMA node. This made sense because:

  1) the libnuma API - numa_set_preferred() allowed exactly one
     node, because
  2) corresponding kernel syscall (__NR_set_mempolicy) accepted
     exactly one node (for MPOL_PREFERRED mode).

But things have changed since then. Firstly, kernel introduced
new MPOL_PREFERRED_MANY mode (v5.15-rc1~107^2~21) which was then
exposed in libnuma as numa_set_preferred_many() (v2.0.15~24).

Fortunately, libnuma also exposes numa_has_preferred_many() which
returns whether the kernel has support for the new mode (1) or
not (0).

Putting this all together, we can lift our check for sufficiently
new kernel and libnuma.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2151064
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
meson.build
src/util/virnuma.c

index 0f8ef079b18c25ca1e00ab3b5737d8c833d68aa6..177009c44d4763ec58c9b0a188ffbb13082a719f 100644 (file)
@@ -1059,6 +1059,9 @@ endif
 numactl_dep = cc.find_library('numa', required: get_option('numactl'))
 if numactl_dep.found()
   conf.set('WITH_NUMACTL', 1)
+  if cc.has_function('numa_set_preferred_many', dependencies: numactl_dep)
+    conf.set('WITH_NUMACTL_SET_PREFERRED_MANY', 1)
+  endif
 endif
 
 openwsman_version = '2.6.3'
index 2306ab0cb157e7003446494c51ad7f0f421ffad9..43e299f4bb62d1cb0c161f28d1fc5808e7909497 100644 (file)
@@ -93,7 +93,6 @@ virNumaSetupMemoryPolicy(virDomainNumatuneMemMode mode,
                          virBitmap *nodeset)
 {
     nodemask_t mask;
-    int node = -1;
     int bit = 0;
     size_t i;
     int maxnode = 0;
@@ -128,7 +127,19 @@ virNumaSetupMemoryPolicy(virDomainNumatuneMemMode mode,
 
     case VIR_DOMAIN_NUMATUNE_MEM_PREFERRED:
     {
+# ifdef WITH_NUMACTL_SET_PREFERRED_MANY
+        struct bitmask *bitmask = NULL;
+# endif
+        int G_GNUC_UNUSED node = -1;
         int nnodes = 0;
+        bool has_preferred_many = false;
+
+# ifdef WITH_NUMACTL_SET_PREFERRED_MANY
+        if (numa_has_preferred_many() > 0) {
+            has_preferred_many = true;
+        }
+# endif
+
         for (i = 0; i < NUMA_NUM_NODES; i++) {
             if (nodemask_isset(&mask, i)) {
                 node = i;
@@ -136,15 +147,25 @@ virNumaSetupMemoryPolicy(virDomainNumatuneMemMode mode,
             }
         }
 
-        if (nnodes != 1) {
+        if (!has_preferred_many && nnodes != 1) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("NUMA memory tuning in 'preferred' mode "
                                    "only supports single node"));
             return -1;
         }
 
+        /* The following automatically sets MPOL_PREFERRED_MANY
+         * whenever possible, so no need to special case it. */
         numa_set_bind_policy(0);
+
+# ifdef WITH_NUMACTL_SET_PREFERRED_MANY
+        bitmask = numa_bitmask_alloc(maxnode + 1);
+        copy_nodemask_to_bitmask(&mask, bitmask);
+        numa_set_preferred_many(bitmask);
+        numa_bitmask_free(bitmask);
+# else
         numa_set_preferred(node);
+# endif
     }
     break;