[PATCH 00/14] qemuBuildThreadContextProps: Prune .node-afinity wrt <emulatorpin/>

See 12/14 for explanation and seeing the fix in action. Michal Prívozník (14): virnuma: Move virNumaNodesetToCPUset() our of WITH_NUMACTL virnuma: Introduce virNumaCPUSetToNodeset() virnumamock: Introduce virNumaGetNodeOfCPU() mock qemuxml2argvtest: Use virnuma mock qemuxml2argvdata: Adjust maximum NUMA node used qemuxml2argvdata: Extend vCPUs placement in memory-hotplug-dimm-addr.xml qemuxml2argvmock: Drop virNuma* mocks qemu: Move cpuset preference evaluation into a separate function qemu: Fix qemuDomainGetEmulatorPinInfo() qemu: Add @nodemaskRet argument to qemuBuildMemoryBackendProps() qemu: Add @nodemask argument to qemuBuildThreadContextProps() qemuBuildThreadContextProps: Prune .node-afinity wrt <emulatorpin/> docs: Document memory allocation and emulator pinning limitation NEWS: Document recent thread-context bug fix NEWS.rst | 7 + docs/formatdomain.rst | 4 +- src/libvirt_private.syms | 2 + src/qemu/qemu_command.c | 90 +++++++---- src/qemu/qemu_command.h | 8 +- src/qemu/qemu_domain.c | 18 +++ src/qemu/qemu_domain.h | 5 + src/qemu/qemu_driver.c | 11 +- src/qemu/qemu_hotplug.c | 2 +- src/qemu/qemu_process.c | 9 +- src/util/virnuma.c | 148 ++++++++++++------ src/util/virnuma.h | 5 +- tests/meson.build | 2 +- ...emory-hotplug-dimm-addr.x86_64-latest.args | 2 +- .../memory-hotplug-dimm-addr.xml | 2 +- .../migrate-numa-unaligned.args | 4 +- .../migrate-numa-unaligned.xml | 4 +- .../numatune-memnode-restrictive-mode.xml | 4 +- ...-unavailable-restrictive.x86_64-latest.err | 2 +- ...mnode-unavailable-strict.x86_64-latest.err | 2 +- tests/qemuxml2argvdata/numatune-memnode.args | 4 +- .../numatune-memnode.x86_64-5.2.0.args | 4 +- .../numatune-memnode.x86_64-latest.args | 4 +- tests/qemuxml2argvdata/numatune-memnode.xml | 4 +- ...umatune-static-nodeset-exceed-hostnode.err | 2 +- tests/qemuxml2argvmock.c | 41 ----- tests/qemuxml2argvtest.c | 5 +- ...memory-hotplug-dimm-addr.x86_64-latest.xml | 2 +- tests/qemuxml2xmloutdata/numatune-memnode.xml | 4 +- .../linux-basic/system/cpu/cpu0/node0 | 1 + .../linux-basic/system/cpu/cpu1/node0 | 1 + .../linux-basic/system/cpu/cpu10/node2 | 1 + .../linux-basic/system/cpu/cpu11/node2 | 1 + .../linux-basic/system/cpu/cpu12/node3 | 1 + .../linux-basic/system/cpu/cpu13/node3 | 1 + .../linux-basic/system/cpu/cpu14/node3 | 1 + .../linux-basic/system/cpu/cpu15/node3 | 1 + .../linux-basic/system/cpu/cpu2/node0 | 1 + .../linux-basic/system/cpu/cpu3/node0 | 1 + .../linux-basic/system/cpu/cpu4/node1 | 1 + .../linux-basic/system/cpu/cpu5/node1 | 1 + .../linux-basic/system/cpu/cpu6/node1 | 1 + .../linux-basic/system/cpu/cpu7/node1 | 1 + .../linux-basic/system/cpu/cpu8/node2 | 1 + .../linux-basic/system/cpu/cpu9/node2 | 1 + .../linux-caches/system/cpu/cpu0/node0 | 1 + .../linux-caches/system/cpu/cpu1/node0 | 1 + .../linux-caches/system/cpu/cpu2/node0 | 1 + .../linux-caches/system/cpu/cpu3/node0 | 1 + .../linux-caches/system/cpu/cpu4/node0 | 1 + .../linux-caches/system/cpu/cpu5/node0 | 1 + .../linux-caches/system/cpu/cpu6/node0 | 1 + .../linux-caches/system/cpu/cpu7/node0 | 1 + .../system/cpu/cpu0/node0 | 1 + .../linux-resctrl/system/cpu/cpu0/node0 | 1 + .../linux-resctrl/system/cpu/cpu1/node0 | 1 + .../linux-resctrl/system/cpu/cpu10/node1 | 1 + .../linux-resctrl/system/cpu/cpu11/node1 | 1 + .../linux-resctrl/system/cpu/cpu2/node0 | 1 + .../linux-resctrl/system/cpu/cpu3/node0 | 1 + .../linux-resctrl/system/cpu/cpu4/node0 | 1 + .../linux-resctrl/system/cpu/cpu5/node0 | 1 + .../linux-resctrl/system/cpu/cpu6/node1 | 1 + .../linux-resctrl/system/cpu/cpu7/node1 | 1 + .../linux-resctrl/system/cpu/cpu8/node1 | 1 + .../linux-resctrl/system/cpu/cpu9/node1 | 1 + tests/virnumamock.c | 42 +++++ 67 files changed, 317 insertions(+), 163 deletions(-) create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu1/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu10/node2 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu11/node2 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu12/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu13/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu14/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu15/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu2/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu3/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu4/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu5/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu6/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu7/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu8/node2 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu9/node2 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu1/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu2/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu3/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu4/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu5/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu6/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu7/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl-skx-twocaches/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu1/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu10/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu11/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu2/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu3/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu4/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu5/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu6/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu7/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu8/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu9/node1 -- 2.39.2

