[libvirt] [PATCH v2 0/2] Don't choke on valid NUMA nodesets on daemon restart

Changes from [v1]: * make sure the tests pass even when compiling --without-qemu; * actually run syntax-check before sending out patches. [v1] https://www.redhat.com/archives/libvir-list/2018-April/msg00937.html Andrea Bolognani (2): tests: Create full host NUMA topology in more cases qemu: Figure out nodeset bitmap size correctly src/qemu/qemu_domain.c | 10 ++++- tests/qemustatusxml2xmldata/modern-in.xml | 2 +- tests/testutils.c | 51 ++++++++++++++++++++++++ tests/testutils.h | 2 + tests/testutilsqemu.c | 7 +++- tests/vircapstest.c | 66 +++---------------------------- 6 files changed, 74 insertions(+), 64 deletions(-) -- 2.14.3

vircapstest has code to add a full host NUMA topology, that is, one that includes all information about nodes and CPUs including IDs; testQemuCapsInit(), which is used to create a mock virCapsPtr for QEMU tests, however, just fakes it by setting nnumaCell_max to some number. While the latter approach has served us well so far, we're going to need all the information to be filled in soon. In order to do that, we can just move the existing code from vircapstest to testutils and, with some renaming and trivial tweaking, use it as-is. Interestingly, the NUMA topology generated by the function is rigged up so that the NUMA nodes aren't (necessarily) numbered starting from 0, which is a nice way to spot mistaken assumptions in our codebase. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- tests/testutils.c | 51 +++++++++++++++++++++++++++++++++++++++ tests/testutils.h | 2 ++ tests/testutilsqemu.c | 7 +++++- tests/vircapstest.c | 66 ++++----------------------------------------------- 4 files changed, 64 insertions(+), 62 deletions(-) diff --git a/tests/testutils.c b/tests/testutils.c index 7c095caac9..4b13d11278 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -1228,6 +1228,57 @@ virCapsPtr virTestGenericCapsInit(void) return NULL; } + +#define MAX_CELLS 4 +#define MAX_CPUS_IN_CELL 2 +#define MAX_MEM_IN_CELL 2097152 + +/* + * Build NUMA topology with cell id starting from (0 + seq) + * for testing + */ +int +virTestCapsBuildNUMATopology(virCapsPtr caps, + int seq) +{ + virCapsHostNUMACellCPUPtr cell_cpus = NULL; + int core_id, cell_id; + int id; + + id = 0; + for (cell_id = 0; cell_id < MAX_CELLS; cell_id++) { + if (VIR_ALLOC_N(cell_cpus, MAX_CPUS_IN_CELL) < 0) + goto error; + + for (core_id = 0; core_id < MAX_CPUS_IN_CELL; core_id++) { + cell_cpus[core_id].id = id + core_id; + cell_cpus[core_id].socket_id = cell_id + seq; + cell_cpus[core_id].core_id = id + core_id; + if (!(cell_cpus[core_id].siblings = + virBitmapNew(MAX_CPUS_IN_CELL))) + goto error; + ignore_value(virBitmapSetBit(cell_cpus[core_id].siblings, id)); + } + id++; + + if (virCapabilitiesAddHostNUMACell(caps, cell_id + seq, + MAX_MEM_IN_CELL, + MAX_CPUS_IN_CELL, cell_cpus, + VIR_ARCH_NONE, NULL, + VIR_ARCH_NONE, NULL) < 0) + goto error; + + cell_cpus = NULL; + } + + return 0; + + error: + virCapabilitiesClearHostNUMACellCPUTopology(cell_cpus, MAX_CPUS_IN_CELL); + VIR_FREE(cell_cpus); + return -1; +} + static virDomainDefParserConfig virTestGenericDomainDefParserConfig = { .features = VIR_DOMAIN_DEF_FEATURE_INDIVIDUAL_VCPUS, }; diff --git a/tests/testutils.h b/tests/testutils.h index d840875bc1..3bd7bf1603 100644 --- a/tests/testutils.h +++ b/tests/testutils.h @@ -147,6 +147,8 @@ int virTestMain(int argc, } virCapsPtr virTestGenericCapsInit(void); +int virTestCapsBuildNUMATopology(virCapsPtr caps, + int seq); virDomainXMLOptionPtr virTestGenericDomainXMLConfInit(void); typedef enum { diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index 9671a46f12..01fa1b701f 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -400,7 +400,12 @@ virCapsPtr testQemuCapsInit(void) qemuTestSetHostCPU(caps, NULL); - caps->host.nnumaCell_max = 4; + /* + * Build a NUMA topology with cell_id (NUMA node id + * being 3(0 + 3),4(1 + 3), 5 and 6 + */ + if (virTestCapsBuildNUMATopology(caps, 3) < 0) + goto cleanup; if (testQemuAddI686Guest(caps) < 0) goto cleanup; diff --git a/tests/vircapstest.c b/tests/vircapstest.c index 664b7da143..1df3fa091f 100644 --- a/tests/vircapstest.c +++ b/tests/vircapstest.c @@ -29,62 +29,6 @@ #define VIR_FROM_THIS VIR_FROM_NONE -#define MAX_CELLS 4 -#define MAX_CPUS_IN_CELL 2 -#define MAX_MEM_IN_CELL 2097152 - - -/* - * Build NUMA Toplogy with cell id starting from (0 + seq) - * for testing - */ -static virCapsPtr -buildNUMATopology(int seq) -{ - virCapsPtr caps; - virCapsHostNUMACellCPUPtr cell_cpus = NULL; - int core_id, cell_id; - int id; - - if ((caps = virCapabilitiesNew(VIR_ARCH_X86_64, false, false)) == NULL) - goto error; - - id = 0; - for (cell_id = 0; cell_id < MAX_CELLS; cell_id++) { - if (VIR_ALLOC_N(cell_cpus, MAX_CPUS_IN_CELL) < 0) - goto error; - - for (core_id = 0; core_id < MAX_CPUS_IN_CELL; core_id++) { - cell_cpus[core_id].id = id + core_id; - cell_cpus[core_id].socket_id = cell_id + seq; - cell_cpus[core_id].core_id = id + core_id; - if (!(cell_cpus[core_id].siblings = - virBitmapNew(MAX_CPUS_IN_CELL))) - goto error; - ignore_value(virBitmapSetBit(cell_cpus[core_id].siblings, id)); - } - id++; - - if (virCapabilitiesAddHostNUMACell(caps, cell_id + seq, - MAX_MEM_IN_CELL, - MAX_CPUS_IN_CELL, cell_cpus, - VIR_ARCH_NONE, NULL, - VIR_ARCH_NONE, NULL) < 0) - goto error; - - cell_cpus = NULL; - } - - return caps; - - error: - virCapabilitiesClearHostNUMACellCPUTopology(cell_cpus, MAX_CPUS_IN_CELL); - VIR_FREE(cell_cpus); - virObjectUnref(caps); - return NULL; - -} - static int test_virCapabilitiesGetCpusForNodemask(const void *data ATTRIBUTE_UNUSED) @@ -96,11 +40,11 @@ test_virCapabilitiesGetCpusForNodemask(const void *data ATTRIBUTE_UNUSED) int mask_size = 8; int ret = -1; - /* - * Build a NUMA topology with cell_id (NUMA node id - * being 3(0 + 3),4(1 + 3), 5 and 6 - */ - if (!(caps = buildNUMATopology(3))) + + if (!(caps = virCapabilitiesNew(VIR_ARCH_X86_64, false, false))) + goto error; + + if (virTestCapsBuildNUMATopology(caps, 3) < 0) goto error; if (virBitmapParse(nodestr, &nodemask, mask_size) < 0) -- 2.14.3

