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

v2 of: https://listman.redhat.com/archives/libvir-list/2023-March/238536.html diff to v1: - Swapped arguments in virNumaCPUSetToNodeset() - Other small nits - typos Michal Prívozník (15): 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() qemuBuildMemoryBackendProps: Join two conditions qemu: Add @nodemaskRet argument to qemuBuildMemoryBackendProps() qemu: Add @nodemask argument to qemuBuildThreadContextProps() qemuBuildThreadContextProps: Prune .node-affinity 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 | 42 ----- 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(+), 164 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> Reviewed-by: Kristina Hanicova <khanicov@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 Tue, Mar 14, 2023 at 05:52:15PM +0100, Michal Privoznik wrote:
virnuma: Move virNumaNodesetToCPUset() our of WITH_NUMACTL
Typo ("our" instead of "out"). -- Andrea Bolognani / Red Hat / Virtualization

On Tue, 14 Mar 2023, 11:22 pm Andrea Bolognani, <abologna@redhat.com> wrote:
On Tue, Mar 14, 2023 at 05:52:15PM +0100, Michal Privoznik wrote:
virnuma: Move virNumaNodesetToCPUset() our of WITH_NUMACTL
Typo ("our" instead of "out").
-- Andrea Bolognani / Red Hat / Virtualization

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> Reviewed-by: Kristina Hanicova <khanicov@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 6f44788233..605522c9f6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2976,6 +2976,7 @@ virNodeSuspendGetTargetMask; # util/virnuma.h +virNumaCPUSetToNodeset; virNumaGetAutoPlacementAdvice; virNumaGetDistances; virNumaGetHostMemoryNodeset; @@ -2983,6 +2984,7 @@ virNumaGetMaxCPUs; virNumaGetMaxNode; virNumaGetNodeCPUs; virNumaGetNodeMemory; +virNumaGetNodeOfCPU; virNumaGetPageInfo; virNumaGetPages; virNumaIsAvailable; diff --git a/src/util/virnuma.c b/src/util/virnuma.c index dae0827c65..4a15bf32c8 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) } +/** + * virNumaCPUSetToNodeset: + * @cpuset: bitmap containing a set of CPUs + * @nodeset: returned bitmap containing a set of NUMA nodes + * + * 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 *cpuset, + virBitmap **nodeset) +{ + 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..2c30ef4e31 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 *cpuset, + virBitmap **nodeset); int virNumaNodesetToCPUset(virBitmap *nodeset, virBitmap **cpuset); -- 2.39.2

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> Reviewed-by: Kristina Hanicova <khanicov@redhat.com> Reviewed-by: Andrea Bolognani <abologna@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 2c30ef4e31..edd701d5c8 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 *cpuset, virBitmap **nodeset); 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

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..0fd3bc62cf 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -84,6 +84,7 @@ mock_libs = [ { 'name': 'virnetdaemonmock' }, { 'name': 'virnetdevmock' }, { 'name': 'virnetserverclientmock' }, + { 'name': 'virnumamock' }, { 'name': 'virpcimock' }, { 'name': 'virportallocatormock' }, { 'name': 'virprocessmock' }, @@ -94,7 +95,6 @@ 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 c879fa90e0..efecb7c89d 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", @@ -2911,7 +2913,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

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> Reviewed-by: Andrea Bolognani <abologna@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

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> Reviewed-by: Andrea Bolognani <abologna@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

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> Reviewed-by: Kristina Hanicova <khanicov@redhat.com> Reviewed-by: Andrea Bolognani <abologna@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 | 42 ------------------- 5 files changed, 4 insertions(+), 46 deletions(-) diff --git a/src/util/virnuma.h b/src/util/virnuma.h index edd701d5c8..475df96e1d 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..f566ec539a 100644 --- a/tests/qemuxml2argvmock.c +++ b/tests/qemuxml2argvmock.c @@ -30,7 +30,6 @@ #include "virnetdevip.h" #include "virnetdevtap.h" #include "virnetdevopenvswitch.h" -#include "virnuma.h" #include "virscsivhost.h" #include "virtpm.h" #include "virutil.h" @@ -56,47 +55,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

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> Reviewed-by: Andrea Bolognani <abologna@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 0feab09bee..3d41d9e90f 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -12451,3 +12451,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 9bcc5e1380..e230e9777b 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -1133,3 +1133,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 be418ad8e6..18b7781cbb 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

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> Reviewed-by: Andrea Bolognani <abologna@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 fd8136be37..754b2a8192 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

There are two compound conditions in qemuBuildMemoryBackendProps() and each one checks for nodemask for NULL first. Join them into one bigger block. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Kristina Hanicova <khanicov@redhat.com> --- src/qemu/qemu_command.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 929bcc0be1..b0cb252d0b 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3437,19 +3437,21 @@ 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 none of the following is requested... */ -- 2.39.2

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), if 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> Reviewed-by: Kristina Hanicova <khanicov@redhat.com> --- src/qemu/qemu_command.c | 14 ++++++++++---- src/qemu/qemu_command.h | 4 +++- src/qemu/qemu_hotplug.c | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index b0cb252d0b..15ba3c02d1 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; @@ -3451,6 +3453,9 @@ qemuBuildMemoryBackendProps(virJSONValue **backendProps, "S:policy", qemuNumaPolicyTypeToString(mode), NULL) < 0) return -1; + + if (nodemaskRet) + *nodemaskRet = nodemask; } } @@ -3504,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); } @@ -3528,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) @@ -7179,7 +7185,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

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> Reviewed-by: Andrea Bolognani <abologna@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 15ba3c02d1..6de3b549a0 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; @@ -7178,17 +7177,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 && @@ -7459,6 +7459,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; @@ -7480,10 +7481,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) @@ -7513,7 +7516,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

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> Reviewed-by: Andrea Bolognani <abologna@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 6de3b549a0..7137edac8f 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(emulatorpin, &emulatorNodes) < 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", @@ -7188,7 +7208,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 && @@ -7517,7 +7537,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 Tue, Mar 14, 2023 at 5:53 PM Michal Privoznik <mprivozn@redhat.com> wrote:
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> Reviewed-by: Andrea Bolognani <abologna@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 6de3b549a0..7137edac8f 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()) {
Could have been on the same line.
+ if (virNumaCPUSetToNodeset(emulatorpin, &emulatorNodes) < 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", @@ -7188,7 +7208,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 && @@ -7517,7 +7537,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
Reviewed-by: Kristina Hanicova <khanicov@redhat.com> Kristina

Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Andrea Bolognani <abologna@redhat.com> --- docs/formatdomain.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 4f4874eba2..27f83e254d 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

Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Andrea Bolognani <abologna@redhat.com> --- NEWS.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index e5b304786b..5b5265996f 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -48,6 +48,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 Tue, Mar 14, 2023 at 05:52:14PM +0100, Michal Privoznik wrote:
v2 of:
https://listman.redhat.com/archives/libvir-list/2023-March/238536.html
diff to v1: - Swapped arguments in virNumaCPUSetToNodeset() - Other small nits - typos
Michal Prívozník (15): 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() qemuBuildMemoryBackendProps: Join two conditions qemu: Add @nodemaskRet argument to qemuBuildMemoryBackendProps() qemu: Add @nodemask argument to qemuBuildThreadContextProps() qemuBuildThreadContextProps: Prune .node-affinity wrt <emulatorpin/> docs: Document memory allocation and emulator pinning limitation NEWS: Document recent thread-context bug fix
Series Reviewed-by: Andrea Bolognani <abologna@redhat.com> Maybe give Kristina a chance to take a look at the patches that don't already have her R-b before pushing. -- Andrea Bolognani / Red Hat / Virtualization

On Tue, Mar 14, 2023 at 5:53 PM Michal Privoznik <mprivozn@redhat.com> wrote:
v2 of:
https://listman.redhat.com/archives/libvir-list/2023-March/238536.html
diff to v1: - Swapped arguments in virNumaCPUSetToNodeset() - Other small nits - typos
Michal Prívozník (15): 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() qemuBuildMemoryBackendProps: Join two conditions qemu: Add @nodemaskRet argument to qemuBuildMemoryBackendProps() qemu: Add @nodemask argument to qemuBuildThreadContextProps() qemuBuildThreadContextProps: Prune .node-affinity wrt <emulatorpin/> docs: Document memory allocation and emulator pinning limitation NEWS: Document recent thread-context bug fix
Reviewed-by: Kristina Hanicova <khanicov@redhat.com> Kristina

On a Tuesday in 2023, Michal Privoznik wrote:
v2 of:
https://listman.redhat.com/archives/libvir-list/2023-March/238536.html
diff to v1: - Swapped arguments in virNumaCPUSetToNodeset() - Other small nits - typos
Michal Prívozník (15): 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
Thank you for splitting this.
qemu: Fix qemuDomainGetEmulatorPinInfo() qemuBuildMemoryBackendProps: Join two conditions qemu: Add @nodemaskRet argument to qemuBuildMemoryBackendProps() qemu: Add @nodemask argument to qemuBuildThreadContextProps() qemuBuildThreadContextProps: Prune .node-affinity wrt <emulatorpin/> docs: Document memory allocation and emulator pinning limitation NEWS: Document recent thread-context bug fix
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano
participants (5)
-
Andrea Bolognani
-
Ján Tomko
-
Kristina Hanicova
-
Kshitiz Mhto
-
Michal Privoznik