Technically, there's nothing libnuma specific about virNumaNodesetToCPUset(). It just implements a generic algorithm over virNumaGetNodeCPUs() (which is then libnuma dependant). Nevertheless, there's no need to have this function living inside WITH_NUMACTL block. Any error returned from virNumaGetNodeCPUs() (including the one that !WITH_NUMACTL stub returns) is propagated properly. Move the function out of the block into a generic one and drop the !WITH_NUMACTL stub. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/virnuma.c | 115 +++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 62 deletions(-) diff --git a/src/util/virnuma.c b/src/util/virnuma.c index 43e299f4bb..dae0827c65 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -311,57 +311,6 @@ virNumaGetNodeCPUs(int node, # undef MASK_CPU_ISSET # undef n_bits -/** - * virNumaNodesetToCPUset: - * @nodeset: bitmap containing a set of NUMA nodes - * @cpuset: return location for a bitmap containing a set of CPUs - * - * Convert a set of NUMA node to the set of CPUs they contain. - * - * Returns 0 on success, <0 on failure. - */ -int -virNumaNodesetToCPUset(virBitmap *nodeset, - virBitmap **cpuset) -{ - g_autoptr(virBitmap) allNodesCPUs = NULL; - size_t nodesetSize; - size_t i; - - *cpuset = NULL; - - if (!nodeset) - return 0; - - allNodesCPUs = virBitmapNew(0); - nodesetSize = virBitmapSize(nodeset); - - for (i = 0; i < nodesetSize; i++) { - g_autoptr(virBitmap) nodeCPUs = NULL; - int rc; - - if (!virBitmapIsBitSet(nodeset, i)) - continue; - - rc = virNumaGetNodeCPUs(i, &nodeCPUs); - if (rc < 0) { - /* Error is reported for cases other than non-existent NUMA node. */ - if (rc == -2) { - virReportError(VIR_ERR_OPERATION_FAILED, - _("NUMA node %zu is not available"), - i); - } - return -1; - } - - virBitmapUnion(allNodesCPUs, nodeCPUs); - } - - *cpuset = g_steal_pointer(&allNodesCPUs); - - return 0; -} - #else /* !WITH_NUMACTL */ int @@ -417,17 +366,6 @@ virNumaGetNodeCPUs(int node G_GNUC_UNUSED, return -1; } -int -virNumaNodesetToCPUset(virBitmap *nodeset G_GNUC_UNUSED, - virBitmap **cpuset) -{ - *cpuset = NULL; - - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("NUMA isn't available on this host")); - return -1; -} - #endif /* !WITH_NUMACTL */ /** @@ -1050,3 +988,56 @@ virNumaGetHostMemoryNodeset(void) return nodeset; } + + +/** + * virNumaNodesetToCPUset: + * @nodeset: bitmap containing a set of NUMA nodes + * @cpuset: return location for a bitmap containing a set of CPUs + * + * Convert a set of NUMA node to the set of CPUs they contain. + * + * Returns 0 on success, + * -1 on failure (with error reported). + */ +int +virNumaNodesetToCPUset(virBitmap *nodeset, + virBitmap **cpuset) +{ + g_autoptr(virBitmap) allNodesCPUs = NULL; + size_t nodesetSize; + size_t i; + + *cpuset = NULL; + + if (!nodeset) + return 0; + + allNodesCPUs = virBitmapNew(0); + nodesetSize = virBitmapSize(nodeset); + + for (i = 0; i < nodesetSize; i++) { + g_autoptr(virBitmap) nodeCPUs = NULL; + int rc; + + if (!virBitmapIsBitSet(nodeset, i)) + continue; + + rc = virNumaGetNodeCPUs(i, &nodeCPUs); + if (rc < 0) { + /* Error is reported for cases other than non-existent NUMA node. */ + if (rc == -2) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("NUMA node %zu is not available"), + i); + } + return -1; + } + + virBitmapUnion(allNodesCPUs, nodeCPUs); + } + + *cpuset = g_steal_pointer(&allNodesCPUs); + + return 0; +} -- 2.39.2

On Wed, Mar 08, 2023 at 12:14:28PM +0100, Michal Privoznik wrote:
Technically, there's nothing libnuma specific about virNumaNodesetToCPUset(). It just implements a generic algorithm over virNumaGetNodeCPUs() (which is then libnuma dependant). Nevertheless, there's no need to have this function living inside WITH_NUMACTL block. Any error returned from virNumaGetNodeCPUs() (including the one that !WITH_NUMACTL stub returns) is propagated properly.
Move the function out of the block into a generic one and drop the !WITH_NUMACTL stub.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/virnuma.c | 115 +++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 62 deletions(-)
Reviewed-by: Andrea Bolognani <abologna@redhat.com> -- Andrea Bolognani / Red Hat / Virtualization

On Wed, Mar 8, 2023 at 12:16 PM Michal Privoznik <mprivozn@redhat.com> wrote:
Technically, there's nothing libnuma specific about virNumaNodesetToCPUset(). It just implements a generic algorithm over virNumaGetNodeCPUs() (which is then libnuma dependant). Nevertheless, there's no need to have this function living inside WITH_NUMACTL block. Any error returned from virNumaGetNodeCPUs() (including the one that !WITH_NUMACTL stub returns) is propagated properly.
Move the function out of the block into a generic one and drop the !WITH_NUMACTL stub.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/virnuma.c | 115 +++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 62 deletions(-)
Reviewed-by: Kristina Hanicova <khanicov@redhat.com> Kristina

So far, we have a function that expands given list of NUMA nodes into list of CPUs. But soon, we are going to need the inverse - expand list of CPUs into list of NUMA nodes. Introduce virNumaCPUSetToNodeset() for that. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/libvirt_private.syms | 2 ++ src/util/virnuma.c | 59 ++++++++++++++++++++++++++++++++++++++++ src/util/virnuma.h | 3 ++ 3 files changed, 64 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d5b1b9cb72..3ae97e62de 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2975,6 +2975,7 @@ virNodeSuspendGetTargetMask; # util/virnuma.h +virNumaCPUSetToNodeset; virNumaGetAutoPlacementAdvice; virNumaGetDistances; virNumaGetHostMemoryNodeset; @@ -2982,6 +2983,7 @@ virNumaGetMaxCPUs; virNumaGetMaxNode; virNumaGetNodeCPUs; virNumaGetNodeMemory; +virNumaGetNodeOfCPU; virNumaGetPageInfo; virNumaGetPages; virNumaIsAvailable; diff --git a/src/util/virnuma.c b/src/util/virnuma.c index dae0827c65..5f484a16f5 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -311,6 +311,22 @@ virNumaGetNodeCPUs(int node, # undef MASK_CPU_ISSET # undef n_bits + +/** + * virNumaGetNodeOfCPU: + * @cpu: CPU ID + * + * For given @cpu, return NUMA node which it belongs to. + * + * Returns: NUMA node # on success, + * -1 on failure (with errno set). + */ +int +virNumaGetNodeOfCPU(int cpu) +{ + return numa_node_of_cpu(cpu); +} + #else /* !WITH_NUMACTL */ int @@ -366,6 +382,14 @@ virNumaGetNodeCPUs(int node G_GNUC_UNUSED, return -1; } +int +virNumaGetNodeOfCPU(int cpu G_GNUC_UNUSED) +{ + errno = ENOSYS; + return -1; +} + + #endif /* !WITH_NUMACTL */ /** @@ -990,6 +1014,41 @@ virNumaGetHostMemoryNodeset(void) } +/** + * virNumaNodesetToCPUset: + * @nodeset: returned bitmap containing a set of NUMA nodes + * @cpuset: bitmap containing a set of CPUs + * + * Convert a set of CPUs to set of NUMA nodes that contain the CPUs. + * + * Returns: 0 on success, + * -1 on failure (with error reported) + */ +int +virNumaCPUSetToNodeset(virBitmap **nodeset, + virBitmap *cpuset) +{ + g_autoptr(virBitmap) nodes = virBitmapNew(0); + ssize_t pos = -1; + + while ((pos = virBitmapNextSetBit(cpuset, pos)) >= 0) { + int node = virNumaGetNodeOfCPU(pos); + + if (node < 0) { + virReportSystemError(errno, + _("Unable to get NUMA node of cpu %zd"), + pos); + return -1; + } + + virBitmapSetBitExpand(nodes, node); + } + + *nodeset = g_steal_pointer(&nodes); + return 0; +} + + /** * virNumaNodesetToCPUset: * @nodeset: bitmap containing a set of NUMA nodes diff --git a/src/util/virnuma.h b/src/util/virnuma.h index c35acd47cb..67e699f2cf 100644 --- a/src/util/virnuma.h +++ b/src/util/virnuma.h @@ -45,7 +45,10 @@ int virNumaGetNodeMemory(int node, unsigned int virNumaGetMaxCPUs(void) G_NO_INLINE; +int virNumaGetNodeOfCPU(int cpu); int virNumaGetNodeCPUs(int node, virBitmap **cpus) G_NO_INLINE; +int virNumaCPUSetToNodeset(virBitmap **nodeset, + virBitmap *cpuset); int virNumaNodesetToCPUset(virBitmap *nodeset, virBitmap **cpuset); -- 2.39.2

On Wed, Mar 8, 2023 at 12:15 PM Michal Privoznik <mprivozn@redhat.com> wrote:
So far, we have a function that expands given list of NUMA nodes into list of CPUs. But soon, we are going to need the inverse - expand list of CPUs into list of NUMA nodes. Introduce virNumaCPUSetToNodeset() for that.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/libvirt_private.syms | 2 ++ src/util/virnuma.c | 59 ++++++++++++++++++++++++++++++++++++++++ src/util/virnuma.h | 3 ++ 3 files changed, 64 insertions(+)
Reviewed-by: Kristina Hanicova <khanicov@redhat.com> Kristina

On Wed, Mar 08, 2023 at 12:14:29PM +0100, Michal Privoznik wrote:
+/** + * virNumaNodesetToCPUset: + * @nodeset: returned bitmap containing a set of NUMA nodes + * @cpuset: bitmap containing a set of CPUs + * + * Convert a set of CPUs to set of NUMA nodes that contain the CPUs. + * + * Returns: 0 on success, + * -1 on failure (with error reported) + */ +int +virNumaCPUSetToNodeset(virBitmap **nodeset, + virBitmap *cpuset)
The name of the function in the docstring is wrong. Please also consider swapping the arguments, to match the name of the function and how the existing virNumaNodesetToCPUset() does it. -- Andrea Bolognani / Red Hat / Virtualization

Introduce a mock of virNumaGetNodeOfCPU() because soon we will need virNumaCPUSetToNodeset() to return predictable results. Also, fill in missing symlinks in vircaps2xmldata/. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/virnuma.h | 2 +- .../linux-basic/system/cpu/cpu0/node0 | 1 + .../linux-basic/system/cpu/cpu1/node0 | 1 + .../linux-basic/system/cpu/cpu10/node2 | 1 + .../linux-basic/system/cpu/cpu11/node2 | 1 + .../linux-basic/system/cpu/cpu12/node3 | 1 + .../linux-basic/system/cpu/cpu13/node3 | 1 + .../linux-basic/system/cpu/cpu14/node3 | 1 + .../linux-basic/system/cpu/cpu15/node3 | 1 + .../linux-basic/system/cpu/cpu2/node0 | 1 + .../linux-basic/system/cpu/cpu3/node0 | 1 + .../linux-basic/system/cpu/cpu4/node1 | 1 + .../linux-basic/system/cpu/cpu5/node1 | 1 + .../linux-basic/system/cpu/cpu6/node1 | 1 + .../linux-basic/system/cpu/cpu7/node1 | 1 + .../linux-basic/system/cpu/cpu8/node2 | 1 + .../linux-basic/system/cpu/cpu9/node2 | 1 + .../linux-caches/system/cpu/cpu0/node0 | 1 + .../linux-caches/system/cpu/cpu1/node0 | 1 + .../linux-caches/system/cpu/cpu2/node0 | 1 + .../linux-caches/system/cpu/cpu3/node0 | 1 + .../linux-caches/system/cpu/cpu4/node0 | 1 + .../linux-caches/system/cpu/cpu5/node0 | 1 + .../linux-caches/system/cpu/cpu6/node0 | 1 + .../linux-caches/system/cpu/cpu7/node0 | 1 + .../system/cpu/cpu0/node0 | 1 + .../linux-resctrl/system/cpu/cpu0/node0 | 1 + .../linux-resctrl/system/cpu/cpu1/node0 | 1 + .../linux-resctrl/system/cpu/cpu10/node1 | 1 + .../linux-resctrl/system/cpu/cpu11/node1 | 1 + .../linux-resctrl/system/cpu/cpu2/node0 | 1 + .../linux-resctrl/system/cpu/cpu3/node0 | 1 + .../linux-resctrl/system/cpu/cpu4/node0 | 1 + .../linux-resctrl/system/cpu/cpu5/node0 | 1 + .../linux-resctrl/system/cpu/cpu6/node1 | 1 + .../linux-resctrl/system/cpu/cpu7/node1 | 1 + .../linux-resctrl/system/cpu/cpu8/node1 | 1 + .../linux-resctrl/system/cpu/cpu9/node1 | 1 + tests/virnumamock.c | 42 +++++++++++++++++++ 39 files changed, 80 insertions(+), 1 deletion(-) create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu1/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu10/node2 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu11/node2 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu12/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu13/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu14/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu15/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu2/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu3/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu4/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu5/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu6/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu7/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu8/node2 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu9/node2 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu1/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu2/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu3/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu4/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu5/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu6/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu7/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl-skx-twocaches/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu1/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu10/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu11/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu2/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu3/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu4/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu5/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu6/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu7/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu8/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu9/node1 diff --git a/src/util/virnuma.h b/src/util/virnuma.h index 67e699f2cf..21b3efee6d 100644 --- a/src/util/virnuma.h +++ b/src/util/virnuma.h @@ -45,7 +45,7 @@ int virNumaGetNodeMemory(int node, unsigned int virNumaGetMaxCPUs(void) G_NO_INLINE; -int virNumaGetNodeOfCPU(int cpu); +int virNumaGetNodeOfCPU(int cpu) G_NO_INLINE; int virNumaGetNodeCPUs(int node, virBitmap **cpus) G_NO_INLINE; int virNumaCPUSetToNodeset(virBitmap **nodeset, virBitmap *cpuset); diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu0/node0 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu0/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu0/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu1/node0 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu1/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu1/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu10/node2 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu10/node2 new file mode 120000 index 0000000000..e04af16eeb --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu10/node2 @@ -0,0 +1 @@ +../../node/node2 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu11/node2 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu11/node2 new file mode 120000 index 0000000000..e04af16eeb --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu11/node2 @@ -0,0 +1 @@ +../../node/node2 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu12/node3 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu12/node3 new file mode 120000 index 0000000000..f213d662fe --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu12/node3 @@ -0,0 +1 @@ +../../node/node3 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu13/node3 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu13/node3 new file mode 120000 index 0000000000..f213d662fe --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu13/node3 @@ -0,0 +1 @@ +../../node/node3 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu14/node3 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu14/node3 new file mode 120000 index 0000000000..f213d662fe --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu14/node3 @@ -0,0 +1 @@ +../../node/node3 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu15/node3 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu15/node3 new file mode 120000 index 0000000000..f213d662fe --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu15/node3 @@ -0,0 +1 @@ +../../node/node3 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu2/node0 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu2/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu2/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu3/node0 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu3/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu3/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu4/node1 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu4/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu4/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu5/node1 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu5/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu5/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu6/node1 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu6/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu6/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu7/node1 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu7/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu7/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu8/node2 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu8/node2 new file mode 120000 index 0000000000..e04af16eeb --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu8/node2 @@ -0,0 +1 @@ +../../node/node2 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu9/node2 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu9/node2 new file mode 120000 index 0000000000..e04af16eeb --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu9/node2 @@ -0,0 +1 @@ +../../node/node2 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu0/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu0/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu0/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu1/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu1/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu1/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu2/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu2/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu2/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu3/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu3/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu3/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu4/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu4/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu4/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu5/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu5/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu5/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu6/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu6/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu6/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu7/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu7/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu7/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl-skx-twocaches/system/cpu/cpu0/node0 b/tests/vircaps2xmldata/linux-resctrl-skx-twocaches/system/cpu/cpu0/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl-skx-twocaches/system/cpu/cpu0/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu0/node0 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu0/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu0/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu1/node0 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu1/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu1/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu10/node1 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu10/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu10/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu11/node1 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu11/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu11/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu2/node0 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu2/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu2/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu3/node0 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu3/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu3/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu4/node0 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu4/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu4/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu5/node0 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu5/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu5/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu6/node1 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu6/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu6/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu7/node1 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu7/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu7/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu8/node1 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu8/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu8/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu9/node1 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu9/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu9/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/virnumamock.c b/tests/virnumamock.c index 87c9a58c6f..8d5c862fa2 100644 --- a/tests/virnumamock.c +++ b/tests/virnumamock.c @@ -21,6 +21,7 @@ #include "internal.h" #include "virnuma.h" #include "virfile.h" +#include "virstring.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -171,3 +172,44 @@ virNumaGetNodeCPUs(int node, virBitmap **cpus) return virBitmapCountBits(*cpus); } + +int +virNumaGetNodeOfCPU(int cpu) +{ + g_autoptr(DIR) cpuDir = NULL; + g_autofree char *sysfs_cpu_path = NULL; + struct dirent *ent = NULL; + int dirErr = 0; + + sysfs_cpu_path = g_strdup_printf("%s/cpu/cpu%d", SYSFS_SYSTEM_PATH, cpu); + + if (virDirOpen(&cpuDir, sysfs_cpu_path) < 0) + return -1; + + while ((dirErr = virDirRead(cpuDir, &ent, sysfs_cpu_path)) > 0) { + g_autofree char *entPath = NULL; + const char *number = NULL; + int node; + + if (!(number = STRSKIP(ent->d_name, "node"))) + continue; + + entPath = g_strdup_printf("%s/%s", sysfs_cpu_path, ent->d_name); + + if (!virFileIsLink(entPath)) + continue; + + if (virStrToLong_i(number, NULL, 10, &node) < 0) { + errno = EINVAL; + return -1; + } + + return node; + } + + if (dirErr < 0) + return -1; + + errno = EINVAL; + return -1; +} -- 2.39.2

On Wed, Mar 8, 2023 at 12:16 PM Michal Privoznik <mprivozn@redhat.com> wrote:
Introduce a mock of virNumaGetNodeOfCPU() because soon we will need virNumaCPUSetToNodeset() to return predictable results. Also, fill in missing symlinks in vircaps2xmldata/.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/virnuma.h | 2 +- .../linux-basic/system/cpu/cpu0/node0 | 1 + .../linux-basic/system/cpu/cpu1/node0 | 1 + .../linux-basic/system/cpu/cpu10/node2 | 1 + .../linux-basic/system/cpu/cpu11/node2 | 1 + .../linux-basic/system/cpu/cpu12/node3 | 1 + .../linux-basic/system/cpu/cpu13/node3 | 1 + .../linux-basic/system/cpu/cpu14/node3 | 1 + .../linux-basic/system/cpu/cpu15/node3 | 1 + .../linux-basic/system/cpu/cpu2/node0 | 1 + .../linux-basic/system/cpu/cpu3/node0 | 1 + .../linux-basic/system/cpu/cpu4/node1 | 1 + .../linux-basic/system/cpu/cpu5/node1 | 1 + .../linux-basic/system/cpu/cpu6/node1 | 1 + .../linux-basic/system/cpu/cpu7/node1 | 1 + .../linux-basic/system/cpu/cpu8/node2 | 1 + .../linux-basic/system/cpu/cpu9/node2 | 1 + .../linux-caches/system/cpu/cpu0/node0 | 1 + .../linux-caches/system/cpu/cpu1/node0 | 1 + .../linux-caches/system/cpu/cpu2/node0 | 1 + .../linux-caches/system/cpu/cpu3/node0 | 1 + .../linux-caches/system/cpu/cpu4/node0 | 1 + .../linux-caches/system/cpu/cpu5/node0 | 1 + .../linux-caches/system/cpu/cpu6/node0 | 1 + .../linux-caches/system/cpu/cpu7/node0 | 1 + .../system/cpu/cpu0/node0 | 1 + .../linux-resctrl/system/cpu/cpu0/node0 | 1 + .../linux-resctrl/system/cpu/cpu1/node0 | 1 + .../linux-resctrl/system/cpu/cpu10/node1 | 1 + .../linux-resctrl/system/cpu/cpu11/node1 | 1 + .../linux-resctrl/system/cpu/cpu2/node0 | 1 + .../linux-resctrl/system/cpu/cpu3/node0 | 1 + .../linux-resctrl/system/cpu/cpu4/node0 | 1 + .../linux-resctrl/system/cpu/cpu5/node0 | 1 + .../linux-resctrl/system/cpu/cpu6/node1 | 1 + .../linux-resctrl/system/cpu/cpu7/node1 | 1 + .../linux-resctrl/system/cpu/cpu8/node1 | 1 + .../linux-resctrl/system/cpu/cpu9/node1 | 1 + tests/virnumamock.c | 42 +++++++++++++++++++ 39 files changed, 80 insertions(+), 1 deletion(-) create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu1/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu10/node2 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu11/node2 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu12/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu13/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu14/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu15/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu2/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu3/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu4/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu5/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu6/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu7/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu8/node2 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu9/node2 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu1/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu2/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu3/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu4/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu5/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu6/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu7/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl-skx-twocaches/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu1/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu10/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu11/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu2/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu3/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu4/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu5/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu6/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu7/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu8/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu9/node1
diff --git a/src/util/virnuma.h b/src/util/virnuma.h index 67e699f2cf..21b3efee6d 100644 --- a/src/util/virnuma.h +++ b/src/util/virnuma.h @@ -45,7 +45,7 @@ int virNumaGetNodeMemory(int node,
unsigned int virNumaGetMaxCPUs(void) G_NO_INLINE;
-int virNumaGetNodeOfCPU(int cpu); +int virNumaGetNodeOfCPU(int cpu) G_NO_INLINE; int virNumaGetNodeCPUs(int node, virBitmap **cpus) G_NO_INLINE; int virNumaCPUSetToNodeset(virBitmap **nodeset, virBitmap *cpuset); diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu0/node0 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu0/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu0/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu1/node0 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu1/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu1/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu10/node2 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu10/node2 new file mode 120000 index 0000000000..e04af16eeb --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu10/node2 @@ -0,0 +1 @@ +../../node/node2 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu11/node2 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu11/node2 new file mode 120000 index 0000000000..e04af16eeb --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu11/node2 @@ -0,0 +1 @@ +../../node/node2 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu12/node3 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu12/node3 new file mode 120000 index 0000000000..f213d662fe --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu12/node3 @@ -0,0 +1 @@ +../../node/node3 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu13/node3 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu13/node3 new file mode 120000 index 0000000000..f213d662fe --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu13/node3 @@ -0,0 +1 @@ +../../node/node3 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu14/node3 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu14/node3 new file mode 120000 index 0000000000..f213d662fe --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu14/node3 @@ -0,0 +1 @@ +../../node/node3 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu15/node3 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu15/node3 new file mode 120000 index 0000000000..f213d662fe --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu15/node3 @@ -0,0 +1 @@ +../../node/node3 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu2/node0 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu2/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu2/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu3/node0 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu3/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu3/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu4/node1 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu4/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu4/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu5/node1 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu5/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu5/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu6/node1 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu6/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu6/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu7/node1 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu7/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu7/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu8/node2 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu8/node2 new file mode 120000 index 0000000000..e04af16eeb --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu8/node2 @@ -0,0 +1 @@ +../../node/node2 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-basic/system/cpu/cpu9/node2 b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu9/node2 new file mode 120000 index 0000000000..e04af16eeb --- /dev/null +++ b/tests/vircaps2xmldata/linux-basic/system/cpu/cpu9/node2 @@ -0,0 +1 @@ +../../node/node2 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu0/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu0/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu0/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu1/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu1/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu1/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu2/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu2/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu2/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu3/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu3/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu3/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu4/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu4/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu4/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu5/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu5/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu5/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu6/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu6/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu6/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-caches/system/cpu/cpu7/node0 b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu7/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-caches/system/cpu/cpu7/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl-skx-twocaches/system/cpu/cpu0/node0 b/tests/vircaps2xmldata/linux-resctrl-skx-twocaches/system/cpu/cpu0/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl-skx-twocaches/system/cpu/cpu0/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu0/node0 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu0/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu0/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu1/node0 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu1/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu1/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu10/node1 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu10/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu10/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu11/node1 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu11/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu11/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu2/node0 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu2/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu2/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu3/node0 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu3/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu3/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu4/node0 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu4/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu4/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu5/node0 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu5/node0 new file mode 120000 index 0000000000..222b6af326 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu5/node0 @@ -0,0 +1 @@ +../../node/node0 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu6/node1 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu6/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu6/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu7/node1 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu7/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu7/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu8/node1 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu8/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu8/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu9/node1 b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu9/node1 new file mode 120000 index 0000000000..1f9c101cd1 --- /dev/null +++ b/tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu9/node1 @@ -0,0 +1 @@ +../../node/node1 \ No newline at end of file diff --git a/tests/virnumamock.c b/tests/virnumamock.c index 87c9a58c6f..8d5c862fa2 100644 --- a/tests/virnumamock.c +++ b/tests/virnumamock.c @@ -21,6 +21,7 @@ #include "internal.h" #include "virnuma.h" #include "virfile.h" +#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_NONE
@@ -171,3 +172,44 @@ virNumaGetNodeCPUs(int node, virBitmap **cpus)
return virBitmapCountBits(*cpus); } + +int +virNumaGetNodeOfCPU(int cpu) +{ + g_autoptr(DIR) cpuDir = NULL; + g_autofree char *sysfs_cpu_path = NULL; + struct dirent *ent = NULL; + int dirErr = 0;
I would prefer naming this variable as 'rc', but that's just my preference.
+ + sysfs_cpu_path = g_strdup_printf("%s/cpu/cpu%d", SYSFS_SYSTEM_PATH, cpu); + + if (virDirOpen(&cpuDir, sysfs_cpu_path) < 0) + return -1; + + while ((dirErr = virDirRead(cpuDir, &ent, sysfs_cpu_path)) > 0) { + g_autofree char *entPath = NULL; + const char *number = NULL; + int node; + + if (!(number = STRSKIP(ent->d_name, "node"))) + continue; + + entPath = g_strdup_printf("%s/%s", sysfs_cpu_path, ent->d_name); + + if (!virFileIsLink(entPath)) + continue; + + if (virStrToLong_i(number, NULL, 10, &node) < 0) { + errno = EINVAL; + return -1; + } + + return node; + } + + if (dirErr < 0) + return -1; + + errno = EINVAL; + return -1; +} -- 2.39.2
Reviewed-by: Kristina Hanicova <khanicov@redhat.com> Kristina

On Wed, Mar 08, 2023 at 12:14:30PM +0100, Michal Privoznik wrote:
Introduce a mock of virNumaGetNodeOfCPU() because soon we will need virNumaCPUSetToNodeset() to return predictable results. Also, fill in missing symlinks in vircaps2xmldata/.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/virnuma.h | 2 +- .../linux-basic/system/cpu/cpu0/node0 | 1 + .../linux-basic/system/cpu/cpu1/node0 | 1 + .../linux-basic/system/cpu/cpu10/node2 | 1 + .../linux-basic/system/cpu/cpu11/node2 | 1 + .../linux-basic/system/cpu/cpu12/node3 | 1 + .../linux-basic/system/cpu/cpu13/node3 | 1 + .../linux-basic/system/cpu/cpu14/node3 | 1 + .../linux-basic/system/cpu/cpu15/node3 | 1 + .../linux-basic/system/cpu/cpu2/node0 | 1 + .../linux-basic/system/cpu/cpu3/node0 | 1 + .../linux-basic/system/cpu/cpu4/node1 | 1 + .../linux-basic/system/cpu/cpu5/node1 | 1 + .../linux-basic/system/cpu/cpu6/node1 | 1 + .../linux-basic/system/cpu/cpu7/node1 | 1 + .../linux-basic/system/cpu/cpu8/node2 | 1 + .../linux-basic/system/cpu/cpu9/node2 | 1 + .../linux-caches/system/cpu/cpu0/node0 | 1 + .../linux-caches/system/cpu/cpu1/node0 | 1 + .../linux-caches/system/cpu/cpu2/node0 | 1 + .../linux-caches/system/cpu/cpu3/node0 | 1 + .../linux-caches/system/cpu/cpu4/node0 | 1 + .../linux-caches/system/cpu/cpu5/node0 | 1 + .../linux-caches/system/cpu/cpu6/node0 | 1 + .../linux-caches/system/cpu/cpu7/node0 | 1 + .../system/cpu/cpu0/node0 | 1 + .../linux-resctrl/system/cpu/cpu0/node0 | 1 + .../linux-resctrl/system/cpu/cpu1/node0 | 1 + .../linux-resctrl/system/cpu/cpu10/node1 | 1 + .../linux-resctrl/system/cpu/cpu11/node1 | 1 + .../linux-resctrl/system/cpu/cpu2/node0 | 1 + .../linux-resctrl/system/cpu/cpu3/node0 | 1 + .../linux-resctrl/system/cpu/cpu4/node0 | 1 + .../linux-resctrl/system/cpu/cpu5/node0 | 1 + .../linux-resctrl/system/cpu/cpu6/node1 | 1 + .../linux-resctrl/system/cpu/cpu7/node1 | 1 + .../linux-resctrl/system/cpu/cpu8/node1 | 1 + .../linux-resctrl/system/cpu/cpu9/node1 | 1 + tests/virnumamock.c | 42 +++++++++++++++++++ 39 files changed, 80 insertions(+), 1 deletion(-) create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu1/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu10/node2 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu11/node2 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu12/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu13/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu14/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu15/node3 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu2/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu3/node0 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu4/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu5/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu6/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu7/node1 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu8/node2 create mode 120000 tests/vircaps2xmldata/linux-basic/system/cpu/cpu9/node2 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu1/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu2/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu3/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu4/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu5/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu6/node0 create mode 120000 tests/vircaps2xmldata/linux-caches/system/cpu/cpu7/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl-skx-twocaches/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu0/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu1/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu10/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu11/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu2/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu3/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu4/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu5/node0 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu6/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu7/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu8/node1 create mode 120000 tests/vircaps2xmldata/linux-resctrl/system/cpu/cpu9/node1
Reviewed-by: Andrea Bolognani <abologna@redhat.com> -- Andrea Bolognani / Red Hat / Virtualization

While no part of cmd line building process currently depends on a host NUMA configuration, this will change soon. Use freshly changed virnumamock from qemuxml2argvtest and make the mock read NUMA data from vircaps2xmldata which seems to have the most rich NUMA configuration. This also means, we have to start building virnumamock unconditionally. But this is not a problem, since nothing inside of the mock relies on Linux specificity. The whole mock is merely just reading files and parsing them. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tests/meson.build | 2 +- tests/qemuxml2argvtest.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/meson.build b/tests/meson.build index 15b049c6ac..44a04698cf 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -88,13 +88,13 @@ mock_libs = [ { 'name': 'virportallocatormock' }, { 'name': 'virprocessmock' }, { 'name': 'virrandommock' }, + { 'name': 'virnumamock' }, ] if host_machine.system() == 'linux' mock_libs += [ { 'name': 'virfilemock' }, { 'name': 'virnetdevbandwidthmock' }, - { 'name': 'virnumamock' }, { 'name': 'virtestmock' }, { 'name': 'virusbmock' }, ] diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 740d7a5db5..8bc0b5147f 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -830,6 +830,8 @@ mymain(void) linuxCaps = driver.caps; macOSCaps = testQemuCapsInitMacOS(); + virFileWrapperAddPrefix("/sys/devices/system", + abs_srcdir "/vircaps2xmldata/linux-basic/system"); virFileWrapperAddPrefix(SYSCONFDIR "/qemu/firmware", abs_srcdir "/qemufirmwaredata/etc/qemu/firmware"); virFileWrapperAddPrefix(PREFIX "/share/qemu/firmware", @@ -2908,7 +2910,8 @@ VIR_TEST_MAIN_PRELOAD(mymain, VIR_TEST_MOCK("domaincaps"), VIR_TEST_MOCK("virrandom"), VIR_TEST_MOCK("qemucpu"), - VIR_TEST_MOCK("virpci")) + VIR_TEST_MOCK("virpci"), + VIR_TEST_MOCK("virnuma")) #else -- 2.39.2

On Wed, Mar 08, 2023 at 12:14:31PM +0100, Michal Privoznik wrote:
While no part of cmd line building process currently depends on a host NUMA configuration, this will change soon. Use freshly changed virnumamock from qemuxml2argvtest and make the mock read NUMA data from vircaps2xmldata which seems to have the most rich NUMA configuration.
This also means, we have to start building virnumamock unconditionally. But this is not a problem, since nothing inside of the mock relies on Linux specificity. The whole mock is merely just reading files and parsing them.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tests/meson.build | 2 +- tests/qemuxml2argvtest.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/tests/meson.build b/tests/meson.build index 15b049c6ac..44a04698cf 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -88,13 +88,13 @@ mock_libs = [ { 'name': 'virportallocatormock' }, { 'name': 'virprocessmock' }, { 'name': 'virrandommock' }, + { 'name': 'virnumamock' }, ]
Please keep this list sorted. -- Andrea Bolognani / Red Hat / Virtualization

We have couple of qemuxml2argvtest cases where up to 8 NUMA nodes are assumed. These are used to check whether disjoint ranges of host-nodes= is generated properly. Without prejudice to the generality, we can rewrite corresponding XML files to use up to 4 NUMA nodes and still have disjoint ranges. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tests/qemuxml2argvdata/migrate-numa-unaligned.args | 4 ++-- tests/qemuxml2argvdata/migrate-numa-unaligned.xml | 4 ++-- tests/qemuxml2argvdata/numatune-memnode-restrictive-mode.xml | 4 ++-- tests/qemuxml2argvdata/numatune-memnode.args | 4 ++-- tests/qemuxml2argvdata/numatune-memnode.x86_64-5.2.0.args | 4 ++-- tests/qemuxml2argvdata/numatune-memnode.x86_64-latest.args | 4 ++-- tests/qemuxml2argvdata/numatune-memnode.xml | 4 ++-- tests/qemuxml2xmloutdata/numatune-memnode.xml | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/qemuxml2argvdata/migrate-numa-unaligned.args b/tests/qemuxml2argvdata/migrate-numa-unaligned.args index 6e961cba84..04d4903065 100644 --- a/tests/qemuxml2argvdata/migrate-numa-unaligned.args +++ b/tests/qemuxml2argvdata/migrate-numa-unaligned.args @@ -17,9 +17,9 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest/.config \ -smp 32,sockets=32,cores=1,threads=1 \ -object memory-backend-ram,id=ram-node0,size=20482048,host-nodes=3,policy=preferred \ -numa node,nodeid=0,cpus=0,memdev=ram-node0 \ --object memory-backend-ram,id=ram-node1,size=675907584,host-nodes=0-7,policy=bind \ +-object memory-backend-ram,id=ram-node1,size=675907584,host-nodes=0-3,policy=bind \ -numa node,nodeid=1,cpus=1-27,cpus=29,memdev=ram-node1 \ --object memory-backend-ram,id=ram-node2,size=24578457600,host-nodes=1-2,host-nodes=5,host-nodes=7,policy=bind \ +-object memory-backend-ram,id=ram-node2,size=24578457600,host-nodes=0,host-nodes=2,policy=bind \ -numa node,nodeid=2,cpus=28,cpus=30-31,memdev=ram-node2 \ -uuid 9f4b6512-e73a-4a25-93e8-5307802821ce \ -display none \ diff --git a/tests/qemuxml2argvdata/migrate-numa-unaligned.xml b/tests/qemuxml2argvdata/migrate-numa-unaligned.xml index e46b723acb..c060852297 100644 --- a/tests/qemuxml2argvdata/migrate-numa-unaligned.xml +++ b/tests/qemuxml2argvdata/migrate-numa-unaligned.xml @@ -6,8 +6,8 @@ <vcpu placement='static'>32</vcpu> <numatune> <memnode cellid='0' mode='preferred' nodeset='3'/> - <memory mode='strict' nodeset='0-7'/> - <memnode cellid='2' mode='strict' nodeset='1-2,5-7,^6'/> + <memory mode='strict' nodeset='0-3'/> + <memnode cellid='2' mode='strict' nodeset='0-2,^1'/> </numatune> <os> <type arch='x86_64' machine='pc'>hvm</type> diff --git a/tests/qemuxml2argvdata/numatune-memnode-restrictive-mode.xml b/tests/qemuxml2argvdata/numatune-memnode-restrictive-mode.xml index 012c526460..2a640f5501 100644 --- a/tests/qemuxml2argvdata/numatune-memnode-restrictive-mode.xml +++ b/tests/qemuxml2argvdata/numatune-memnode-restrictive-mode.xml @@ -5,9 +5,9 @@ <currentMemory unit='KiB'>24682468</currentMemory> <vcpu placement='static'>32</vcpu> <numatune> - <memory mode='restrictive' nodeset='0-7'/> + <memory mode='restrictive' nodeset='0-3'/> <memnode cellid='0' mode='restrictive' nodeset='3'/> - <memnode cellid='2' mode='restrictive' nodeset='1-2,5,7'/> + <memnode cellid='2' mode='restrictive' nodeset='1-2'/> </numatune> <os> <type arch='x86_64' machine='pc'>hvm</type> diff --git a/tests/qemuxml2argvdata/numatune-memnode.args b/tests/qemuxml2argvdata/numatune-memnode.args index ab222f53db..917746a523 100644 --- a/tests/qemuxml2argvdata/numatune-memnode.args +++ b/tests/qemuxml2argvdata/numatune-memnode.args @@ -17,9 +17,9 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest/.config \ -smp 32,sockets=32,cores=1,threads=1 \ -object memory-backend-ram,id=ram-node0,size=20971520,host-nodes=3,policy=preferred \ -numa node,nodeid=0,cpus=0,memdev=ram-node0 \ --object memory-backend-ram,id=ram-node1,size=676331520,host-nodes=0-7,policy=bind \ +-object memory-backend-ram,id=ram-node1,size=676331520,host-nodes=0-3,policy=bind \ -numa node,nodeid=1,cpus=1-27,cpus=29,memdev=ram-node1 \ --object memory-backend-ram,id=ram-node2,size=24578621440,host-nodes=1-2,host-nodes=5,host-nodes=7,policy=bind \ +-object memory-backend-ram,id=ram-node2,size=24578621440,host-nodes=0,host-nodes=2,policy=bind \ -numa node,nodeid=2,cpus=28,cpus=30-31,memdev=ram-node2 \ -uuid 9f4b6512-e73a-4a25-93e8-5307802821ce \ -display none \ diff --git a/tests/qemuxml2argvdata/numatune-memnode.x86_64-5.2.0.args b/tests/qemuxml2argvdata/numatune-memnode.x86_64-5.2.0.args index 0ef1fbfbca..982df0b569 100644 --- a/tests/qemuxml2argvdata/numatune-memnode.x86_64-5.2.0.args +++ b/tests/qemuxml2argvdata/numatune-memnode.x86_64-5.2.0.args @@ -18,9 +18,9 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest/.config \ -smp 32,sockets=32,cores=1,threads=1 \ -object memory-backend-ram,id=ram-node0,size=20971520,host-nodes=3,policy=preferred \ -numa node,nodeid=0,cpus=0,memdev=ram-node0 \ --object memory-backend-ram,id=ram-node1,size=676331520,host-nodes=0-7,policy=bind \ +-object memory-backend-ram,id=ram-node1,size=676331520,host-nodes=0-3,policy=bind \ -numa node,nodeid=1,cpus=1-27,cpus=29,memdev=ram-node1 \ --object memory-backend-ram,id=ram-node2,size=24578621440,host-nodes=1-2,host-nodes=5,host-nodes=7,policy=bind \ +-object memory-backend-ram,id=ram-node2,size=24578621440,host-nodes=0,host-nodes=2,policy=bind \ -numa node,nodeid=2,cpus=28,cpus=30-31,memdev=ram-node2 \ -uuid 9f4b6512-e73a-4a25-93e8-5307802821ce \ -display none \ diff --git a/tests/qemuxml2argvdata/numatune-memnode.x86_64-latest.args b/tests/qemuxml2argvdata/numatune-memnode.x86_64-latest.args index 684586b404..087ddf8629 100644 --- a/tests/qemuxml2argvdata/numatune-memnode.x86_64-latest.args +++ b/tests/qemuxml2argvdata/numatune-memnode.x86_64-latest.args @@ -18,9 +18,9 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest/.config \ -smp 32,sockets=32,cores=1,threads=1 \ -object '{"qom-type":"memory-backend-ram","id":"ram-node0","size":20971520,"host-nodes":[3],"policy":"preferred"}' \ -numa node,nodeid=0,cpus=0,memdev=ram-node0 \ --object '{"qom-type":"memory-backend-ram","id":"ram-node1","size":676331520,"host-nodes":[0,1,2,3,4,5,6,7],"policy":"bind"}' \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node1","size":676331520,"host-nodes":[0,1,2,3],"policy":"bind"}' \ -numa node,nodeid=1,cpus=1-27,cpus=29,memdev=ram-node1 \ --object '{"qom-type":"memory-backend-ram","id":"ram-node2","size":24578621440,"host-nodes":[1,2,5,7],"policy":"bind"}' \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node2","size":24578621440,"host-nodes":[0,2],"policy":"bind"}' \ -numa node,nodeid=2,cpus=28,cpus=30-31,memdev=ram-node2 \ -uuid 9f4b6512-e73a-4a25-93e8-5307802821ce \ -display none \ diff --git a/tests/qemuxml2argvdata/numatune-memnode.xml b/tests/qemuxml2argvdata/numatune-memnode.xml index dd653c5d3b..9640eeb945 100644 --- a/tests/qemuxml2argvdata/numatune-memnode.xml +++ b/tests/qemuxml2argvdata/numatune-memnode.xml @@ -6,8 +6,8 @@ <vcpu placement='static'>32</vcpu> <numatune> <memnode cellid='0' mode='preferred' nodeset='3'/> - <memory mode='strict' nodeset='0-7'/> - <memnode cellid='2' mode='strict' nodeset='1-2,5-7,^6'/> + <memory mode='strict' nodeset='0-3'/> + <memnode cellid='2' mode='strict' nodeset='0-2,^1'/> </numatune> <os> <type arch='x86_64' machine='pc'>hvm</type> diff --git a/tests/qemuxml2xmloutdata/numatune-memnode.xml b/tests/qemuxml2xmloutdata/numatune-memnode.xml index 104d2e6d4c..a117745bfb 100644 --- a/tests/qemuxml2xmloutdata/numatune-memnode.xml +++ b/tests/qemuxml2xmloutdata/numatune-memnode.xml @@ -5,9 +5,9 @@ <currentMemory unit='KiB'>24682468</currentMemory> <vcpu placement='static'>32</vcpu> <numatune> - <memory mode='strict' nodeset='0-7'/> + <memory mode='strict' nodeset='0-3'/> <memnode cellid='0' mode='preferred' nodeset='3'/> - <memnode cellid='2' mode='strict' nodeset='1-2,5,7'/> + <memnode cellid='2' mode='strict' nodeset='0,2'/> </numatune> <os> <type arch='x86_64' machine='pc'>hvm</type> -- 2.39.2

On Wed, Mar 08, 2023 at 12:14:32PM +0100, Michal Privoznik wrote:
We have couple of qemuxml2argvtest cases where up to 8 NUMA nodes are assumed. These are used to check whether disjoint ranges of host-nodes= is generated properly. Without prejudice to the generality, we can rewrite corresponding XML files to use up to 4 NUMA nodes and still have disjoint ranges.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tests/qemuxml2argvdata/migrate-numa-unaligned.args | 4 ++-- tests/qemuxml2argvdata/migrate-numa-unaligned.xml | 4 ++-- tests/qemuxml2argvdata/numatune-memnode-restrictive-mode.xml | 4 ++-- tests/qemuxml2argvdata/numatune-memnode.args | 4 ++-- tests/qemuxml2argvdata/numatune-memnode.x86_64-5.2.0.args | 4 ++-- tests/qemuxml2argvdata/numatune-memnode.x86_64-latest.args | 4 ++-- tests/qemuxml2argvdata/numatune-memnode.xml | 4 ++-- tests/qemuxml2xmloutdata/numatune-memnode.xml | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-)
Reviewed-by: Andrea Bolognani <abologna@redhat.com> -- Andrea Bolognani / Red Hat / Virtualization

