提交 1bc17319 编写于 作者: M Michal Privoznik

qemu: Implement NVDIMM

So, majority of the code is just ready as-is. Well, with one
slight change: differentiate between dimm and nvdimm in places
like device alias generation, generating the command line and so
on.

Speaking of the command line, we also need to append 'nvdimm=on'
to the '-machine' argument so that the nvdimm feature is
advertised in the ACPI tables properly.
Signed-off-by: NMichal Privoznik <mprivozn@redhat.com>
上级 e21250de
......@@ -352,17 +352,23 @@ qemuAssignDeviceMemoryAlias(virDomainDefPtr def,
size_t i;
int maxidx = 0;
int idx;
const char *prefix;
if (mem->model == VIR_DOMAIN_MEMORY_MODEL_DIMM)
prefix = "dimm";
else
prefix = "nvdimm";
if (oldAlias) {
for (i = 0; i < def->nmems; i++) {
if ((idx = qemuDomainDeviceAliasIndex(&def->mems[i]->info, "dimm")) >= maxidx)
if ((idx = qemuDomainDeviceAliasIndex(&def->mems[i]->info, prefix)) >= maxidx)
maxidx = idx + 1;
}
} else {
maxidx = mem->info.addr.dimm.slot;
}
if (virAsprintf(&mem->info.alias, "dimm%d", maxidx) < 0)
if (virAsprintf(&mem->info.alias, "%s%d", prefix, maxidx) < 0)
return -1;
return 0;
......
......@@ -3217,7 +3217,8 @@ qemuBuildMemoryBackendStr(virJSONValuePtr *backendProps,
const long system_page_size = virGetSystemPageSizeKB();
virDomainMemoryAccess memAccess = VIR_DOMAIN_MEMORY_ACCESS_DEFAULT;
size_t i;
char *mem_path = NULL;
char *memPath = NULL;
bool prealloc = false;
virBitmapPtr nodemask = NULL;
int ret = -1;
virJSONValuePtr props = NULL;
......@@ -3298,26 +3299,31 @@ qemuBuildMemoryBackendStr(virJSONValuePtr *backendProps,
if (!(props = virJSONValueNewObject()))
return -1;
if (pagesize || def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE) {
if (pagesize || mem->nvdimmPath ||
def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE) {
*backendType = "memory-backend-file";
if (def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE) {
/* we can have both pagesize and mem source, then check mem source first */
if (virJSONValueObjectAdd(props,
"s:mem-path", cfg->memoryBackingDir,
NULL) < 0)
if (mem->nvdimmPath) {
if (VIR_STRDUP(memPath, mem->nvdimmPath) < 0)
goto cleanup;
} else {
if (qemuGetDomainHupageMemPath(def, cfg, pagesize, &mem_path) < 0)
prealloc = true;
} else if (def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE) {
/* We can have both pagesize and mem source,
* then check mem source first. */
if (VIR_STRDUP(memPath, cfg->memoryBackingDir) < 0)
goto cleanup;
if (virJSONValueObjectAdd(props,
"b:prealloc", true,
"s:mem-path", mem_path,
NULL) < 0)
} else {
if (qemuGetDomainHupageMemPath(def, cfg, pagesize, &memPath) < 0)
goto cleanup;
prealloc = true;
}
if (virJSONValueObjectAdd(props,
"B:prealloc", prealloc,
"s:mem-path", memPath,
NULL) < 0)
goto cleanup;
switch (memAccess) {
case VIR_DOMAIN_MEMORY_ACCESS_SHARED:
if (virJSONValueObjectAdd(props, "b:share", true, NULL) < 0)
......@@ -3373,6 +3379,7 @@ qemuBuildMemoryBackendStr(virJSONValuePtr *backendProps,
/* If none of the following is requested... */
if (!needHugepage && !mem->sourceNodes && !nodeSpecified &&
!mem->nvdimmPath &&
memAccess == VIR_DOMAIN_MEMORY_ACCESS_DEFAULT &&
def->mem.source != VIR_DOMAIN_MEMORY_SOURCE_FILE && !force) {
/* report back that using the new backend is not necessary
......@@ -3402,8 +3409,7 @@ qemuBuildMemoryBackendStr(virJSONValuePtr *backendProps,
cleanup:
virJSONValueFree(props);
VIR_FREE(mem_path);
VIR_FREE(memPath);
return ret;
}
......@@ -3490,6 +3496,7 @@ char *
qemuBuildMemoryDeviceStr(virDomainMemoryDefPtr mem)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
const char *device;
if (!mem->info.alias) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
......@@ -3498,8 +3505,15 @@ qemuBuildMemoryDeviceStr(virDomainMemoryDefPtr mem)
}
switch ((virDomainMemoryModel) mem->model) {
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
virBufferAddLit(&buf, "pc-dimm,");
if (mem->model == VIR_DOMAIN_MEMORY_MODEL_DIMM)
device = "pc-dimm";
else
device = "nvdimm";
virBufferAsprintf(&buf, "%s,", device);
if (mem->targetNode >= 0)
virBufferAsprintf(&buf, "node=%d,", mem->targetNode);
......@@ -3515,12 +3529,6 @@ qemuBuildMemoryDeviceStr(virDomainMemoryDefPtr mem)
break;
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
virReportError(VIR_ERR_NO_SUPPORT, "%s",
_("nvdimm not supported yet"));
return NULL;
break;
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
......@@ -7071,6 +7079,7 @@ qemuBuildMachineCommandLine(virCommandPtr cmd,
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
bool obsoleteAccel = false;
size_t i;
int ret = -1;
/* This should *never* be NULL, since we always provide
......@@ -7107,6 +7116,15 @@ qemuBuildMachineCommandLine(virCommandPtr cmd,
"with this QEMU binary"));
return -1;
}
for (i = 0; i < def->nmems; i++) {
if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("nvdimm not is not available "
"with this QEMU binary"));
return -1;
}
}
} else {
virTristateSwitch vmport = def->features[VIR_DOMAIN_FEATURE_VMPORT];
virTristateSwitch smm = def->features[VIR_DOMAIN_FEATURE_SMM];
......@@ -7227,6 +7245,18 @@ qemuBuildMachineCommandLine(virCommandPtr cmd,
}
}
for (i = 0; i < def->nmems; i++) {
if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_NVDIMM)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("nvdimm isn't supported by this QEMU binary"));
goto cleanup;
}
virBufferAddLit(&buf, ",nvdimm=on");
break;
}
}
virCommandAddArgBuffer(cmd, &buf);
}
......
......@@ -5935,6 +5935,7 @@ qemuDomainDefValidateMemoryHotplugDevice(const virDomainMemoryDef *mem,
{
switch ((virDomainMemoryModel) mem->model) {
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
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",
......@@ -5967,11 +5968,6 @@ qemuDomainDefValidateMemoryHotplugDevice(const virDomainMemoryDef *mem,
}
break;
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("nvdimm hotplug not supported yet"));
return -1;
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
return -1;
......@@ -6002,6 +5998,8 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def,
unsigned int nmems = def->nmems;
unsigned long long hotplugSpace;
unsigned long long hotplugMemory = 0;
bool needPCDimmCap = false;
bool needNvdimmCap = false;
size_t i;
hotplugSpace = def->mem.max_memory - virDomainDefGetMemoryInitial(def);
......@@ -6025,12 +6023,6 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def,
return 0;
}
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PC_DIMM)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("memory hotplug isn't supported by this QEMU binary"));
return -1;
}
if (!ARCH_IS_PPC64(def->os.arch)) {
/* due to guest support, qemu would silently enable NUMA with one node
* once the memory hotplug backend is enabled. To avoid possible
......@@ -6054,12 +6046,40 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def,
for (i = 0; i < def->nmems; i++) {
hotplugMemory += def->mems[i]->size;
switch ((virDomainMemoryModel) def->mems[i]->model) {
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
needPCDimmCap = true;
break;
case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
needNvdimmCap = true;
break;
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
}
/* already existing devices don't need to be checked on hotplug */
if (!mem &&
qemuDomainDefValidateMemoryHotplugDevice(def->mems[i], def) < 0)
return -1;
}
if (needPCDimmCap &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PC_DIMM)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("memory hotplug isn't supported by this QEMU binary"));
return -1;
}
if (needNvdimmCap &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_NVDIMM)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("nvdimm isn't supported by this QEMU binary"));
return -1;
}
if (hotplugMemory > hotplugSpace) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("memory device total size exceeds hotplug space"));
......
LC_ALL=C \
PATH=/bin \
HOME=/home/test \
USER=test \
LOGNAME=test \
QEMU_AUDIO_DRV=none \
/usr/bin/qemu \
-name QEMUGuest1 \
-S \
-machine pc,accel=tcg,nvdimm=on \
-m size=1048576k,slots=16,maxmem=1099511627776k \
-smp 2,sockets=2,cores=1,threads=1 \
-numa node,nodeid=0,cpus=0-1,mem=1024 \
-object memory-backend-file,id=memnvdimm0,prealloc=yes,mem-path=/tmp/nvdimm,\
size=536870912 \
-device nvdimm,node=0,memdev=memnvdimm0,id=nvdimm0,slot=0 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-nographic \
-nodefaults \
-monitor unix:/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server,nowait \
-no-acpi \
-boot c \
-usb \
-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \
-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
......@@ -2326,7 +2326,7 @@ mymain(void)
DO_TEST_FAILURE("memory-align-fail", NONE);
DO_TEST_FAILURE("memory-hotplug-nonuma", QEMU_CAPS_DEVICE_PC_DIMM);
DO_TEST_FAILURE("memory-hotplug", NONE);
DO_TEST("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_OBJECT_MEMORY_RAM, QEMU_CAPS_OBJECT_MEMORY_FILE);
......@@ -2334,6 +2334,8 @@ mymain(void)
QEMU_CAPS_OBJECT_MEMORY_RAM, QEMU_CAPS_OBJECT_MEMORY_FILE);
DO_TEST("memory-hotplug-ppc64-nonuma", QEMU_CAPS_KVM, QEMU_CAPS_DEVICE_PC_DIMM, QEMU_CAPS_NUMA,
QEMU_CAPS_OBJECT_MEMORY_RAM, QEMU_CAPS_OBJECT_MEMORY_FILE);
DO_TEST("memory-hotplug-nvdimm", QEMU_CAPS_MACHINE_OPT, QEMU_CAPS_DEVICE_NVDIMM,
QEMU_CAPS_NUMA, QEMU_CAPS_OBJECT_MEMORY_RAM, QEMU_CAPS_OBJECT_MEMORY_FILE);
DO_TEST("machine-aeskeywrap-on-caps",
QEMU_CAPS_MACHINE_OPT, QEMU_CAPS_AES_KEY_WRAP,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册