From: Wim ten Have <wim.ten.have@xxxxxxxxxx> Add support for hot plugging memory into vNUMA partitioned KVM guests. Hot plugging memory without a target <numa> node with result in evenly balancing the added memory along all vNUMA nodes. Signed-off-by: Wim ten Have <wim.ten.have@xxxxxxxxxx> --- src/qemu/qemu_driver.c | 59 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e64afcb8efc9..8d1f0bf13cb7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2348,9 +2348,12 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, } if (persistentDef) { - /* resizing memory with NUMA nodes specified doesn't work as there - * is no way to change the individual node sizes with this API */ - if (virDomainNumaGetNodeCount(persistentDef->numa) > 0) { + /* Resizing memory with NUMA nodes specified doesn't work, as there + * is no way to change the individual node sizes with this API, but + * when vNUMA automatic partitioning is in effect resizing is possible. + */ + if (!virDomainVnumaIsEnabled(persistentDef->numa) && + virDomainNumaGetNodeCount(persistentDef->numa) > 0) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("initial memory size of a domain with NUMA " "nodes cannot be modified with this API")); @@ -2365,7 +2368,12 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, goto endjob; } - virDomainDefSetMemoryTotal(persistentDef, newmem); + if (virDomainDefSetNUMAMemoryTotal(persistentDef, newmem, driver->caps) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to distribute newly configured " + "memory across NUMA nodes")); + goto endjob; + } if (persistentDef->mem.cur_balloon > newmem) persistentDef->mem.cur_balloon = newmem; @@ -2378,6 +2386,18 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, /* resize the current memory */ unsigned long oldmax = 0; + if ((def && + virDomainVnumaIsEnabled(def->numa) && + virDomainNumaGetNodeCount(def->numa)) || + (persistentDef && + virDomainVnumaIsEnabled(persistentDef->numa) && + virDomainNumaGetNodeCount(persistentDef->numa)) > 0) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("the current memory size of a domain with NUMA " + "nodes cannot be modified with this API")); + goto endjob; + } + if (def) oldmax = virDomainDefGetMemoryTotal(def); if (persistentDef) { @@ -7820,6 +7840,7 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm, { int ret = -1; const char *alias = NULL; + virDomainMemoryDefPtr mem; switch ((virDomainDeviceType)dev->type) { case VIR_DOMAIN_DEVICE_DISK: @@ -7895,8 +7916,34 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm, case VIR_DOMAIN_DEVICE_MEMORY: /* note that qemuDomainAttachMemory always consumes dev->data.memory * and dispatches DeviceAdded event on success */ - ret = qemuDomainAttachMemory(driver, vm, - dev->data.memory); + + mem = dev->data.memory; + if (mem->targetNode >= 0) { + ret = qemuDomainAttachMemory(driver, vm, + dev->data.memory); + } else { + size_t i, ncells = virDomainNumaGetNodeCount(vm->def->numa); + unsigned long long memsizeCell = dev->data.memory->size / ncells; + + for (i = 0; i < ncells; i++) { + + if (VIR_ALLOC(mem) < 0) { + ret = -1; + break; + } + + memcpy(mem, dev->data.memory, sizeof(virDomainMemoryDef)); + + if (dev->data.memory->sourceNodes) + virBitmapCopy(mem->sourceNodes, dev->data.memory->sourceNodes); + + mem->size = memsizeCell; + mem->targetNode = i; + + ret = qemuDomainAttachMemory(driver, vm, mem); + } + virDomainMemoryDefFree(dev->data.memory); + } dev->data.memory = NULL; break; -- 2.21.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list