So far, the memory-hotplug-dimm-addr.xml test case pins its vCPUs onto CPUs 0-1 which correspond to NUMA node #0 (per tests/vircaps2xmldata/linux-basic/system/node/node0). Place vCPUs onto nodes #1 and #2 too so that DIMM <memory/> device can continue using thread-context after future patches. This configuration, as-is currently, would make QEMU error out anyway. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tests/qemuxml2argvdata/memory-hotplug-dimm-addr.xml | 2 +- .../memory-hotplug-dimm-addr.x86_64-latest.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qemuxml2argvdata/memory-hotplug-dimm-addr.xml b/tests/qemuxml2argvdata/memory-hotplug-dimm-addr.xml index 92ea679bbe..47486dda0c 100644 --- a/tests/qemuxml2argvdata/memory-hotplug-dimm-addr.xml +++ b/tests/qemuxml2argvdata/memory-hotplug-dimm-addr.xml @@ -4,7 +4,7 @@ <maxMemory slots='16' unit='KiB'>1099511627776</maxMemory> <memory unit='KiB'>7434230</memory> <currentMemory unit='KiB'>7434230</currentMemory> - <vcpu placement='static' cpuset='0-1'>2</vcpu> + <vcpu placement='static' cpuset='0-1,4-5,9'>2</vcpu> <os> <type arch='i686' machine='pc'>hvm</type> <boot dev='hd'/> diff --git a/tests/qemuxml2xmloutdata/memory-hotplug-dimm-addr.x86_64-latest.xml b/tests/qemuxml2xmloutdata/memory-hotplug-dimm-addr.x86_64-latest.xml index ef671fcfa3..0a32d5491a 100644 --- a/tests/qemuxml2xmloutdata/memory-hotplug-dimm-addr.x86_64-latest.xml +++ b/tests/qemuxml2xmloutdata/memory-hotplug-dimm-addr.x86_64-latest.xml @@ -4,7 +4,7 @@ <maxMemory slots='16' unit='KiB'>1099511627776</maxMemory> <memory unit='KiB'>7434230</memory> <currentMemory unit='KiB'>7434230</currentMemory> - <vcpu placement='static' cpuset='0-1'>2</vcpu> + <vcpu placement='static' cpuset='0-1,4-5,9'>2</vcpu> <os> <type arch='i686' machine='pc'>hvm</type> <boot dev='hd'/> -- 2.39.2

