diff --git a/src/nodeinfo.c b/src/nodeinfo.c index 1482036a339eaf8005977ba944f98a153423afcf..d1242411e02a2f34dd77973d04ddba18fc13b765 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -1535,11 +1535,6 @@ nodeGetFreeMemoryFake(void) } #if WITH_NUMACTL - -# define n_bits(var) (8 * sizeof(var)) -# define MASK_CPU_ISSET(mask, cpu) \ - (((mask)[((cpu) / n_bits(*(mask)))] >> ((cpu) % n_bits(*(mask)))) & 1) - static virBitmapPtr virNodeGetSiblingsList(const char *dir, int cpu_id) { @@ -1592,14 +1587,12 @@ int nodeCapsInitNUMA(virCapsPtr caps) { int n; - unsigned long *mask = NULL; - unsigned long *allonesmask = NULL; unsigned long long memory; virCapsHostNUMACellCPUPtr cpus = NULL; + virBitmapPtr cpumap = NULL; int ret = -1; - int max_n_cpus = virNumaGetMaxCPUs(); - int mask_n_bytes = max_n_cpus / 8; int ncpus = 0; + int cpu; bool topology_failed = false; int max_node; @@ -1609,49 +1602,41 @@ nodeCapsInitNUMA(virCapsPtr caps) if ((max_node = virNumaGetMaxNode()) < 0) goto cleanup; - if (VIR_ALLOC_N(mask, mask_n_bytes / sizeof(*mask)) < 0) - goto cleanup; - if (VIR_ALLOC_N(allonesmask, mask_n_bytes / sizeof(*mask)) < 0) - goto cleanup; - memset(allonesmask, 0xff, mask_n_bytes); - for (n = 0; n <= max_node; n++) { size_t i; - /* The first time this returns -1, ENOENT if node doesn't exist... */ - if (numa_node_to_cpus(n, mask, mask_n_bytes) < 0) { - VIR_WARN("NUMA topology for cell %d of %d not available, ignoring", - n, max_node + 1); - continue; - } - /* second, third... times it returns an all-1's mask */ - if (memcmp(mask, allonesmask, mask_n_bytes) == 0) { - VIR_DEBUG("NUMA topology for cell %d of %d is all ones, ignoring", - n, max_node + 1); - continue; - } - /* Detect the amount of memory in the numa cell in KiB */ - virNumaGetNodeMemory(n, &memory, NULL); - memory >>= 10; + if ((ncpus = virNumaGetNodeCPUs(n, &cpumap)) < 0) { + if (ncpus == -2) + continue; - for (ncpus = 0, i = 0; i < max_n_cpus; i++) - if (MASK_CPU_ISSET(mask, i)) - ncpus++; + goto cleanup; + } if (VIR_ALLOC_N(cpus, ncpus) < 0) goto cleanup; + cpu = 0; - for (ncpus = 0, i = 0; i < max_n_cpus; i++) { - if (MASK_CPU_ISSET(mask, i)) { - if (virNodeCapsFillCPUInfo(i, cpus + ncpus++) < 0) { + for (i = 0; i < virBitmapSize(cpumap); i++) { + bool cpustate; + if (virBitmapGetBit(cpumap, i, &cpustate) < 0) + continue; + + if (cpustate) { + if (virNodeCapsFillCPUInfo(i, cpus + cpu++) < 0) { topology_failed = true; virResetLastError(); } } } + /* Detect the amount of memory in the numa cell in KiB */ + virNumaGetNodeMemory(n, &memory, NULL); + memory >>= 10; + if (virCapabilitiesAddHostNUMACell(caps, n, ncpus, memory, cpus) < 0) goto cleanup; + + cpus = NULL; } ret = 0; @@ -1660,11 +1645,12 @@ cleanup: if (topology_failed || ret < 0) virCapabilitiesClearHostNUMACellCPUTopology(cpus, ncpus); + virBitmapFree(cpumap); + VIR_FREE(cpus); + if (ret < 0) VIR_FREE(cpus); - VIR_FREE(mask); - VIR_FREE(allonesmask); return ret; } diff --git a/src/util/virnuma.c b/src/util/virnuma.c index 0530d64f58fcc0a01bbafb3a3a1ffee71fffbd92..ab4659131e2ae14216dabda9c4633fc706ce791b 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -38,6 +38,8 @@ #include "vircommand.h" #include "virerror.h" #include "virlog.h" +#include "viralloc.h" +#include "virbitmap.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -249,6 +251,83 @@ virNumaGetNodeMemory(int node, return 0; } + + +/** + * virNumaGetNodeCPUs: + * @node: identifier of the requested NUMA node + * @cpus: returns a bitmap of CPUs in @node + * + * Returns count of CPUs in the selected node and sets the map of the cpus to + * @cpus. On error if the @node doesn't exist in the system this function + * returns -2 and sets @cpus to NULL. On other errors -1 is returned, @cpus + * is set to NULL and an error is reported. + */ + +# define n_bits(var) (8 * sizeof(var)) +# define MASK_CPU_ISSET(mask, cpu) \ + (((mask)[((cpu) / n_bits(*(mask)))] >> ((cpu) % n_bits(*(mask)))) & 1) +int +virNumaGetNodeCPUs(int node, + virBitmapPtr *cpus) +{ + unsigned long *mask = NULL; + unsigned long *allonesmask = NULL; + virBitmapPtr cpumap = NULL; + int ncpus = 0; + int max_n_cpus = virNumaGetMaxCPUs(); + int mask_n_bytes = max_n_cpus / 8; + size_t i; + int ret = -1; + + *cpus = NULL; + + if (VIR_ALLOC_N(mask, mask_n_bytes / sizeof(*mask)) < 0) + goto cleanup; + + if (VIR_ALLOC_N(allonesmask, mask_n_bytes / sizeof(*mask)) < 0) + goto cleanup; + + memset(allonesmask, 0xff, mask_n_bytes); + + /* The first time this returns -1, ENOENT if node doesn't exist... */ + if (numa_node_to_cpus(node, mask, mask_n_bytes) < 0) { + VIR_WARN("NUMA topology for cell %d is not available, ignoring", node); + ret = -2; + goto cleanup; + } + + /* second, third... times it returns an all-1's mask */ + if (memcmp(mask, allonesmask, mask_n_bytes) == 0) { + VIR_DEBUG("NUMA topology for cell %d is invalid, ignoring", node); + ret = -2; + goto cleanup; + } + + if (!(cpumap = virBitmapNew(max_n_cpus))) + goto cleanup; + + for (i = 0; i < max_n_cpus; i++) { + if (MASK_CPU_ISSET(mask, i)) { + ignore_value(virBitmapSetBit(cpumap, i)); + ncpus++; + } + } + + *cpus = cpumap; + cpumap = NULL; + ret = ncpus; + +cleanup: + VIR_FREE(mask); + VIR_FREE(allonesmask); + VIR_FREE(cpumap); + + return ret; +} +# undef MASK_CPU_ISSET +# undef n_bits + #else int virNumaSetupMemoryPolicy(virNumaTuneDef numatune, @@ -295,6 +374,18 @@ virNumaGetNodeMemory(int node ATTRIBUTE_UNUSED, VIR_DEBUG("NUMA isn't available on this host"); return -1; } + + +int +virNumaGetNodeCPUs(int node ATTRIBUTE_UNUSED, + virBitmapPtr *cpus) +{ + *cpus = NULL; + + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("NUMA isn't available on this host")); + return -1; +} #endif diff --git a/src/util/virnuma.h b/src/util/virnuma.h index 62b2c0ad9c6692b260b313107d6c2ac09f92e306..eee0225eaaa8866c43d230f4962effd744036499 100644 --- a/src/util/virnuma.h +++ b/src/util/virnuma.h @@ -64,4 +64,6 @@ int virNumaGetNodeMemory(int node, unsigned int virNumaGetMaxCPUs(void); +int virNumaGetNodeCPUs(int node, virBitmapPtr *cpus); + #endif /* __VIR_NUMA_H__ */