diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index b6caaf7c8f6d457a41a2552641ae24f3b68c2c73..806251071e10c175cd96cdbb085cc4cf9e05c736 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -150,6 +150,11 @@ VIR_ENUM_IMPL(qemuDomainFSDriver, VIR_DOMAIN_FS_DRIVER_TYPE_LAST, NULL, NULL); +VIR_ENUM_DECL(qemuNumaPolicy) +VIR_ENUM_IMPL(qemuNumaPolicy, VIR_DOMAIN_NUMATUNE_MEM_LAST, + "bind", + "preferred", + "interleave"); /** * qemuPhysIfaceConnect: @@ -6383,13 +6388,23 @@ qemuBuildNumaArgStr(const virDomainDef *def, size_t i; virBuffer buf = VIR_BUFFER_INITIALIZER; char *cpumask = NULL, *tmpmask = NULL, *next = NULL; + char *nodemask = NULL; int ret = -1; + if (virDomainNumatuneHasPerNodeBinding(def->numatune) && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Per-node memory binding is not supported " + "with this QEMU")); + goto cleanup; + } + for (i = 0; i < def->cpu->ncells; i++) { int cellmem = VIR_DIV_UP(def->cpu->cells[i].mem, 1024); def->cpu->cells[i].mem = cellmem * 1024; VIR_FREE(cpumask); + VIR_FREE(nodemask); if (!(cpumask = virBitmapFormat(def->cpu->cells[i].cpumask))) goto cleanup; @@ -6402,6 +6417,43 @@ qemuBuildNumaArgStr(const virDomainDef *def, goto cleanup; } + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM)) { + virDomainNumatuneMemMode mode; + const char *policy = NULL; + + mode = virDomainNumatuneGetMode(def->numatune, i); + policy = qemuNumaPolicyTypeToString(mode); + + virBufferAsprintf(&buf, "memory-backend-ram,size=%dM,id=ram-node%zu", + cellmem, i); + + if (virDomainNumatuneMaybeFormatNodeset(def->numatune, NULL, + &nodemask, i) < 0) + goto cleanup; + + if (nodemask) { + if (strchr(nodemask, ',') && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_NUMA)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("disjoint NUMA node ranges are not supported " + "with this QEMU")); + goto cleanup; + } + + for (tmpmask = nodemask; tmpmask; tmpmask = next) { + if ((next = strchr(tmpmask, ','))) + *(next++) = '\0'; + virBufferAddLit(&buf, ",host-nodes="); + virBufferAdd(&buf, tmpmask, -1); + } + + virBufferAsprintf(&buf, ",policy=%s", policy); + } + + virCommandAddArg(cmd, "-object"); + virCommandAddArgBuffer(cmd, &buf); + } + virCommandAddArg(cmd, "-numa"); virBufferAsprintf(&buf, "node,nodeid=%zu", i); @@ -6412,7 +6464,11 @@ qemuBuildNumaArgStr(const virDomainDef *def, virBufferAdd(&buf, tmpmask, -1); } - virBufferAsprintf(&buf, ",mem=%d", cellmem); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM)) { + virBufferAsprintf(&buf, ",memdev=ram-node%zu", i); + } else { + virBufferAsprintf(&buf, ",mem=%d", cellmem); + } virCommandAddArgBuffer(cmd, &buf); } @@ -6420,6 +6476,7 @@ qemuBuildNumaArgStr(const virDomainDef *def, cleanup: VIR_FREE(cpumask); + VIR_FREE(nodemask); virBufferFreeAndReset(&buf); return ret; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode-no-memory.args b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode-no-memory.args new file mode 100644 index 0000000000000000000000000000000000000000..b0e274ca07e51bb7aeb98b1f6783795a9bd494ac --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode-no-memory.args @@ -0,0 +1,8 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \ +/usr/bin/kvm -S -M pc -m 64 -smp 2 \ +-object memory-backend-ram,size=32M,id=ram-node0,host-nodes=3,policy=preferred \ +-numa node,nodeid=0,cpus=0,memdev=ram-node0 \ +-object memory-backend-ram,size=32M,id=ram-node1 \ +-numa node,nodeid=1,cpus=1,memdev=ram-node1 \ +-nographic -monitor unix:/tmp/test-monitor,server,nowait \ +-no-acpi -boot c -usb -net none -serial none -parallel none diff --git a/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args new file mode 100644 index 0000000000000000000000000000000000000000..e4beb98084bef1f398ab8ed932ff153eb3ec9ae6 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-numatune-memnode.args @@ -0,0 +1,11 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \ +/usr/bin/kvm -S -M pc -m 24104 -smp 32 \ +-object memory-backend-ram,size=20M,id=ram-node0,host-nodes=3,policy=preferred \ +-numa node,nodeid=0,cpus=0,memdev=ram-node0 \ +-object memory-backend-ram,size=645M,id=ram-node1,host-nodes=0-7,policy=bind \ +-numa node,nodeid=1,cpus=1-27,cpus=29,memdev=ram-node1 \ +-object memory-backend-ram,size=23440M,id=ram-node2,\ +host-nodes=1-2,host-nodes=5,host-nodes=7,policy=bind \ +-numa node,nodeid=2,cpus=28,cpus=30-31,memdev=ram-node2 \ +-nographic -monitor unix:/tmp/test-monitor,server,nowait \ +-no-acpi -boot c -usb -net none -serial none -parallel none diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 1fd106679e3982e391e6a1aa5f67111e327b46f4..28436f2e5d75913dd2a090f8d4aa02ec90747850 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1197,7 +1197,14 @@ mymain(void) DO_TEST("blkiotune-device", QEMU_CAPS_NAME); DO_TEST("cputune", QEMU_CAPS_NAME); DO_TEST("cputune-zero-shares", QEMU_CAPS_NAME); + DO_TEST("numatune-memory", NONE); + DO_TEST("numatune-memnode", QEMU_CAPS_NUMA, QEMU_CAPS_OBJECT_MEMORY_RAM); + DO_TEST_FAILURE("numatune-memnode", NONE); + + DO_TEST("numatune-memnode-no-memory", QEMU_CAPS_NUMA, QEMU_CAPS_OBJECT_MEMORY_RAM); + DO_TEST_FAILURE("numatune-memnode-no-memory", NONE); + DO_TEST("numatune-auto-nodeset-invalid", NONE); DO_TEST_PARSE_ERROR("numatune-memnode-nocpu", NONE); DO_TEST_PARSE_ERROR("numatune-memnodes-problematic", NONE);