On Wed, Mar 08, 2023 at 12:14:33PM +0100, Michal Privoznik wrote:
So far, the memory-hotplug-dimm-addr.xml test case pins its vCPUs onto CPUs 0-1 which correspond to NUMA node #0 (per tests/vircaps2xmldata/linux-basic/system/node/node0). Place vCPUs onto nodes #1 and #2 too so that DIMM <memory/> device can continue using thread-context after future patches. This configuration, as-is currently, would make QEMU error out anyway.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tests/qemuxml2argvdata/memory-hotplug-dimm-addr.xml | 2 +- .../memory-hotplug-dimm-addr.x86_64-latest.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Andrea Bolognani <abologna@redhat.com> -- Andrea Bolognani / Red Hat / Virtualization

Since qemuxml2argvtest is now using virnumamock, there's no need for qemuxml2argvmock to offer reimplementation of virNuma*() functions. Also, the comment about CLang and FreeBSD (introduced in v4.3.0-40-g77ac204d14) is no longer true. Looks like noinline attribute was the missing culprit. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/virnuma.h | 2 +- ...-unavailable-restrictive.x86_64-latest.err | 2 +- ...mnode-unavailable-strict.x86_64-latest.err | 2 +- ...umatune-static-nodeset-exceed-hostnode.err | 2 +- tests/qemuxml2argvmock.c | 41 ------------------- 5 files changed, 4 insertions(+), 45 deletions(-) diff --git a/src/util/virnuma.h b/src/util/virnuma.h index 21b3efee6d..f131017f85 100644 --- a/src/util/virnuma.h +++ b/src/util/virnuma.h @@ -32,7 +32,7 @@ int virNumaSetupMemoryPolicy(virDomainNumatuneMemMode mode, virBitmap *nodeset); virBitmap *virNumaGetHostMemoryNodeset(void); -bool virNumaNodesetIsAvailable(virBitmap *nodeset) G_NO_INLINE; +bool virNumaNodesetIsAvailable(virBitmap *nodeset); bool virNumaIsAvailable(void) G_NO_INLINE; int virNumaGetMaxNode(void) G_NO_INLINE; bool virNumaNodeIsAvailable(int node) G_NO_INLINE; diff --git a/tests/qemuxml2argvdata/numatune-memnode-unavailable-restrictive.x86_64-latest.err b/tests/qemuxml2argvdata/numatune-memnode-unavailable-restrictive.x86_64-latest.err index a826c3cdeb..f872dd7e92 100644 --- a/tests/qemuxml2argvdata/numatune-memnode-unavailable-restrictive.x86_64-latest.err +++ b/tests/qemuxml2argvdata/numatune-memnode-unavailable-restrictive.x86_64-latest.err @@ -1 +1 @@ -internal error: Mock: no numa node set is available at bit 999 +unsupported configuration: NUMA node 999 is unavailable diff --git a/tests/qemuxml2argvdata/numatune-memnode-unavailable-strict.x86_64-latest.err b/tests/qemuxml2argvdata/numatune-memnode-unavailable-strict.x86_64-latest.err index a826c3cdeb..f872dd7e92 100644 --- a/tests/qemuxml2argvdata/numatune-memnode-unavailable-strict.x86_64-latest.err +++ b/tests/qemuxml2argvdata/numatune-memnode-unavailable-strict.x86_64-latest.err @@ -1 +1 @@ -internal error: Mock: no numa node set is available at bit 999 +unsupported configuration: NUMA node 999 is unavailable diff --git a/tests/qemuxml2argvdata/numatune-static-nodeset-exceed-hostnode.err b/tests/qemuxml2argvdata/numatune-static-nodeset-exceed-hostnode.err index b6b98775ee..2a33ccd791 100644 --- a/tests/qemuxml2argvdata/numatune-static-nodeset-exceed-hostnode.err +++ b/tests/qemuxml2argvdata/numatune-static-nodeset-exceed-hostnode.err @@ -1 +1 @@ -internal error: Mock: no numa node set is available at bit 8 +unsupported configuration: NUMA node 4 is unavailable diff --git a/tests/qemuxml2argvmock.c b/tests/qemuxml2argvmock.c index 85bd76c315..7169e4ca3a 100644 --- a/tests/qemuxml2argvmock.c +++ b/tests/qemuxml2argvmock.c @@ -56,47 +56,6 @@ GDateTime *g_date_time_new_now_local(void) return g_date_time_new_from_unix_local(1234567890); } -bool -virNumaIsAvailable(void) -{ - return true; -} - -int -virNumaGetMaxNode(void) -{ - return 7; -} - -/* We shouldn't need to mock virNumaNodeIsAvailable() and *definitely* not - * virNumaNodesetIsAvailable(), but it seems to be the only way to get - * mocking to work with Clang on FreeBSD, so keep these duplicates around - * until we figure out a cleaner solution */ -bool -virNumaNodeIsAvailable(int node) -{ - return node >= 0 && node <= virNumaGetMaxNode(); -} - -bool -virNumaNodesetIsAvailable(virBitmap *nodeset) -{ - ssize_t bit = -1; - - if (!nodeset) - return true; - - while ((bit = virBitmapNextSetBit(nodeset, bit)) >= 0) { - if (virNumaNodeIsAvailable(bit)) - continue; - - virReportError(VIR_ERR_INTERNAL_ERROR, - "Mock: no numa node set is available at bit %zd", bit); - return false; - } - - return true; -} char * virTPMCreateCancelPath(const char *devpath) -- 2.39.2

