mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 04:25:18 +00:00
qemu: add support for memory devices
Add support to start qemu instance with 'pc-dimm' device. Thanks to the refactors we are able to reuse the existing function to determine the parameters.
This commit is contained in:
parent
c5710066e8
commit
8b54bffbab
@ -1222,6 +1222,10 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
|
||||
if (virAsprintf(&def->tpm->info.alias, "tpm%d", 0) < 0)
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < def->nmems; i++) {
|
||||
if (virAsprintf(&def->mems[i]->info.alias, "dimm%zu", i) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -4612,8 +4616,7 @@ qemuBuildMemoryBackendStr(unsigned long long size,
|
||||
virDomainHugePagePtr hugepage = NULL;
|
||||
virDomainNumatuneMemMode mode;
|
||||
const long system_page_size = virGetSystemPageSizeKB();
|
||||
virNumaMemAccess memAccess = virDomainNumaGetNodeMemoryAccessMode(def->numa, guestNode);
|
||||
|
||||
virNumaMemAccess memAccess = VIR_NUMA_MEM_ACCESS_DEFAULT;
|
||||
size_t i;
|
||||
char *mem_path = NULL;
|
||||
virBitmapPtr nodemask = NULL;
|
||||
@ -4623,9 +4626,19 @@ qemuBuildMemoryBackendStr(unsigned long long size,
|
||||
*backendProps = NULL;
|
||||
*backendType = NULL;
|
||||
|
||||
/* memory devices could provide a invalid guest node */
|
||||
if (guestNode >= virDomainNumaGetNodeCount(def->numa)) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||
_("can't add memory backend for guest node '%d' as "
|
||||
"the guest has only '%zu' NUMA nodes configured"),
|
||||
guestNode, virDomainNumaGetNodeCount(def->numa));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(props = virJSONValueNewObject()))
|
||||
return -1;
|
||||
|
||||
memAccess = virDomainNumaGetNodeMemoryAccessMode(def->numa, guestNode);
|
||||
mode = virDomainNumatuneGetMode(def->numa, guestNode);
|
||||
|
||||
if (pagesize == 0 || pagesize != system_page_size) {
|
||||
@ -4824,6 +4837,95 @@ qemuBuildMemoryCellBackendStr(virDomainDefPtr def,
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
qemuBuildMemoryDimmBackendStr(virDomainMemoryDefPtr mem,
|
||||
virDomainDefPtr def,
|
||||
virQEMUCapsPtr qemuCaps,
|
||||
virQEMUDriverConfigPtr cfg)
|
||||
{
|
||||
virJSONValuePtr props = NULL;
|
||||
char *alias = NULL;
|
||||
const char *backendType;
|
||||
char *ret = NULL;
|
||||
|
||||
if (!mem->info.alias) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("memory device alias is not assigned"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (virAsprintf(&alias, "mem%s", mem->info.alias) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (qemuBuildMemoryBackendStr(mem->size, mem->pagesize,
|
||||
mem->targetNode, mem->sourceNodes, NULL,
|
||||
def, qemuCaps, cfg,
|
||||
&backendType, &props, true) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = qemuBuildObjectCommandlineFromJSON(backendType, alias, props);
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(alias);
|
||||
virJSONValueFree(props);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
qemuBuildMemoryDeviceStr(virDomainMemoryDefPtr mem,
|
||||
virQEMUCapsPtr qemuCaps)
|
||||
{
|
||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||
|
||||
if (!mem->info.alias) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("missing alias for memory device"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch ((virDomainMemoryModel) mem->model) {
|
||||
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
|
||||
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PC_DIMM)) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("this qemu doesn't support the pc-dimm device"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM &&
|
||||
mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("only 'dimm' addresses are supported for the "
|
||||
"pc-dimm device"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virBufferAsprintf(&buf, "pc-dimm,node=%d,memdev=mem%s,id=%s",
|
||||
mem->targetNode, mem->info.alias, mem->info.alias);
|
||||
|
||||
if (mem->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM) {
|
||||
virBufferAsprintf(&buf, ",slot=%d", mem->info.addr.dimm.slot);
|
||||
virBufferAsprintf(&buf, ",base=%llu", mem->info.addr.dimm.base);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_MEMORY_MODEL_NONE:
|
||||
case VIR_DOMAIN_MEMORY_MODEL_LAST:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("invalid memory device type"));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (virBufferCheckError(&buf) < 0)
|
||||
return NULL;
|
||||
|
||||
return virBufferContentAndReset(&buf);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
qemuBuildNicStr(virDomainNetDefPtr net,
|
||||
const char *prefix,
|
||||
@ -8602,10 +8704,32 @@ qemuBuildCommandLine(virConnectPtr conn,
|
||||
}
|
||||
}
|
||||
|
||||
if (virDomainNumaGetNodeCount(def->numa))
|
||||
if (virDomainNumaGetNodeCount(def->numa)) {
|
||||
if (qemuBuildNumaArgStr(cfg, def, cmd, qemuCaps, nodeset) < 0)
|
||||
goto error;
|
||||
|
||||
/* memory hotplug requires NUMA to be enabled - we already checked
|
||||
* that memory devices are present only when NUMA is */
|
||||
for (i = 0; i < def->nmems; i++) {
|
||||
char *backStr;
|
||||
char *dimmStr;
|
||||
|
||||
if (!(backStr = qemuBuildMemoryDimmBackendStr(def->mems[i], def,
|
||||
qemuCaps, cfg)))
|
||||
goto error;
|
||||
|
||||
if (!(dimmStr = qemuBuildMemoryDeviceStr(def->mems[i], qemuCaps))) {
|
||||
VIR_FREE(backStr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
virCommandAddArgList(cmd, "-object", backStr, "-device", dimmStr, NULL);
|
||||
|
||||
VIR_FREE(backStr);
|
||||
VIR_FREE(dimmStr);
|
||||
}
|
||||
}
|
||||
|
||||
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_UUID))
|
||||
virCommandAddArgList(cmd, "-uuid", uuid, NULL);
|
||||
if (def->virtType == VIR_DOMAIN_VIRT_XEN ||
|
||||
|
@ -1200,8 +1200,13 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
|
||||
}
|
||||
}
|
||||
|
||||
if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
|
||||
if (dev->type == VIR_DOMAIN_DEVICE_MEMORY &&
|
||||
def->mem.max_memory == 0) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("maxMemory has to be specified when using memory "
|
||||
"devices "));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
@ -2958,5 +2963,24 @@ qemuDomainAlignMemorySizes(virDomainDefPtr def)
|
||||
* We'll take the "traditional" path and round it to 1MiB*/
|
||||
def->mem.max_memory = VIR_ROUND_UP(def->mem.max_memory, 1024);
|
||||
|
||||
/* Align memory module sizes */
|
||||
for (i = 0; i < def->nmems; i++)
|
||||
qemuDomainMemoryDeviceAlignSize(def->mems[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qemuDomainMemoryDeviceAlignSize:
|
||||
* @mem: memory device definition object
|
||||
*
|
||||
* Aligns the size of the memory module as qemu enforces it. The size is updated
|
||||
* inplace. Default rounding is now to 1 MiB (qemu requires rouding to page,
|
||||
* size so this should be safe).
|
||||
*/
|
||||
void
|
||||
qemuDomainMemoryDeviceAlignSize(virDomainMemoryDefPtr mem)
|
||||
{
|
||||
mem->size = VIR_ROUND_UP(mem->size, 1024);
|
||||
}
|
||||
|
@ -423,5 +423,6 @@ bool qemuDomainDiskBlockJobIsActive(virDomainDiskDefPtr disk);
|
||||
void qemuDomObjEndAPI(virDomainObjPtr *vm);
|
||||
|
||||
int qemuDomainAlignMemorySizes(virDomainDefPtr def);
|
||||
void qemuDomainMemoryDeviceAlignSize(virDomainMemoryDefPtr mem);
|
||||
|
||||
#endif /* __QEMU_DOMAIN_H__ */
|
||||
|
11
tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.args
Normal file
11
tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.args
Normal file
@ -0,0 +1,11 @@
|
||||
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
|
||||
/usr/bin/qemu -S -M pc -m size=219136k,slots=16,maxmem=1099511627776k -smp 2 \
|
||||
-numa node,nodeid=0,cpus=0-1,mem=214 \
|
||||
-object memory-backend-ram,id=memdimm0,size=536870912 \
|
||||
-device pc-dimm,node=0,memdev=memdimm0,id=dimm0 \
|
||||
-object memory-backend-ram,id=memdimm1,size=536870912,host-nodes=1-3,\
|
||||
policy=bind \
|
||||
-device pc-dimm,node=0,memdev=memdimm1,id=dimm1 \
|
||||
-nographic -nodefaults -monitor unix:/tmp/test-monitor,server,nowait \
|
||||
-no-acpi -boot c -usb -hda /dev/HostVG/QEMUGuest1 \
|
||||
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
|
@ -1546,6 +1546,8 @@ mymain(void)
|
||||
DO_TEST_FAILURE("memory-hotplug-nonuma", QEMU_CAPS_DEVICE_PC_DIMM);
|
||||
DO_TEST_FAILURE("memory-hotplug", NONE);
|
||||
DO_TEST("memory-hotplug", QEMU_CAPS_DEVICE_PC_DIMM, QEMU_CAPS_NUMA);
|
||||
DO_TEST("memory-hotplug-dimm", QEMU_CAPS_DEVICE_PC_DIMM, QEMU_CAPS_NUMA,
|
||||
QEMU_CAPS_DEVICE, QEMU_CAPS_OBJECT_MEMORY_RAM);
|
||||
|
||||
virObjectUnref(driver.config);
|
||||
virObjectUnref(driver.caps);
|
||||
|
@ -430,6 +430,7 @@ mymain(void)
|
||||
|
||||
DO_TEST("memory-hotplug");
|
||||
DO_TEST("memory-hotplug-nonuma");
|
||||
DO_TEST("memory-hotplug-dimm");
|
||||
|
||||
virObjectUnref(driver.caps);
|
||||
virObjectUnref(driver.xmlopt);
|
||||
|
Loading…
x
Reference in New Issue
Block a user