On Thu, Apr 19, 2018 at 04:19:38PM +0200, Andrea Bolognani wrote:
vircapstest has code to add a full host NUMA topology, that is, one that includes all information about nodes and CPUs including IDs; testQemuCapsInit(), which is used to create a mock virCapsPtr for QEMU tests, however, just fakes it by setting nnumaCell_max to some number.
While the latter approach has served us well so far, we're going to need all the information to be filled in soon. In order to do that, we can just move the existing code from vircapstest to testutils and, with some renaming and trivial tweaking, use it as-is.
Interestingly, the NUMA topology generated by the function is rigged up so that the NUMA nodes aren't (necessarily) numbered starting from 0, which is a nice way to spot mistaken assumptions in our codebase.
Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- tests/testutils.c | 51 +++++++++++++++++++++++++++++++++++++++ tests/testutils.h | 2 ++ tests/testutilsqemu.c | 7 +++++- tests/vircapstest.c | 66 ++++----------------------------------------------- 4 files changed, 64 insertions(+), 62 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

The current private XML parsing code relies on the assumption that NUMA node IDs start from 0 and are densely allocated, neither of which is necessarily the case. Change it so that the bitmap size is dynamically calculated by looking at NUMA node IDs instead, which ensures all nodes will be able to fit and thus the bitmap will be parsed successfully. Update one of the test cases so that it would fail with the previous approach, but passes with the new one. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1490158 Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/qemu/qemu_domain.c | 10 +++++++++- tests/qemustatusxml2xmldata/modern-in.xml | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 21897cb47a..2670a10119 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2233,6 +2233,8 @@ qemuDomainObjPrivateXMLParseAutomaticPlacement(xmlXPathContextPtr ctxt, virCapsPtr caps = NULL; char *nodeset; char *cpuset; + int nodesetSize = 0; + size_t i; int ret = -1; nodeset = virXPathString("string(./numad/@nodeset)", ctxt); @@ -2244,8 +2246,14 @@ qemuDomainObjPrivateXMLParseAutomaticPlacement(xmlXPathContextPtr ctxt, if (!(caps = virQEMUDriverGetCapabilities(driver, false))) goto cleanup; + /* Figure out how big the nodeset bitmap needs to be. + * This is necessary because NUMA node IDs are not guaranteed to + * start from 0 or be densely allocated */ + for (i = 0; i < caps->host.nnumaCell; i++) + nodesetSize = MAX(nodesetSize, caps->host.numaCell[i]->num + 1); + if (nodeset && - virBitmapParse(nodeset, &priv->autoNodeset, caps->host.nnumaCell_max) < 0) + virBitmapParse(nodeset, &priv->autoNodeset, nodesetSize) < 0) goto cleanup; if (cpuset) { diff --git a/tests/qemustatusxml2xmldata/modern-in.xml b/tests/qemustatusxml2xmldata/modern-in.xml index 2e166e6e67..c1e57618b6 100644 --- a/tests/qemustatusxml2xmldata/modern-in.xml +++ b/tests/qemustatusxml2xmldata/modern-in.xml @@ -252,7 +252,7 @@ <device alias='usb'/> <device alias='ide0-0-0'/> </devices> - <numad nodeset='0' cpuset='0-7'/> + <numad nodeset='6' cpuset='0-7'/> <libDir path='/var/lib/libvirt/qemu/domain-1-upstream'/> <channelTargetDir path='/var/lib/libvirt/qemu/channel/target/domain-1-upstream'/> <chardevStdioLogd/> -- 2.14.3

On Thu, Apr 19, 2018 at 04:19:39PM +0200, Andrea Bolognani wrote:
The current private XML parsing code relies on the assumption that NUMA node IDs start from 0 and are densely allocated, neither of which is necessarily the case.
Change it so that the bitmap size is dynamically calculated by looking at NUMA node IDs instead, which ensures all nodes will be able to fit and thus the bitmap will be parsed successfully.
Update one of the test cases so that it would fail with the previous approach, but passes with the new one.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1490158 Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/qemu/qemu_domain.c | 10 +++++++++- tests/qemustatusxml2xmldata/modern-in.xml | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano
participants (2)
-
Andrea Bolognani
-
Ján Tomko