On Wed, Mar 8, 2023 at 12:17 PM Michal Privoznik <mprivozn@redhat.com> wrote:
Since qemuxml2argvtest is now using virnumamock, there's no need for qemuxml2argvmock to offer reimplementation of virNuma*() functions. Also, the comment about CLang and FreeBSD (introduced in v4.3.0-40-g77ac204d14) is no longer true. Looks like noinline attribute was the missing culprit.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/virnuma.h | 2 +- ...-unavailable-restrictive.x86_64-latest.err | 2 +- ...mnode-unavailable-strict.x86_64-latest.err | 2 +- ...umatune-static-nodeset-exceed-hostnode.err | 2 +- tests/qemuxml2argvmock.c | 41 ------------------- 5 files changed, 4 insertions(+), 45 deletions(-)
I think you can also drop include of virnuma.h in tests/qemuxml2argvmock.c Reviewed-by: Kristina Hanicova <khanicov@redhat.com> Kristina

On Wed, Mar 08, 2023 at 12:14:34PM +0100, Michal Privoznik wrote:
Since qemuxml2argvtest is now using virnumamock, there's no need for qemuxml2argvmock to offer reimplementation of virNuma*() functions. Also, the comment about CLang and FreeBSD (introduced in v4.3.0-40-g77ac204d14) is no longer true. Looks like noinline attribute was the missing culprit.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/virnuma.h | 2 +- ...-unavailable-restrictive.x86_64-latest.err | 2 +- ...mnode-unavailable-strict.x86_64-latest.err | 2 +- ...umatune-static-nodeset-exceed-hostnode.err | 2 +- tests/qemuxml2argvmock.c | 41 ------------------- 5 files changed, 4 insertions(+), 45 deletions(-)
Double spaces in the commit message. Honestly I'm as baffled as to how this works as I was back when I introduced those mocks. The situation after your changes is clearly preferable to the hack that's currently there, so I'm more than happy to see them merged, under the assumption of course that you've already ensured that everything keeps working on non-Linux platforms by running a full GitLab CI pipeline. Reviewed-by: Andrea Bolognani <abologna@redhat.com> -- Andrea Bolognani / Red Hat / Virtualization

The set of if()-s that determines the preference in cpumask used for setting things like emulatorpin, vcpupin, etc. is going to be re-used. Separate it out into a function. You may think that this changes behaviour, but qemuProcessPrepareDomainNUMAPlacement() ensures that priv->autoCpuset is set for VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_domain.c | 18 ++++++++++++++++++ src/qemu/qemu_domain.h | 5 +++++ src/qemu/qemu_process.c | 9 ++------- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index aa567f652a..f99a9614e9 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -12442,3 +12442,21 @@ qemuDomainStartupCleanup(virDomainObj *vm) for (i = 0; i < vm->def->ndisks; i++) qemuDomainCleanupStorageSourceFD(vm->def->disks[i]->src); } + + +virBitmap * +qemuDomainEvaluateCPUMask(const virDomainDef *def, + virBitmap *cpumask, + virBitmap *autoCpuset) +{ + if (cpumask) { + return cpumask; + } else if (autoCpuset && + def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) { + return autoCpuset; + } else if (def->cpumask) { + return def->cpumask; + } + + return NULL; +} diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 550397ee50..5ca5fa416c 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -1132,3 +1132,8 @@ qemuDomainSchedCoreStart(virQEMUDriverConfig *cfg, void qemuDomainSchedCoreStop(qemuDomainObjPrivate *priv); + +virBitmap * +qemuDomainEvaluateCPUMask(const virDomainDef *def, + virBitmap *cpumask, + virBitmap *autoCpuset); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 9a612ca443..2f6378b549 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -2571,13 +2571,8 @@ qemuProcessSetupPid(virDomainObj *vm, } /* Infer which cpumask shall be used. */ - if (cpumask) { - use_cpumask = cpumask; - } else if (vm->def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) { - use_cpumask = priv->autoCpuset; - } else if (vm->def->cpumask) { - use_cpumask = vm->def->cpumask; - } else { + if (!(use_cpumask = qemuDomainEvaluateCPUMask(vm->def, + cpumask, priv->autoCpuset))) { /* You may think this is redundant, but we can't assume libvirtd * itself is running on all pCPUs, so we need to explicitly set * the spawned QEMU instance to all pCPUs if no map is given in -- 2.39.2

On Wed, Mar 08, 2023 at 12:14:35PM +0100, Michal Privoznik wrote:
The set of if()-s that determines the preference in cpumask used for setting things like emulatorpin, vcpupin, etc. is going to be re-used. Separate it out into a function.
You may think that this changes behaviour, but qemuProcessPrepareDomainNUMAPlacement() ensures that priv->autoCpuset is set for VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_domain.c | 18 ++++++++++++++++++ src/qemu/qemu_domain.h | 5 +++++ src/qemu/qemu_process.c | 9 ++------- 3 files changed, 25 insertions(+), 7 deletions(-)
Reviewed-by: Andrea Bolognani <abologna@redhat.com> -- Andrea Bolognani / Red Hat / Virtualization

The order of pinning priority (at least for emulator thread) was set by v1.2.15-rc1~58 (for cgroup code). But later, when automatic placement was implemented into qemuDomainGetEmulatorPinInfo(), the priority was not honored. Now that we have this priority code in a separate function, we can just call that and avoid this type of error. Fixes: 776924e37649f2d47acd805746d5fd9325212ea5 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_driver.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c546e35953..0a6f96e68c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4574,14 +4574,9 @@ qemuDomainGetEmulatorPinInfo(virDomainPtr dom, if (live) autoCpuset = QEMU_DOMAIN_PRIVATE(vm)->autoCpuset; - if (def->cputune.emulatorpin) { - cpumask = def->cputune.emulatorpin; - } else if (def->cpumask) { - cpumask = def->cpumask; - } else if (vm->def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO && - autoCpuset) { - cpumask = autoCpuset; - } else { + if (!(cpumask = qemuDomainEvaluateCPUMask(def, + def->cputune.emulatorpin, + autoCpuset))) { if (!(bitmap = virHostCPUGetAvailableCPUsBitmap())) goto cleanup; cpumask = bitmap; -- 2.39.2

On Wed, Mar 08, 2023 at 12:14:36PM +0100, Michal Privoznik wrote:
The order of pinning priority (at least for emulator thread) was set by v1.2.15-rc1~58 (for cgroup code). But later, when automatic placement was implemented into qemuDomainGetEmulatorPinInfo(), the priority was not honored.
Now that we have this priority code in a separate function, we can just call that and avoid this type of error.
Fixes: 776924e37649f2d47acd805746d5fd9325212ea5 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_driver.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-)
Reviewed-by: Andrea Bolognani <abologna@redhat.com> -- Andrea Bolognani / Red Hat / Virtualization

While it's true that anybody who's interested in getting .host-nodes attribute value can just use virJSONValueObjectGetArray() (and that's exactly what qemuBuildThreadContextProps() is doing, btw), it somebody is interested in getting the actual virBitmap, they would have to parse the JSON array. Instead, introduce an argument to qemuBuildMemoryBackendProps() which is set to corresponding value used when formatting the attribute. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 40 ++++++++++++++++++++++++---------------- src/qemu/qemu_command.h | 4 +++- src/qemu/qemu_hotplug.c | 2 +- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 7adcac418f..1b58171287 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3240,6 +3240,7 @@ qemuBuildMemoryGetPagesize(virQEMUDriverConfig *cfg, * @def: domain definition object * @mem: memory definition object * @force: forcibly use one of the backends + * @nodemaskRet: [out] bitmap used to format .host-nodes attribute * * Creates a configuration object that represents memory backend of given guest * NUMA node (domain @def and @mem). Use @priv->autoNodeset to fine tune the @@ -3264,7 +3265,8 @@ qemuBuildMemoryBackendProps(virJSONValue **backendProps, const virDomainDef *def, const virDomainMemoryDef *mem, bool force, - bool systemMemory) + bool systemMemory, + virBitmap **nodemaskRet) { const char *backendType = "memory-backend-file"; virDomainNumatuneMemMode mode; @@ -3437,19 +3439,24 @@ qemuBuildMemoryBackendProps(virJSONValue **backendProps, return -1; } - /* Make sure the requested nodeset is sensible */ - if (nodemask && !virNumaNodesetIsAvailable(nodemask)) - return -1; - - /* If mode is "restrictive", we should only use cgroups setting allowed memory - * nodes, and skip passing the host-nodes and policy parameters to QEMU command - * line which means we will use system default memory policy. */ - if (nodemask && mode != VIR_DOMAIN_NUMATUNE_MEM_RESTRICTIVE) { - if (virJSONValueObjectAdd(&props, - "m:host-nodes", nodemask, - "S:policy", qemuNumaPolicyTypeToString(mode), - NULL) < 0) + if (nodemask) { + /* Make sure the requested nodeset is sensible */ + if (!virNumaNodesetIsAvailable(nodemask)) return -1; + + /* If mode is "restrictive", we should only use cgroups setting allowed memory + * nodes, and skip passing the host-nodes and policy parameters to QEMU command + * line which means we will use system default memory policy. */ + if (mode != VIR_DOMAIN_NUMATUNE_MEM_RESTRICTIVE) { + if (virJSONValueObjectAdd(&props, + "m:host-nodes", nodemask, + "S:policy", qemuNumaPolicyTypeToString(mode), + NULL) < 0) + return -1; + + if (nodemaskRet) + *nodemaskRet = nodemask; + } } /* If none of the following is requested... */ @@ -3502,7 +3509,8 @@ qemuBuildMemoryCellBackendProps(virDomainDef *def, mem.targetNode = cell; mem.info.alias = alias; - return qemuBuildMemoryBackendProps(props, alias, cfg, priv, def, &mem, false, false); + return qemuBuildMemoryBackendProps(props, alias, cfg, priv, + def, &mem, false, false, NULL); } @@ -3526,7 +3534,7 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd, alias = g_strdup_printf("mem%s", mem->info.alias); if (qemuBuildMemoryBackendProps(&props, alias, cfg, - priv, def, mem, true, false) < 0) + priv, def, mem, true, false, NULL) < 0) return -1; if (qemuBuildThreadContextProps(&tcProps, &props, priv) < 0) @@ -7150,7 +7158,7 @@ qemuBuildMemCommandLineMemoryDefaultBackend(virCommand *cmd, mem.info.alias = (char *) defaultRAMid; if (qemuBuildMemoryBackendProps(&props, defaultRAMid, cfg, - priv, def, &mem, false, true) < 0) + priv, def, &mem, false, true, NULL) < 0) return -1; if (qemuBuildThreadContextProps(&tcProps, &props, priv) < 0) diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index c49096a057..9074822bc5 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -22,6 +22,7 @@ #pragma once #include "domain_conf.h" +#include "virbitmap.h" #include "vircommand.h" #include "virenum.h" #include "qemu_block.h" @@ -140,7 +141,8 @@ int qemuBuildMemoryBackendProps(virJSONValue **backendProps, const virDomainDef *def, const virDomainMemoryDef *mem, bool force, - bool systemMemory); + bool systemMemory, + virBitmap **nodemaskRet); virJSONValue * qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index da17525824..b9f6a031de 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -2280,7 +2280,7 @@ qemuDomainAttachMemory(virQEMUDriver *driver, goto cleanup; if (qemuBuildMemoryBackendProps(&props, objalias, cfg, - priv, vm->def, mem, true, false) < 0) + priv, vm->def, mem, true, false, NULL) < 0) goto cleanup; if (qemuProcessBuildDestroyMemoryPaths(driver, vm, mem, true) < 0) -- 2.39.2

On Wed, Mar 8, 2023 at 12:16 PM Michal Privoznik <mprivozn@redhat.com> wrote:
While it's true that anybody who's interested in getting .host-nodes attribute value can just use virJSONValueObjectGetArray() (and that's exactly what qemuBuildThreadContextProps() is doing, btw), it somebody is
*if
interested in getting the actual virBitmap, they would have to parse the JSON array.
Instead, introduce an argument to qemuBuildMemoryBackendProps() which is set to corresponding value used when formatting the attribute.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 40 ++++++++++++++++++++++++---------------- src/qemu/qemu_command.h | 4 +++- src/qemu/qemu_hotplug.c | 2 +- 3 files changed, 28 insertions(+), 18 deletions(-)
Reviewed-by: Kristina Hanicova <khanicov@redhat.com> Kristina

On Wed, Mar 08, 2023 at 12:14:37PM +0100, Michal Privoznik wrote:
- /* Make sure the requested nodeset is sensible */ - if (nodemask && !virNumaNodesetIsAvailable(nodemask)) - return -1; - - /* If mode is "restrictive", we should only use cgroups setting allowed memory - * nodes, and skip passing the host-nodes and policy parameters to QEMU command - * line which means we will use system default memory policy. */ - if (nodemask && mode != VIR_DOMAIN_NUMATUNE_MEM_RESTRICTIVE) { - if (virJSONValueObjectAdd(&props, - "m:host-nodes", nodemask, - "S:policy", qemuNumaPolicyTypeToString(mode), - NULL) < 0) + if (nodemask) { + /* Make sure the requested nodeset is sensible */ + if (!virNumaNodesetIsAvailable(nodemask)) return -1; + + /* If mode is "restrictive", we should only use cgroups setting allowed memory + * nodes, and skip passing the host-nodes and policy parameters to QEMU command + * line which means we will use system default memory policy. */ + if (mode != VIR_DOMAIN_NUMATUNE_MEM_RESTRICTIVE) { + if (virJSONValueObjectAdd(&props, + "m:host-nodes", nodemask, + "S:policy", qemuNumaPolicyTypeToString(mode), + NULL) < 0) + return -1; + + if (nodemaskRet) + *nodemaskRet = nodemask; + } }
I don't mind the additional nesting, but adding it at the same time as you're making functional changes makes it harder to focus on the latter. Please separate the functional and non-functional parts of this change into two commits. -- Andrea Bolognani / Red Hat / Virtualization

When building a thread-context object (inside of qemuBuildThreadContextProps()) we look at given memory-backend-* object and look for .host-nodes attribute. This works, as long as we need to just copy the attribute value into another thread-context attribute. But soon we will need to adjust it. That's the point where having the value in virBitmap comes handy. Utilize the previous commit, which made qemuBuildMemoryBackendProps() set the argument and pass it into qemuBuildThreadContextProps(). Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 38 +++++++++++++++++++++----------------- src/qemu/qemu_command.h | 3 ++- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 1b58171287..b274ab6ff8 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3496,7 +3496,8 @@ qemuBuildMemoryCellBackendProps(virDomainDef *def, virQEMUDriverConfig *cfg, size_t cell, qemuDomainObjPrivate *priv, - virJSONValue **props) + virJSONValue **props, + virBitmap **nodemask) { g_autofree char *alias = NULL; virDomainMemoryDef mem = { 0 }; @@ -3509,8 +3510,8 @@ qemuBuildMemoryCellBackendProps(virDomainDef *def, mem.targetNode = cell; mem.info.alias = alias; - return qemuBuildMemoryBackendProps(props, alias, cfg, priv, - def, &mem, false, false, NULL); + return qemuBuildMemoryBackendProps(props, alias, cfg, priv, def, + &mem, false, false, nodemask); } @@ -3523,6 +3524,7 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd, { g_autoptr(virJSONValue) props = NULL; g_autoptr(virJSONValue) tcProps = NULL; + virBitmap *nodemask = NULL; g_autofree char *alias = NULL; if (!mem->info.alias) { @@ -3533,11 +3535,11 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd, alias = g_strdup_printf("mem%s", mem->info.alias); - if (qemuBuildMemoryBackendProps(&props, alias, cfg, - priv, def, mem, true, false, NULL) < 0) + if (qemuBuildMemoryBackendProps(&props, alias, cfg, priv, + def, mem, true, false, &nodemask) < 0) return -1; - if (qemuBuildThreadContextProps(&tcProps, &props, priv) < 0) + if (qemuBuildThreadContextProps(&tcProps, &props, priv, nodemask) < 0) return -1; if (tcProps && @@ -3634,11 +3636,10 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg, int qemuBuildThreadContextProps(virJSONValue **tcProps, virJSONValue **memProps, - qemuDomainObjPrivate *priv) + qemuDomainObjPrivate *priv, + virBitmap *nodemask) { g_autoptr(virJSONValue) props = NULL; - virJSONValue *nodemask = NULL; - g_autoptr(virJSONValue) nodemaskCopy = NULL; g_autofree char *tcAlias = NULL; const char *memalias = NULL; bool prealloc = false; @@ -3648,7 +3649,6 @@ qemuBuildThreadContextProps(virJSONValue **tcProps, if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_THREAD_CONTEXT)) return 0; - nodemask = virJSONValueObjectGetArray(*memProps, "host-nodes"); if (!nodemask) return 0; @@ -3664,12 +3664,11 @@ qemuBuildThreadContextProps(virJSONValue **tcProps, } tcAlias = g_strdup_printf("tc-%s", memalias); - nodemaskCopy = virJSONValueCopy(nodemask); if (virJSONValueObjectAdd(&props, "s:qom-type", "thread-context", "s:id", tcAlias, - "a:node-affinity", &nodemaskCopy, + "m:node-affinity", nodemask, NULL) < 0) return -1; @@ -7151,17 +7150,18 @@ qemuBuildMemCommandLineMemoryDefaultBackend(virCommand *cmd, g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(priv->driver); g_autoptr(virJSONValue) props = NULL; g_autoptr(virJSONValue) tcProps = NULL; + virBitmap *nodemask = NULL; virDomainMemoryDef mem = { 0 }; mem.size = virDomainDefGetMemoryInitial(def); mem.targetNode = -1; mem.info.alias = (char *) defaultRAMid; - if (qemuBuildMemoryBackendProps(&props, defaultRAMid, cfg, - priv, def, &mem, false, true, NULL) < 0) + if (qemuBuildMemoryBackendProps(&props, defaultRAMid, cfg, priv, + def, &mem, false, true, &nodemask) < 0) return -1; - if (qemuBuildThreadContextProps(&tcProps, &props, priv) < 0) + if (qemuBuildThreadContextProps(&tcProps, &props, priv, nodemask) < 0) return -1; if (tcProps && @@ -7432,6 +7432,7 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, virQEMUCaps *qemuCaps = priv->qemuCaps; g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; virJSONValue **nodeBackends = NULL; + g_autofree virBitmap **nodemask = NULL; bool needBackend = false; bool hmat = false; int ret = -1; @@ -7453,10 +7454,12 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, } nodeBackends = g_new0(virJSONValue *, ncells); + nodemask = g_new0(virBitmap *, ncells); for (i = 0; i < ncells; i++) { if ((rc = qemuBuildMemoryCellBackendProps(def, cfg, i, priv, - &nodeBackends[i])) < 0) + &nodeBackends[i], + &nodemask[i])) < 0) goto cleanup; if (rc == 0) @@ -7486,7 +7489,8 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, if (needBackend) { g_autoptr(virJSONValue) tcProps = NULL; - if (qemuBuildThreadContextProps(&tcProps, &nodeBackends[i], priv) < 0) + if (qemuBuildThreadContextProps(&tcProps, &nodeBackends[i], + priv, nodemask[i]) < 0) goto cleanup; if (tcProps && diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 9074822bc5..17f326d13b 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -153,7 +153,8 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg, int qemuBuildThreadContextProps(virJSONValue **tcProps, virJSONValue **memProps, - qemuDomainObjPrivate *priv); + qemuDomainObjPrivate *priv, + virBitmap *nodemask); /* Current, best practice */ virJSONValue * -- 2.39.2

On Wed, Mar 08, 2023 at 12:14:38PM +0100, Michal Privoznik wrote:
When building a thread-context object (inside of qemuBuildThreadContextProps()) we look at given memory-backend-* object and look for .host-nodes attribute. This works, as long as we need to just copy the attribute value into another thread-context attribute. But soon we will need to adjust it. That's the point where having the value in virBitmap comes handy. Utilize the previous commit, which made qemuBuildMemoryBackendProps() set the argument and pass it into qemuBuildThreadContextProps().
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 38 +++++++++++++++++++++----------------- src/qemu/qemu_command.h | 3 ++- 2 files changed, 23 insertions(+), 18 deletions(-)
Reviewed-by: Andrea Bolognani <abologna@redhat.com> -- Andrea Bolognani / Red Hat / Virtualization

When a thread-context object is specified on the cmd line, then QEMU spawns a thread and sets its affinity to the list of NUMA nodes specified in .node-affinity attribute. And this works just fine, until the main QEMU thread itself is not restricted. Because of v5.3.0-rc1~18 we restrict the main emulator thread even before QEMU is executed and thus then it tries to set affinity of a thread-context thread, it inevitably fails with: Setting CPU affinity failed: Invalid argument Now, we could lift the pinning temporarily, let QEMU spawn all thread-context threads, and enforce pinning again, but that would require some form of communication with QEMU (maybe -preconfig?). But that would still be wrong, because it would circumvent <emulatorpin/>. Technically speaking, thread-context is an internal implementation detail of QEMU, and if it weren't for it, the main emulator thread would be doing the allocation. Therefore, we should honor the pinning and prune the list of node so that inaccessible ones are dropped. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2154750 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 26 ++++++++++++++++--- src/qemu/qemu_command.h | 1 + ...emory-hotplug-dimm-addr.x86_64-latest.args | 2 +- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index b274ab6ff8..f93be01101 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3539,7 +3539,7 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd, def, mem, true, false, &nodemask) < 0) return -1; - if (qemuBuildThreadContextProps(&tcProps, &props, priv, nodemask) < 0) + if (qemuBuildThreadContextProps(&tcProps, &props, def, priv, nodemask) < 0) return -1; if (tcProps && @@ -3636,10 +3636,13 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg, int qemuBuildThreadContextProps(virJSONValue **tcProps, virJSONValue **memProps, + const virDomainDef *def, qemuDomainObjPrivate *priv, virBitmap *nodemask) { g_autoptr(virJSONValue) props = NULL; + virBitmap *emulatorpin = NULL; + g_autoptr(virBitmap) emulatorNodes = NULL; g_autofree char *tcAlias = NULL; const char *memalias = NULL; bool prealloc = false; @@ -3656,6 +3659,23 @@ qemuBuildThreadContextProps(virJSONValue **tcProps, !prealloc) return 0; + emulatorpin = qemuDomainEvaluateCPUMask(def, + def->cputune.emulatorpin, + priv->autoNodeset); + + if (emulatorpin && + virNumaIsAvailable()) { + if (virNumaCPUSetToNodeset(&emulatorNodes, emulatorpin) < 0) + return -1; + + virBitmapIntersect(emulatorNodes, nodemask); + + if (virBitmapIsAllClear(emulatorNodes)) + return 0; + + nodemask = emulatorNodes; + } + memalias = virJSONValueObjectGetString(*memProps, "id"); if (!memalias) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -7161,7 +7181,7 @@ qemuBuildMemCommandLineMemoryDefaultBackend(virCommand *cmd, def, &mem, false, true, &nodemask) < 0) return -1; - if (qemuBuildThreadContextProps(&tcProps, &props, priv, nodemask) < 0) + if (qemuBuildThreadContextProps(&tcProps, &props, def, priv, nodemask) < 0) return -1; if (tcProps && @@ -7490,7 +7510,7 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, g_autoptr(virJSONValue) tcProps = NULL; if (qemuBuildThreadContextProps(&tcProps, &nodeBackends[i], - priv, nodemask[i]) < 0) + def, priv, nodemask[i]) < 0) goto cleanup; if (tcProps && diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 17f326d13b..5fdb138030 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -153,6 +153,7 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg, int qemuBuildThreadContextProps(virJSONValue **tcProps, virJSONValue **memProps, + const virDomainDef *def, qemuDomainObjPrivate *priv, virBitmap *nodemask); diff --git a/tests/qemuxml2argvdata/memory-hotplug-dimm-addr.x86_64-latest.args b/tests/qemuxml2argvdata/memory-hotplug-dimm-addr.x86_64-latest.args index 84360843fb..6ae1fd1b98 100644 --- a/tests/qemuxml2argvdata/memory-hotplug-dimm-addr.x86_64-latest.args +++ b/tests/qemuxml2argvdata/memory-hotplug-dimm-addr.x86_64-latest.args @@ -28,7 +28,7 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \ -no-shutdown \ -boot strict=on \ -device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \ --object '{"qom-type":"thread-context","id":"tc-memdimm0","node-affinity":[1,2,3]}' \ +-object '{"qom-type":"thread-context","id":"tc-memdimm0","node-affinity":[1,2]}' \ -object '{"qom-type":"memory-backend-file","id":"memdimm0","mem-path":"/dev/hugepages2M/libvirt/qemu/-1-QEMUGuest1","prealloc":true,"size":536870912,"host-nodes":[1,2,3],"policy":"bind","prealloc-context":"tc-memdimm0"}' \ -device '{"driver":"pc-dimm","node":0,"memdev":"memdimm0","id":"dimm0","slot":0,"addr":4294967296}' \ -object '{"qom-type":"memory-backend-ram","id":"memdimm2","size":536870912}' \ -- 2.39.2

On Wed, Mar 08, 2023 at 12:14:39PM +0100, Michal Privoznik wrote:
qemuBuildThreadContextProps: Prune .node-afinity wrt <emulatorpin/>
Typo ("node-afinity"). Reviewed-by: Andrea Bolognani <abologna@redhat.com> -- Andrea Bolognani / Red Hat / Virtualization

Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- docs/formatdomain.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index c4077c6868..206875d68e 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -1117,7 +1117,9 @@ influence how virtual memory pages are backed by host pages. Using the optional ``mode`` attribute, specify when to allocate the memory by supplying either "immediate" or "ondemand". :since:`Since 8.2.0` it is possible to set the number of threads that hypervisor uses to allocate - memory via ``threads`` attribute. + memory via ``threads`` attribute. To speed allocation process up, when + pinning emulator thread it's recommended to include CPUs from desired NUMA + nodes so that allocation threads can have their affinity set. ``discard`` When set and supported by hypervisor the memory content is discarded just before guest shuts down (or when DIMM module is unplugged). Please note that -- 2.39.2

On Wed, Mar 08, 2023 at 12:14:40PM +0100, Michal Privoznik wrote:
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- docs/formatdomain.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
Reviewed-by: Andrea Bolognani <abologna@redhat.com> -- Andrea Bolognani / Red Hat / Virtualization

Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- NEWS.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 089ad733f2..29239950c1 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -42,6 +42,13 @@ v9.2.0 (unreleased) Due to a logic bug introduced in libvirt 9.0.0, VM configurations explicitly enabling the HPET timer were rejected. + * qemu: Fix thread-context .host-nodes generation + + With new enough QEMU, libvirt instructs QEMU to set affinity of memory + allocation threads. But this may have resulted in QEMU being unable to do + so, as affinity to NUMA nodes inaccessible to emulator thread might have + been requested. + v9.1.0 (2023-03-01) =================== -- 2.39.2

On Wed, Mar 08, 2023 at 12:14:41PM +0100, Michal Privoznik wrote:
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- NEWS.rst | 7 +++++++ 1 file changed, 7 insertions(+)
Reviewed-by: Andrea Bolognani <abologna@redhat.com> -- Andrea Bolognani / Red Hat / Virtualization
participants (3)
-
Andrea Bolognani
-
Kristina Hanicova
-
Michal Privoznik