Reorganize the module to put all the -numa argument processing code
together after the IOThread to form a logical order of processing for
qemuBuildCommandLine working top down in the module
This includes moving the memory cell/dimm and generic object code.
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
src/qemu/qemu_command.c | 4216 ++++++++++++++++++++++++-----------------------
1 file changed, 2119 insertions(+), 2097 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 3000e8f..af4e63f 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1071,6 +1071,9 @@ qemuBuildIOThreadCommandLine(virCommandPtr cmd,
}
+/* Generic -object builder for dynamic memory cell/dimm (with -numa) or
+ * the RNG backend
+ */
static int
qemuBuildObjectCommandLinePropsInternal(const char *key,
const virJSONValue *value,
@@ -1181,2380 +1184,2565 @@ qemuBuildObjectCommandlineFromJSON(const char *type,
}
-static int
-qemuBuildDeviceAddressStr(virBufferPtr buf,
- virDomainDefPtr domainDef,
- virDomainDeviceInfoPtr info,
- virQEMUCapsPtr qemuCaps)
+/** Start numa and memory dimm arguments */
+/**
+ * qemuBuildMemoryBackendStr:
+ * @size: size of the memory device in kibibytes
+ * @pagesize: size of the requested memory page in KiB, 0 for default
+ * @guestNode: NUMA node in the guest that the memory object will be attached
+ * to, or -1 if NUMA is not used in the guest
+ * @hostNodes: map of host nodes to alloc the memory in, NULL for default
+ * @autoNodeset: fallback nodeset in case of automatic numa placement
+ * @def: domain definition object
+ * @qemuCaps: qemu capabilities object
+ * @cfg: qemu driver config object
+ * @aliasPrefix: prefix string of the alias (to allow for multiple frontents)
+ * @id: index of the device (to construct the alias)
+ * @backendStr: returns the object string
+ *
+ * Formats the configuration string for the memory device backend according
+ * to the configuration. @pagesize and @hostNodes can be used to override the
+ * default source configuration, both are optional.
+ *
+ * Returns 0 on success, 1 if only the implicit memory-device-ram with no
+ * other configuration was used (to detect legacy configurations). Returns
+ * -1 in case of an error.
+ */
+int
+qemuBuildMemoryBackendStr(unsigned long long size,
+ unsigned long long pagesize,
+ int guestNode,
+ virBitmapPtr userNodeset,
+ virBitmapPtr autoNodeset,
+ virDomainDefPtr def,
+ virQEMUCapsPtr qemuCaps,
+ virQEMUDriverConfigPtr cfg,
+ const char **backendType,
+ virJSONValuePtr *backendProps,
+ bool force)
{
+ virDomainHugePagePtr master_hugepage = NULL;
+ virDomainHugePagePtr hugepage = NULL;
+ virDomainNumatuneMemMode mode;
+ const long system_page_size = virGetSystemPageSizeKB();
+ virNumaMemAccess memAccess = VIR_NUMA_MEM_ACCESS_DEFAULT;
+ size_t i;
+ char *mem_path = NULL;
+ virBitmapPtr nodemask = NULL;
int ret = -1;
- char *devStr = NULL;
- const char *contAlias = NULL;
+ virJSONValuePtr props = NULL;
+ bool nodeSpecified = virDomainNumatuneNodeSpecified(def->numa, guestNode);
- if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
- size_t i;
+ *backendProps = NULL;
+ *backendType = NULL;
- if (!(devStr = virDomainPCIAddressAsString(&info->addr.pci)))
- goto cleanup;
- for (i = 0; i < domainDef->ncontrollers; i++) {
- virDomainControllerDefPtr cont = domainDef->controllers[i];
+ if (guestNode >= 0) {
+ /* 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 (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI &&
- cont->idx == info->addr.pci.bus) {
- contAlias = cont->info.alias;
- if (!contAlias) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Device alias was not set for PCI "
- "controller with index %u required "
- "for device at address %s"),
- info->addr.pci.bus, devStr);
- goto cleanup;
- }
+ memAccess = virDomainNumaGetNodeMemoryAccessMode(def->numa, guestNode);
+ }
+
+ if (virDomainNumatuneGetMode(def->numa, guestNode, &mode) < 0 &&
+ virDomainNumatuneGetMode(def->numa, -1, &mode) < 0)
+ mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
+
+ if (pagesize == 0) {
+ /* Find the huge page size we want to use */
+ for (i = 0; i < def->mem.nhugepages; i++) {
+ bool thisHugepage = false;
+
+ hugepage = &def->mem.hugepages[i];
+
+ if (!hugepage->nodemask) {
+ master_hugepage = hugepage;
+ continue;
+ }
+
+ /* just find the master hugepage in case we don't use NUMA */
+ if (guestNode < 0)
+ continue;
+
+ if (virBitmapGetBit(hugepage->nodemask, guestNode,
+ &thisHugepage) < 0) {
+ /* Ignore this error. It's not an error after all. Well,
+ * the nodemask for this <page/> can contain lower NUMA
+ * nodes than we are querying in here. */
+ continue;
+ }
+
+ if (thisHugepage) {
+ /* Hooray, we've found the page size */
break;
}
}
- if (!contAlias) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Could not find PCI "
- "controller with index %u required "
- "for device at address %s"),
- info->addr.pci.bus, devStr);
- goto cleanup;
+
+ if (i == def->mem.nhugepages) {
+ /* We have not found specific huge page to be used with this
+ * NUMA node. Use the generic setting then (<page/> without any
+ * @nodemask) if possible. */
+ hugepage = master_hugepage;
}
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_MULTIFUNCTION)) {
- if (info->addr.pci.function != 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Only PCI device addresses with function=0 "
- "are supported with this QEMU binary"));
- goto cleanup;
+ if (hugepage)
+ pagesize = hugepage->size;
+ }
+
+ if (pagesize == system_page_size) {
+ /* However, if user specified to use "huge" page
+ * of regular system page size, it's as if they
+ * hasn't specified any huge pages at all. */
+ pagesize = 0;
+ hugepage = NULL;
+ }
+
+ if (!(props = virJSONValueNewObject()))
+ return -1;
+
+ if (pagesize || hugepage) {
+ if (pagesize) {
+ /* Now lets see, if the huge page we want to use is even mounted
+ * and ready to use */
+ for (i = 0; i < cfg->nhugetlbfs; i++) {
+ if (cfg->hugetlbfs[i].size == pagesize)
+ break;
}
- if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("'multifunction=on' is not supported with
"
- "this QEMU binary"));
+
+ if (i == cfg->nhugetlbfs) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to find any usable hugetlbfs mount for %llu
KiB"),
+ pagesize);
goto cleanup;
}
+
+ if (!(mem_path = qemuGetHugepagePath(&cfg->hugetlbfs[i])))
+ goto cleanup;
+ } else {
+ if (!(mem_path = qemuGetDefaultHugepath(cfg->hugetlbfs,
+ cfg->nhugetlbfs)))
+ goto cleanup;
}
- if (info->addr.pci.bus != 0 &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
+ *backendType = "memory-backend-file";
+
+ if (virJSONValueObjectAdd(props,
+ "b:prealloc", true,
+ "s:mem-path", mem_path,
+ NULL) < 0)
+ goto cleanup;
+
+ switch (memAccess) {
+ case VIR_NUMA_MEM_ACCESS_SHARED:
+ if (virJSONValueObjectAdd(props, "b:share", true, NULL) < 0)
+ goto cleanup;
+ break;
+
+ case VIR_NUMA_MEM_ACCESS_PRIVATE:
+ if (virJSONValueObjectAdd(props, "b:share", false, NULL) < 0)
+ goto cleanup;
+ break;
+
+ case VIR_NUMA_MEM_ACCESS_DEFAULT:
+ case VIR_NUMA_MEM_ACCESS_LAST:
+ break;
+ }
+ } else {
+ if (memAccess) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Multiple PCI buses are not supported "
- "with this QEMU binary"));
+ _("Shared memory mapping is supported "
+ "only with hugepages"));
goto cleanup;
}
- virBufferAsprintf(buf, ",bus=%s", contAlias);
- if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON)
- virBufferAddLit(buf, ",multifunction=on");
- else if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_OFF)
- virBufferAddLit(buf, ",multifunction=off");
- virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot);
- if (info->addr.pci.function != 0)
- virBufferAsprintf(buf, ".0x%x", info->addr.pci.function);
- } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
- if (!(contAlias = virDomainControllerAliasFind(domainDef,
- VIR_DOMAIN_CONTROLLER_TYPE_USB,
- info->addr.usb.bus)))
+ *backendType = "memory-backend-ram";
+ }
+
+ if (virJSONValueObjectAdd(props, "U:size", size * 1024, NULL) < 0)
+ goto cleanup;
+
+ if (userNodeset) {
+ nodemask = userNodeset;
+ } else {
+ if (virDomainNumatuneMaybeGetNodeset(def->numa, autoNodeset,
+ &nodemask, guestNode) < 0)
goto cleanup;
- virBufferAsprintf(buf, ",bus=%s.0,port=%s", contAlias,
info->addr.usb.port);
- } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO) {
- if (info->addr.spaprvio.has_reg)
- virBufferAsprintf(buf, ",reg=0x%llx", info->addr.spaprvio.reg);
- } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
- if (info->addr.ccw.assigned)
- virBufferAsprintf(buf, ",devno=%x.%x.%04x",
- info->addr.ccw.cssid,
- info->addr.ccw.ssid,
- info->addr.ccw.devno);
- } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA) {
- virBufferAsprintf(buf, ",iobase=0x%x,irq=0x%x",
- info->addr.isa.iobase,
- info->addr.isa.irq);
}
- ret = 0;
- cleanup:
- VIR_FREE(devStr);
- return ret;
-}
+ if (nodemask) {
+ if (!virNumaNodesetIsAvailable(nodemask))
+ goto cleanup;
+ if (virJSONValueObjectAdd(props,
+ "m:host-nodes", nodemask,
+ "S:policy",
qemuNumaPolicyTypeToString(mode),
+ NULL) < 0)
+ goto cleanup;
+ }
-static int
-qemuBuildRomStr(virBufferPtr buf,
- virDomainDeviceInfoPtr info,
- virQEMUCapsPtr qemuCaps)
-{
- if (info->rombar || info->romfile) {
- if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- "%s", _("rombar and romfile are supported only
for PCI devices"));
- return -1;
- }
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_ROMBAR)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- "%s", _("rombar and romfile not supported in
this QEMU binary"));
- return -1;
+ /* If none of the following is requested... */
+ if (!pagesize && !userNodeset && !memAccess && !nodeSpecified
&& !force) {
+ /* report back that using the new backend is not necessary
+ * to achieve the desired configuration */
+ ret = 1;
+ } else {
+ /* otherwise check the required capability */
+ if (STREQ(*backendType, "memory-backend-file") &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("this qemu doesn't support the "
+ "memory-backend-file object"));
+ goto cleanup;
+ } else if (STREQ(*backendType, "memory-backend-ram") &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("this qemu doesn't support the "
+ "memory-backend-ram object"));
+ goto cleanup;
}
- switch (info->rombar) {
- case VIR_TRISTATE_SWITCH_OFF:
- virBufferAddLit(buf, ",rombar=0");
- break;
- case VIR_TRISTATE_SWITCH_ON:
- virBufferAddLit(buf, ",rombar=1");
- break;
- default:
- break;
- }
- if (info->romfile)
- virBufferAsprintf(buf, ",romfile=%s", info->romfile);
+ ret = 0;
}
- return 0;
-}
-static int
-qemuBuildIoEventFdStr(virBufferPtr buf,
- virTristateSwitch use,
- virQEMUCapsPtr qemuCaps)
-{
- if (use && virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_IOEVENTFD))
- virBufferAsprintf(buf, ",ioeventfd=%s",
- virTristateSwitchTypeToString(use));
- return 0;
+ *backendProps = props;
+ props = NULL;
+
+ cleanup:
+ virJSONValueFree(props);
+ VIR_FREE(mem_path);
+
+ return ret;
}
-#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_ "
static int
-qemuSafeSerialParamValue(const char *value)
+qemuBuildMemoryCellBackendStr(virDomainDefPtr def,
+ virQEMUCapsPtr qemuCaps,
+ virQEMUDriverConfigPtr cfg,
+ size_t cell,
+ virBitmapPtr auto_nodeset,
+ char **backendStr)
{
- if (strspn(value, QEMU_SERIAL_PARAM_ACCEPTED_CHARS) != strlen(value)) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("driver serial '%s' contains unsafe
characters"),
- value);
- return -1;
- }
+ virJSONValuePtr props = NULL;
+ char *alias = NULL;
+ const char *backendType;
+ int ret = -1;
+ int rc;
+ unsigned long long memsize = virDomainNumaGetNodeMemorySize(def->numa,
+ cell);
- return 0;
+ *backendStr = NULL;
+
+ if (virAsprintf(&alias, "ram-node%zu", cell) < 0)
+ goto cleanup;
+
+ if ((rc = qemuBuildMemoryBackendStr(memsize, 0, cell, NULL, auto_nodeset,
+ def, qemuCaps, cfg, &backendType,
+ &props, false)) < 0)
+ goto cleanup;
+
+ if (!(*backendStr = qemuBuildObjectCommandlineFromJSON(backendType,
+ alias,
+ props)))
+ goto cleanup;
+
+ ret = rc;
+
+ cleanup:
+ VIR_FREE(alias);
+ virJSONValueFree(props);
+
+ return ret;
}
+
static char *
-qemuGetSecretString(virConnectPtr conn,
- const char *scheme,
- bool encoded,
- virStorageAuthDefPtr authdef,
- virSecretUsageType secretUsageType)
+qemuBuildMemoryDimmBackendStr(virDomainMemoryDefPtr mem,
+ virDomainDefPtr def,
+ virQEMUCapsPtr qemuCaps,
+ virQEMUDriverConfigPtr cfg)
{
- size_t secret_size;
- virSecretPtr sec = NULL;
- char *secret = NULL;
- char uuidStr[VIR_UUID_STRING_BUFLEN];
+ virJSONValuePtr props = NULL;
+ char *alias = NULL;
+ const char *backendType;
+ char *ret = NULL;
- /* look up secret */
- switch (authdef->secretType) {
- case VIR_STORAGE_SECRET_TYPE_UUID:
- sec = virSecretLookupByUUID(conn, authdef->secret.uuid);
- virUUIDFormat(authdef->secret.uuid, uuidStr);
- break;
- case VIR_STORAGE_SECRET_TYPE_USAGE:
- sec = virSecretLookupByUsage(conn, secretUsageType,
- authdef->secret.usage);
- break;
+ if (!mem->info.alias) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("memory device alias is not assigned"));
+ return NULL;
}
- if (!sec) {
- if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
- virReportError(VIR_ERR_NO_SECRET,
- _("%s no secret matches uuid '%s'"),
- scheme, uuidStr);
- } else {
- virReportError(VIR_ERR_NO_SECRET,
- _("%s no secret matches usage value '%s'"),
- scheme, authdef->secret.usage);
- }
+ if (virAsprintf(&alias, "mem%s", mem->info.alias) < 0)
goto cleanup;
- }
- secret = (char *)conn->secretDriver->secretGetValue(sec, &secret_size, 0,
-
VIR_SECRET_GET_VALUE_INTERNAL_CALL);
- if (!secret) {
- if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("could not get value of the secret for "
- "username '%s' using uuid '%s'"),
- authdef->username, uuidStr);
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("could not get value of the secret for "
- "username '%s' using usage value
'%s'"),
- authdef->username, authdef->secret.usage);
- }
+ if (qemuBuildMemoryBackendStr(mem->size, mem->pagesize,
+ mem->targetNode, mem->sourceNodes, NULL,
+ def, qemuCaps, cfg,
+ &backendType, &props, true) < 0)
goto cleanup;
- }
-
- if (encoded) {
- char *base64 = NULL;
- base64_encode_alloc(secret, secret_size, &base64);
- VIR_FREE(secret);
- if (!base64) {
- virReportOOMError();
- goto cleanup;
- }
- secret = base64;
- }
+ ret = qemuBuildObjectCommandlineFromJSON(backendType, alias, props);
cleanup:
- virObjectUnref(sec);
- return secret;
+ VIR_FREE(alias);
+ virJSONValueFree(props);
+
+ return ret;
}
-static int
-qemuNetworkDriveGetPort(int protocol,
- const char *port)
+char *
+qemuBuildMemoryDeviceStr(virDomainMemoryDefPtr mem)
{
- int ret = 0;
-
- if (port) {
- if (virStrToLong_i(port, NULL, 10, &ret) < 0 || ret < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("failed to parse port number '%s'"),
- port);
- return -1;
- }
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
- return ret;
+ if (!mem->info.alias) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing alias for memory device"));
+ return NULL;
}
- switch ((virStorageNetProtocol) protocol) {
- case VIR_STORAGE_NET_PROTOCOL_HTTP:
- return 80;
-
- case VIR_STORAGE_NET_PROTOCOL_HTTPS:
- return 443;
-
- case VIR_STORAGE_NET_PROTOCOL_FTP:
- return 21;
+ switch ((virDomainMemoryModel) mem->model) {
+ case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+ virBufferAddLit(&buf, "pc-dimm,");
- case VIR_STORAGE_NET_PROTOCOL_FTPS:
- return 990;
+ if (mem->targetNode >= 0)
+ virBufferAsprintf(&buf, "node=%d,", mem->targetNode);
- case VIR_STORAGE_NET_PROTOCOL_TFTP:
- return 69;
+ virBufferAsprintf(&buf, "memdev=mem%s,id=%s",
+ mem->info.alias, mem->info.alias);
- case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
- return 7000;
+ if (mem->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM) {
+ virBufferAsprintf(&buf, ",slot=%d",
mem->info.addr.dimm.slot);
+ virBufferAsprintf(&buf, ",addr=%llu",
mem->info.addr.dimm.base);
+ }
- case VIR_STORAGE_NET_PROTOCOL_NBD:
- return 10809;
+ break;
- case VIR_STORAGE_NET_PROTOCOL_ISCSI:
- case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
- /* no default port specified */
- return 0;
+ case VIR_DOMAIN_MEMORY_MODEL_NONE:
+ case VIR_DOMAIN_MEMORY_MODEL_LAST:
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("invalid memory device type"));
+ break;
- case VIR_STORAGE_NET_PROTOCOL_RBD:
- case VIR_STORAGE_NET_PROTOCOL_LAST:
- case VIR_STORAGE_NET_PROTOCOL_NONE:
- /* not applicable */
- return -1;
}
- return -1;
-}
+ if (virBufferCheckError(&buf) < 0)
+ return NULL;
-#define QEMU_DEFAULT_NBD_PORT "10809"
+ return virBufferContentAndReset(&buf);
+}
-static char *
-qemuBuildNetworkDriveURI(virStorageSourcePtr src,
- const char *username,
- const char *secret)
+
+static int
+qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg,
+ virDomainDefPtr def,
+ virCommandPtr cmd,
+ virQEMUCapsPtr qemuCaps,
+ virBitmapPtr auto_nodeset)
{
- char *ret = NULL;
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- virURIPtr uri = NULL;
size_t i;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char *cpumask = NULL, *tmpmask = NULL, *next = NULL;
+ char **nodeBackends = NULL;
+ bool needBackend = false;
+ int rc;
+ int ret = -1;
+ size_t ncells = virDomainNumaGetNodeCount(def->numa);
+ const long system_page_size = virGetSystemPageSizeKB();
- switch ((virStorageNetProtocol) src->protocol) {
- case VIR_STORAGE_NET_PROTOCOL_NBD:
- if (src->nhosts != 1) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("protocol '%s' accepts only one
host"),
- virStorageNetProtocolTypeToString(src->protocol));
- goto cleanup;
- }
-
- if (!((src->hosts->name && strchr(src->hosts->name,
':')) ||
- (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP
&&
- !src->hosts->name) ||
- (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_UNIX
&&
- src->hosts->socket &&
- src->hosts->socket[0] != '/'))) {
+ if (virDomainNumatuneHasPerNodeBinding(def->numa) &&
+ !(virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM) ||
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Per-node memory binding is not supported "
+ "with this QEMU"));
+ goto cleanup;
+ }
- virBufferAddLit(&buf, "nbd:");
+ if (def->mem.nhugepages &&
+ def->mem.hugepages[0].size != system_page_size &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("huge pages per NUMA node are not "
+ "supported with this QEMU"));
+ goto cleanup;
+ }
- switch (src->hosts->transport) {
- case VIR_STORAGE_NET_HOST_TRANS_TCP:
- virBufferStrcat(&buf, src->hosts->name, NULL);
- virBufferAsprintf(&buf, ":%s",
- src->hosts->port ? src->hosts->port :
- QEMU_DEFAULT_NBD_PORT);
- break;
+ if (!virDomainNumatuneNodesetIsAvailable(def->numa, auto_nodeset))
+ goto cleanup;
- case VIR_STORAGE_NET_HOST_TRANS_UNIX:
- if (!src->hosts->socket) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("socket attribute required for "
- "unix transport"));
- goto cleanup;
- }
+ for (i = 0; i < def->mem.nhugepages; i++) {
+ ssize_t next_bit, pos = 0;
- virBufferAsprintf(&buf, "unix:%s",
src->hosts->socket);
- break;
+ if (!def->mem.hugepages[i].nodemask) {
+ /* This is the master hugepage to use. Skip it as it has no
+ * nodemask anyway. */
+ continue;
+ }
- default:
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("nbd does not support transport
'%s'"),
-
virStorageNetHostTransportTypeToString(src->hosts->transport));
- goto cleanup;
- }
+ if (ncells) {
+ /* Fortunately, we allow only guest NUMA nodes to be continuous
+ * starting from zero. */
+ pos = ncells - 1;
+ }
- if (src->path)
- virBufferAsprintf(&buf, ":exportname=%s",
src->path);
+ next_bit = virBitmapNextSetBit(def->mem.hugepages[i].nodemask, pos);
+ if (next_bit >= 0) {
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("hugepages: node %zd not found"),
+ next_bit);
+ goto cleanup;
+ }
+ }
- if (virBufferCheckError(&buf) < 0)
- goto cleanup;
+ if (VIR_ALLOC_N(nodeBackends, ncells) < 0)
+ goto cleanup;
- ret = virBufferContentAndReset(&buf);
+ /* using of -numa memdev= cannot be combined with -numa mem=, thus we
+ * need to check which approach to use */
+ for (i = 0; i < ncells; i++) {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM) ||
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) {
+ if ((rc = qemuBuildMemoryCellBackendStr(def, qemuCaps, cfg, i,
+ auto_nodeset,
+ &nodeBackends[i])) < 0)
goto cleanup;
- }
- /* fallthrough */
- /* NBD code uses same formatting scheme as others in some cases */
- case VIR_STORAGE_NET_PROTOCOL_HTTP:
- case VIR_STORAGE_NET_PROTOCOL_HTTPS:
- case VIR_STORAGE_NET_PROTOCOL_FTP:
- case VIR_STORAGE_NET_PROTOCOL_FTPS:
- case VIR_STORAGE_NET_PROTOCOL_TFTP:
- case VIR_STORAGE_NET_PROTOCOL_ISCSI:
- case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
- if (src->nhosts != 1) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("protocol '%s' accepts only one
host"),
- virStorageNetProtocolTypeToString(src->protocol));
+ if (rc == 0)
+ needBackend = true;
+ } else {
+ if (virDomainNumaGetNodeMemoryAccessMode(def->numa, i)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Shared memory mapping is not supported "
+ "with this QEMU"));
goto cleanup;
}
+ }
+ }
- if (VIR_ALLOC(uri) < 0)
- goto cleanup;
+ if (!needBackend &&
+ qemuBuildMemPathStr(cfg, def, qemuCaps, cmd) < 0)
+ goto cleanup;
- if (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP) {
- if (VIR_STRDUP(uri->scheme,
- virStorageNetProtocolTypeToString(src->protocol)) <
0)
- goto cleanup;
- } else {
- if (virAsprintf(&uri->scheme, "%s+%s",
- virStorageNetProtocolTypeToString(src->protocol),
-
virStorageNetHostTransportTypeToString(src->hosts->transport)) < 0)
- goto cleanup;
- }
+ for (i = 0; i < ncells; i++) {
+ VIR_FREE(cpumask);
+ if (!(cpumask =
+ virBitmapFormat(virDomainNumaGetNodeCpumask(def->numa, i))))
+ goto cleanup;
- if ((uri->port = qemuNetworkDriveGetPort(src->protocol,
src->hosts->port)) < 0)
- goto cleanup;
+ if (strchr(cpumask, ',') &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_NUMA)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("disjoint NUMA cpu ranges are not supported "
+ "with this QEMU"));
+ goto cleanup;
+ }
- if (src->path) {
- if (src->volume) {
- if (virAsprintf(&uri->path, "/%s%s",
- src->volume, src->path) < 0)
- goto cleanup;
- } else {
- if (virAsprintf(&uri->path, "%s%s",
- src->path[0] == '/' ? "" :
"/",
- src->path) < 0)
- goto cleanup;
- }
- }
+ if (needBackend)
+ virCommandAddArgList(cmd, "-object", nodeBackends[i], NULL);
- if (src->hosts->socket &&
- virAsprintf(&uri->query, "socket=%s",
src->hosts->socket) < 0)
- goto cleanup;
+ virCommandAddArg(cmd, "-numa");
+ virBufferAsprintf(&buf, "node,nodeid=%zu", i);
- if (username) {
- if (secret) {
- if (virAsprintf(&uri->user, "%s:%s", username,
secret) < 0)
- goto cleanup;
- } else {
- if (VIR_STRDUP(uri->user, username) < 0)
- goto cleanup;
- }
- }
+ for (tmpmask = cpumask; tmpmask; tmpmask = next) {
+ if ((next = strchr(tmpmask, ',')))
+ *(next++) = '\0';
+ virBufferAddLit(&buf, ",cpus=");
+ virBufferAdd(&buf, tmpmask, -1);
+ }
- if (VIR_STRDUP(uri->server, src->hosts->name) < 0)
- goto cleanup;
+ if (needBackend)
+ virBufferAsprintf(&buf, ",memdev=ram-node%zu", i);
+ else
+ virBufferAsprintf(&buf, ",mem=%llu",
+ virDomainNumaGetNodeMemorySize(def->numa, i) / 1024);
- ret = virURIFormat(uri);
+ virCommandAddArgBuffer(cmd, &buf);
+ }
+ ret = 0;
- break;
+ cleanup:
+ VIR_FREE(cpumask);
- case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
- if (!src->path) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("missing disk source for 'sheepdog'
protocol"));
- goto cleanup;
- }
+ if (nodeBackends) {
+ for (i = 0; i < ncells; i++)
+ VIR_FREE(nodeBackends[i]);
- if (src->nhosts == 0) {
- if (virAsprintf(&ret, "sheepdog:%s", src->path) < 0)
- goto cleanup;
- } else if (src->nhosts == 1) {
- if (virAsprintf(&ret, "sheepdog:%s:%s:%s",
- src->hosts->name,
- src->hosts->port ? src->hosts->port :
"7000",
- src->path) < 0)
- goto cleanup;
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("protocol 'sheepdog' accepts up to one
host"));
- goto cleanup;
- }
+ VIR_FREE(nodeBackends);
+ }
- break;
+ virBufferFreeAndReset(&buf);
+ return ret;
+}
- case VIR_STORAGE_NET_PROTOCOL_RBD:
- if (strchr(src->path, ':')) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("':' not allowed in RBD source volume name
'%s'"),
- src->path);
- goto cleanup;
- }
- virBufferStrcat(&buf, "rbd:", src->path, NULL);
+static int
+qemuBuildNumaCommandLine(virCommandPtr cmd,
+ virQEMUDriverConfigPtr cfg,
+ virDomainDefPtr def,
+ virQEMUCapsPtr qemuCaps,
+ virBitmapPtr nodeset)
+{
+ size_t i;
- if (src->snapshot)
- virBufferEscape(&buf, '\\', ":", "@%s",
src->snapshot);
-
- if (username) {
- virBufferEscape(&buf, '\\', ":",
":id=%s", username);
- virBufferEscape(&buf, '\\', ":",
- ":key=%s:auth_supported=cephx\\;none",
- secret);
- } else {
- virBufferAddLit(&buf, ":auth_supported=none");
- }
-
- if (src->nhosts > 0) {
- virBufferAddLit(&buf, ":mon_host=");
- for (i = 0; i < src->nhosts; i++) {
- if (i)
- virBufferAddLit(&buf, "\\;");
-
- /* assume host containing : is ipv6 */
- if (strchr(src->hosts[i].name, ':'))
- virBufferEscape(&buf, '\\', ":",
"[%s]",
- src->hosts[i].name);
- else
- virBufferAsprintf(&buf, "%s",
src->hosts[i].name);
-
- if (src->hosts[i].port)
- virBufferAsprintf(&buf, "\\:%s",
src->hosts[i].port);
- }
- }
+ if (virDomainNumaGetNodeCount(def->numa) &&
+ qemuBuildNumaArgStr(cfg, def, cmd, qemuCaps, nodeset) < 0)
+ goto error;
- if (src->configFile)
- virBufferEscape(&buf, '\\', ":",
":conf=%s", src->configFile);
+ /* 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 (virBufferCheckError(&buf) < 0)
- goto cleanup;
+ if (!(backStr = qemuBuildMemoryDimmBackendStr(def->mems[i], def,
+ qemuCaps, cfg)))
+ goto error;
- ret = virBufferContentAndReset(&buf);
- break;
+ if (!(dimmStr = qemuBuildMemoryDeviceStr(def->mems[i]))) {
+ VIR_FREE(backStr);
+ goto error;
+ }
+ virCommandAddArgList(cmd, "-object", backStr, "-device",
dimmStr, NULL);
- case VIR_STORAGE_NET_PROTOCOL_LAST:
- case VIR_STORAGE_NET_PROTOCOL_NONE:
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unexpected network protocol '%s'"),
- virStorageNetProtocolTypeToString(src->protocol));
- goto cleanup;
+ VIR_FREE(backStr);
+ VIR_FREE(dimmStr);
}
- cleanup:
- virBufferFreeAndReset(&buf);
- virURIFree(uri);
+ return 0;
- return ret;
+ error:
+ return -1;
}
-int
-qemuGetDriveSourceString(virStorageSourcePtr src,
- virConnectPtr conn,
- char **source)
+static int
+qemuBuildDeviceAddressStr(virBufferPtr buf,
+ virDomainDefPtr domainDef,
+ virDomainDeviceInfoPtr info,
+ virQEMUCapsPtr qemuCaps)
{
- int actualType = virStorageSourceGetActualType(src);
- char *secret = NULL;
- char *username = NULL;
int ret = -1;
+ char *devStr = NULL;
+ const char *contAlias = NULL;
- *source = NULL;
-
- /* return 1 for empty sources */
- if (virStorageSourceIsEmpty(src))
- return 1;
+ if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+ size_t i;
- if (conn) {
- if (actualType == VIR_STORAGE_TYPE_NETWORK &&
- src->auth &&
- (src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI ||
- src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)) {
- bool encode = false;
- int secretType = VIR_SECRET_USAGE_TYPE_ISCSI;
- const char *protocol = virStorageNetProtocolTypeToString(src->protocol);
- username = src->auth->username;
+ if (!(devStr = virDomainPCIAddressAsString(&info->addr.pci)))
+ goto cleanup;
+ for (i = 0; i < domainDef->ncontrollers; i++) {
+ virDomainControllerDefPtr cont = domainDef->controllers[i];
- if (src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD) {
- /* qemu requires the secret to be encoded for RBD */
- encode = true;
- secretType = VIR_SECRET_USAGE_TYPE_CEPH;
+ if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI &&
+ cont->idx == info->addr.pci.bus) {
+ contAlias = cont->info.alias;
+ if (!contAlias) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Device alias was not set for PCI "
+ "controller with index %u required "
+ "for device at address %s"),
+ info->addr.pci.bus, devStr);
+ goto cleanup;
+ }
+ break;
}
+ }
+ if (!contAlias) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not find PCI "
+ "controller with index %u required "
+ "for device at address %s"),
+ info->addr.pci.bus, devStr);
+ goto cleanup;
+ }
- if (!(secret = qemuGetSecretString(conn,
- protocol,
- encode,
- src->auth,
- secretType)))
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_MULTIFUNCTION)) {
+ if (info->addr.pci.function != 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Only PCI device addresses with function=0 "
+ "are supported with this QEMU binary"));
+ goto cleanup;
+ }
+ if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("'multifunction=on' is not supported with
"
+ "this QEMU binary"));
goto cleanup;
+ }
}
- }
- switch ((virStorageType) actualType) {
- case VIR_STORAGE_TYPE_BLOCK:
- case VIR_STORAGE_TYPE_FILE:
- case VIR_STORAGE_TYPE_DIR:
- if (VIR_STRDUP(*source, src->path) < 0)
+ if (info->addr.pci.bus != 0 &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Multiple PCI buses are not supported "
+ "with this QEMU binary"));
goto cleanup;
+ }
+ virBufferAsprintf(buf, ",bus=%s", contAlias);
- break;
-
- case VIR_STORAGE_TYPE_NETWORK:
- if (!(*source = qemuBuildNetworkDriveURI(src, username, secret)))
+ if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON)
+ virBufferAddLit(buf, ",multifunction=on");
+ else if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_OFF)
+ virBufferAddLit(buf, ",multifunction=off");
+ virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot);
+ if (info->addr.pci.function != 0)
+ virBufferAsprintf(buf, ".0x%x", info->addr.pci.function);
+ } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
+ if (!(contAlias = virDomainControllerAliasFind(domainDef,
+ VIR_DOMAIN_CONTROLLER_TYPE_USB,
+ info->addr.usb.bus)))
goto cleanup;
- break;
-
- case VIR_STORAGE_TYPE_VOLUME:
- case VIR_STORAGE_TYPE_NONE:
- case VIR_STORAGE_TYPE_LAST:
- break;
+ virBufferAsprintf(buf, ",bus=%s.0,port=%s", contAlias,
info->addr.usb.port);
+ } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO) {
+ if (info->addr.spaprvio.has_reg)
+ virBufferAsprintf(buf, ",reg=0x%llx", info->addr.spaprvio.reg);
+ } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
+ if (info->addr.ccw.assigned)
+ virBufferAsprintf(buf, ",devno=%x.%x.%04x",
+ info->addr.ccw.cssid,
+ info->addr.ccw.ssid,
+ info->addr.ccw.devno);
+ } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA) {
+ virBufferAsprintf(buf, ",iobase=0x%x,irq=0x%x",
+ info->addr.isa.iobase,
+ info->addr.isa.irq);
}
ret = 0;
-
cleanup:
- VIR_FREE(secret);
+ VIR_FREE(devStr);
return ret;
}
-
-/* Perform disk definition config validity checks */
-int
-qemuCheckDiskConfig(virDomainDiskDefPtr disk)
+static int
+qemuBuildRomStr(virBufferPtr buf,
+ virDomainDeviceInfoPtr info,
+ virQEMUCapsPtr qemuCaps)
{
- if (virDiskNameToIndex(disk->dst) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unsupported disk type '%s'"), disk->dst);
- goto error;
- }
+ if (info->rombar || info->romfile) {
+ if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("rombar and romfile are supported only
for PCI devices"));
+ return -1;
+ }
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_ROMBAR)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("rombar and romfile not supported in
this QEMU binary"));
+ return -1;
+ }
- if (disk->wwn) {
- if ((disk->bus != VIR_DOMAIN_DISK_BUS_IDE) &&
- (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Only ide and scsi disk support wwn"));
- goto error;
+ switch (info->rombar) {
+ case VIR_TRISTATE_SWITCH_OFF:
+ virBufferAddLit(buf, ",rombar=0");
+ break;
+ case VIR_TRISTATE_SWITCH_ON:
+ virBufferAddLit(buf, ",rombar=1");
+ break;
+ default:
+ break;
}
+ if (info->romfile)
+ virBufferAsprintf(buf, ",romfile=%s", info->romfile);
}
+ return 0;
+}
- if ((disk->vendor || disk->product) &&
- disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Only scsi disk supports vendor and product"));
- goto error;
- }
+static int
+qemuBuildIoEventFdStr(virBufferPtr buf,
+ virTristateSwitch use,
+ virQEMUCapsPtr qemuCaps)
+{
+ if (use && virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_IOEVENTFD))
+ virBufferAsprintf(buf, ",ioeventfd=%s",
+ virTristateSwitchTypeToString(use));
+ return 0;
+}
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
- /* make sure that both the bus supports type='lun' (SG_IO). */
- if (disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO &&
- disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("disk device='lun' is not supported for
bus='%s'"),
- virDomainDiskQEMUBusTypeToString(disk->bus));
- goto error;
- }
- if (disk->src->type == VIR_STORAGE_TYPE_NETWORK) {
- if (disk->src->protocol != VIR_STORAGE_NET_PROTOCOL_ISCSI) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("disk device='lun' is not supported "
- "for protocol='%s'"),
-
virStorageNetProtocolTypeToString(disk->src->protocol));
- goto error;
- }
- } else if (!virDomainDiskSourceIsBlockType(disk->src, true)) {
- goto error;
- }
- if (disk->wwn) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Setting wwn is not supported for lun device"));
- goto error;
- }
- if (disk->vendor || disk->product) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Setting vendor or product is not supported "
- "for lun device"));
- goto error;
- }
+#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_ "
+
+static int
+qemuSafeSerialParamValue(const char *value)
+{
+ if (strspn(value, QEMU_SERIAL_PARAM_ACCEPTED_CHARS) != strlen(value)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("driver serial '%s' contains unsafe
characters"),
+ value);
+ return -1;
}
+
return 0;
- error:
- return -1;
}
-
-/* Check whether the device address is using either 'ccw' or default s390
- * address format and whether that's "legal" for the current qemu and/or
- * guest os.machine type. This is the corollary to the code which doesn't
- * find the address type set using an emulator that supports either 'ccw'
- * or s390 and sets the address type based on the capabilities.
- *
- * If the address is using 'ccw' or s390 and it's not supported, generate
- * an error and return false; otherwise, return true.
- */
-bool
-qemuCheckCCWS390AddressSupport(virDomainDefPtr def,
- virDomainDeviceInfo info,
- virQEMUCapsPtr qemuCaps,
- const char *devicename)
+static char *
+qemuGetSecretString(virConnectPtr conn,
+ const char *scheme,
+ bool encoded,
+ virStorageAuthDefPtr authdef,
+ virSecretUsageType secretUsageType)
{
- if (info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
- if (!qemuDomainMachineIsS390CCW(def)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("cannot use CCW address type for device "
- "'%s' using machine type '%s'"),
- devicename, def->os.machine);
- return false;
- } else if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("CCW address type is not supported by "
- "this QEMU"));
- return false;
- }
- } else if (info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("virtio S390 address type is not supported by "
- "this QEMU"));
- return false;
- }
+ size_t secret_size;
+ virSecretPtr sec = NULL;
+ char *secret = NULL;
+ char uuidStr[VIR_UUID_STRING_BUFLEN];
+
+ /* look up secret */
+ switch (authdef->secretType) {
+ case VIR_STORAGE_SECRET_TYPE_UUID:
+ sec = virSecretLookupByUUID(conn, authdef->secret.uuid);
+ virUUIDFormat(authdef->secret.uuid, uuidStr);
+ break;
+ case VIR_STORAGE_SECRET_TYPE_USAGE:
+ sec = virSecretLookupByUsage(conn, secretUsageType,
+ authdef->secret.usage);
+ break;
}
- return true;
-}
+ if (!sec) {
+ if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
+ virReportError(VIR_ERR_NO_SECRET,
+ _("%s no secret matches uuid '%s'"),
+ scheme, uuidStr);
+ } else {
+ virReportError(VIR_ERR_NO_SECRET,
+ _("%s no secret matches usage value '%s'"),
+ scheme, authdef->secret.usage);
+ }
+ goto cleanup;
+ }
-/* Qemu 1.2 and later have a binary flag -enable-fips that must be
- * used for VNC auth to obey FIPS settings; but the flag only
- * exists on Linux, and with no way to probe for it via QMP. Our
- * solution: if FIPS mode is required, then unconditionally use
- * the flag, regardless of qemu version, for the following matrix:
- *
- * old QEMU new QEMU
- * FIPS enabled doesn't start VNC auth disabled
- * FIPS disabled/missing VNC auth enabled VNC auth enabled
- */
-bool
-qemuCheckFips(void)
-{
- bool ret = false;
+ secret = (char *)conn->secretDriver->secretGetValue(sec, &secret_size, 0,
+
VIR_SECRET_GET_VALUE_INTERNAL_CALL);
+ if (!secret) {
+ if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("could not get value of the secret for "
+ "username '%s' using uuid '%s'"),
+ authdef->username, uuidStr);
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("could not get value of the secret for "
+ "username '%s' using usage value
'%s'"),
+ authdef->username, authdef->secret.usage);
+ }
+ goto cleanup;
+ }
- if (virFileExists("/proc/sys/crypto/fips_enabled")) {
- char *buf = NULL;
+ if (encoded) {
+ char *base64 = NULL;
- if (virFileReadAll("/proc/sys/crypto/fips_enabled", 10, &buf) <
0)
- return ret;
- if (STREQ(buf, "1\n"))
- ret = true;
- VIR_FREE(buf);
+ base64_encode_alloc(secret, secret_size, &base64);
+ VIR_FREE(secret);
+ if (!base64) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ secret = base64;
}
- return ret;
+ cleanup:
+ virObjectUnref(sec);
+ return secret;
}
-char *
-qemuBuildDriveStr(virConnectPtr conn,
- virDomainDiskDefPtr disk,
- bool bootable,
- virQEMUCapsPtr qemuCaps)
+static int
+qemuNetworkDriveGetPort(int protocol,
+ const char *port)
{
- virBuffer opt = VIR_BUFFER_INITIALIZER;
- const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
- const char *trans =
- virDomainDiskGeometryTransTypeToString(disk->geometry.trans);
- int idx = virDiskNameToIndex(disk->dst);
- int busid = -1, unitid = -1;
- char *source = NULL;
- int actualType = virStorageSourceGetActualType(disk->src);
-
- if (idx < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unsupported disk type '%s'"), disk->dst);
- goto error;
- }
-
- switch (disk->bus) {
- case VIR_DOMAIN_DISK_BUS_SCSI:
- if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("unexpected address type for scsi disk"));
- goto error;
- }
-
- /* Setting bus= attr for SCSI drives, causes a controller
- * to be created. Yes this is slightly odd. It is not possible
- * to have > 1 bus on a SCSI controller (yet). */
- if (disk->info.addr.drive.bus != 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("SCSI controller only supports 1
bus"));
- goto error;
- }
- busid = disk->info.addr.drive.controller;
- unitid = disk->info.addr.drive.unit;
- break;
+ int ret = 0;
- case VIR_DOMAIN_DISK_BUS_IDE:
- if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("unexpected address type for ide disk"));
- goto error;
- }
- /* We can only have 1 IDE controller (currently) */
- if (disk->info.addr.drive.controller != 0) {
+ if (port) {
+ if (virStrToLong_i(port, NULL, 10, &ret) < 0 || ret < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Only 1 %s controller is supported"), bus);
- goto error;
+ _("failed to parse port number '%s'"),
+ port);
+ return -1;
}
- busid = disk->info.addr.drive.bus;
- unitid = disk->info.addr.drive.unit;
- break;
- case VIR_DOMAIN_DISK_BUS_FDC:
- if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("unexpected address type for fdc disk"));
- goto error;
- }
- /* We can only have 1 FDC controller (currently) */
- if (disk->info.addr.drive.controller != 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Only 1 %s controller is supported"), bus);
- goto error;
- }
- /* We can only have 1 FDC bus (currently) */
- if (disk->info.addr.drive.bus != 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Only 1 %s bus is supported"), bus);
- goto error;
- }
- if (disk->info.addr.drive.target != 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("target must be 0 for controller fdc"));
- goto error;
- }
- unitid = disk->info.addr.drive.unit;
+ return ret;
+ }
- break;
+ switch ((virStorageNetProtocol) protocol) {
+ case VIR_STORAGE_NET_PROTOCOL_HTTP:
+ return 80;
- case VIR_DOMAIN_DISK_BUS_VIRTIO:
- idx = -1;
- break;
+ case VIR_STORAGE_NET_PROTOCOL_HTTPS:
+ return 443;
- case VIR_DOMAIN_DISK_BUS_XEN:
- case VIR_DOMAIN_DISK_BUS_SD:
- /* Xen and SD have no address type currently, so assign
- * based on index */
- break;
- }
+ case VIR_STORAGE_NET_PROTOCOL_FTP:
+ return 21;
- if (qemuGetDriveSourceString(disk->src, conn, &source) < 0)
- goto error;
+ case VIR_STORAGE_NET_PROTOCOL_FTPS:
+ return 990;
- if (source &&
- !((disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY ||
- disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
- disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN)) {
+ case VIR_STORAGE_NET_PROTOCOL_TFTP:
+ return 69;
- virBufferAddLit(&opt, "file=");
+ case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+ return 7000;
- switch (actualType) {
- case VIR_STORAGE_TYPE_DIR:
- /* QEMU only supports magic FAT format for now */
- if (disk->src->format > 0 &&
- disk->src->format != VIR_STORAGE_FILE_FAT) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unsupported disk driver type for
'%s'"),
-
virStorageFileFormatTypeToString(disk->src->format));
- goto error;
- }
+ case VIR_STORAGE_NET_PROTOCOL_NBD:
+ return 10809;
- if (!disk->src->readonly) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot create virtual FAT disks in read-write
mode"));
- goto error;
- }
+ case VIR_STORAGE_NET_PROTOCOL_ISCSI:
+ case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
+ /* no default port specified */
+ return 0;
- virBufferAddLit(&opt, "fat:");
+ case VIR_STORAGE_NET_PROTOCOL_RBD:
+ case VIR_STORAGE_NET_PROTOCOL_LAST:
+ case VIR_STORAGE_NET_PROTOCOL_NONE:
+ /* not applicable */
+ return -1;
+ }
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
- virBufferAddLit(&opt, "floppy:");
+ return -1;
+}
- break;
+#define QEMU_DEFAULT_NBD_PORT "10809"
- case VIR_STORAGE_TYPE_BLOCK:
- if (disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- disk->src->type == VIR_STORAGE_TYPE_VOLUME ?
- _("tray status 'open' is invalid for block
type volume") :
- _("tray status 'open' is invalid for block
type disk"));
- goto error;
+static char *
+qemuBuildNetworkDriveURI(virStorageSourcePtr src,
+ const char *username,
+ const char *secret)
+{
+ char *ret = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ virURIPtr uri = NULL;
+ size_t i;
+
+ switch ((virStorageNetProtocol) src->protocol) {
+ case VIR_STORAGE_NET_PROTOCOL_NBD:
+ if (src->nhosts != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("protocol '%s' accepts only one
host"),
+ virStorageNetProtocolTypeToString(src->protocol));
+ goto cleanup;
}
- break;
+ if (!((src->hosts->name && strchr(src->hosts->name,
':')) ||
+ (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP
&&
+ !src->hosts->name) ||
+ (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_UNIX
&&
+ src->hosts->socket &&
+ src->hosts->socket[0] != '/'))) {
- default:
- break;
- }
+ virBufferAddLit(&buf, "nbd:");
- virBufferEscape(&opt, ',', ",", "%s,", source);
+ switch (src->hosts->transport) {
+ case VIR_STORAGE_NET_HOST_TRANS_TCP:
+ virBufferStrcat(&buf, src->hosts->name, NULL);
+ virBufferAsprintf(&buf, ":%s",
+ src->hosts->port ? src->hosts->port :
+ QEMU_DEFAULT_NBD_PORT);
+ break;
- if (disk->src->format > 0 &&
- disk->src->type != VIR_STORAGE_TYPE_DIR)
- virBufferAsprintf(&opt, "format=%s,",
-
virStorageFileFormatTypeToString(disk->src->format));
- }
- VIR_FREE(source);
+ case VIR_STORAGE_NET_HOST_TRANS_UNIX:
+ if (!src->hosts->socket) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("socket attribute required for "
+ "unix transport"));
+ goto cleanup;
+ }
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))
- virBufferAddLit(&opt, "if=none");
- else
- virBufferAsprintf(&opt, "if=%s", bus);
+ virBufferAsprintf(&buf, "unix:%s",
src->hosts->socket);
+ break;
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
- if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_CD))
- virBufferAddLit(&opt, ",media=cdrom");
- } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_CD))
- virBufferAddLit(&opt, ",media=cdrom");
- } else {
- virBufferAddLit(&opt, ",media=cdrom");
- }
- }
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("nbd does not support transport
'%s'"),
+
virStorageNetHostTransportTypeToString(src->hosts->transport));
+ goto cleanup;
+ }
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
- virBufferAsprintf(&opt, ",id=%s%s", QEMU_DRIVE_HOST_PREFIX,
disk->info.alias);
- } else {
- if (busid == -1 && unitid == -1) {
- if (idx != -1)
- virBufferAsprintf(&opt, ",index=%d", idx);
- } else {
- if (busid != -1)
- virBufferAsprintf(&opt, ",bus=%d", busid);
- if (unitid != -1)
- virBufferAsprintf(&opt, ",unit=%d", unitid);
- }
- }
- if (bootable &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_BOOT) &&
- (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK ||
- disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) &&
- disk->bus != VIR_DOMAIN_DISK_BUS_IDE)
- virBufferAddLit(&opt, ",boot=on");
- if (disk->src->readonly &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_READONLY)) {
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
- if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("readonly ide disks are not supported"));
- goto error;
- }
- if (disk->bus == VIR_DOMAIN_DISK_BUS_SATA) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("readonly sata disks are not supported"));
- goto error;
+ if (src->path)
+ virBufferAsprintf(&buf, ":exportname=%s",
src->path);
+
+ if (virBufferCheckError(&buf) < 0)
+ goto cleanup;
+
+ ret = virBufferContentAndReset(&buf);
+ goto cleanup;
}
- }
- virBufferAddLit(&opt, ",readonly=on");
- }
- if (disk->transient) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("transient disks not supported yet"));
- goto error;
- }
+ /* fallthrough */
+ /* NBD code uses same formatting scheme as others in some cases */
- /* generate geometry command string */
- if (disk->geometry.cylinders > 0 &&
- disk->geometry.heads > 0 &&
- disk->geometry.sectors > 0) {
+ case VIR_STORAGE_NET_PROTOCOL_HTTP:
+ case VIR_STORAGE_NET_PROTOCOL_HTTPS:
+ case VIR_STORAGE_NET_PROTOCOL_FTP:
+ case VIR_STORAGE_NET_PROTOCOL_FTPS:
+ case VIR_STORAGE_NET_PROTOCOL_TFTP:
+ case VIR_STORAGE_NET_PROTOCOL_ISCSI:
+ case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
+ if (src->nhosts != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("protocol '%s' accepts only one
host"),
+ virStorageNetProtocolTypeToString(src->protocol));
+ goto cleanup;
+ }
- virBufferAsprintf(&opt, ",cyls=%u,heads=%u,secs=%u",
- disk->geometry.cylinders,
- disk->geometry.heads,
- disk->geometry.sectors);
+ if (VIR_ALLOC(uri) < 0)
+ goto cleanup;
- if (disk->geometry.trans != VIR_DOMAIN_DISK_TRANS_DEFAULT)
- virBufferAsprintf(&opt, ",trans=%s", trans);
- }
+ if (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP) {
+ if (VIR_STRDUP(uri->scheme,
+ virStorageNetProtocolTypeToString(src->protocol)) <
0)
+ goto cleanup;
+ } else {
+ if (virAsprintf(&uri->scheme, "%s+%s",
+ virStorageNetProtocolTypeToString(src->protocol),
+
virStorageNetHostTransportTypeToString(src->hosts->transport)) < 0)
+ goto cleanup;
+ }
- if (disk->serial &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_SERIAL)) {
- if (qemuSafeSerialParamValue(disk->serial) < 0)
- goto error;
- if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
- disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("scsi-block 'lun' devices do not support the
"
- "serial property"));
- goto error;
- }
- virBufferAddLit(&opt, ",serial=");
- virBufferEscape(&opt, '\\', " ", "%s",
disk->serial);
- }
+ if ((uri->port = qemuNetworkDriveGetPort(src->protocol,
src->hosts->port)) < 0)
+ goto cleanup;
- if (disk->cachemode) {
- const char *mode = NULL;
+ if (src->path) {
+ if (src->volume) {
+ if (virAsprintf(&uri->path, "/%s%s",
+ src->volume, src->path) < 0)
+ goto cleanup;
+ } else {
+ if (virAsprintf(&uri->path, "%s%s",
+ src->path[0] == '/' ? "" :
"/",
+ src->path) < 0)
+ goto cleanup;
+ }
+ }
- mode = qemuDiskCacheV2TypeToString(disk->cachemode);
+ if (src->hosts->socket &&
+ virAsprintf(&uri->query, "socket=%s",
src->hosts->socket) < 0)
+ goto cleanup;
- if (disk->cachemode == VIR_DOMAIN_DISK_CACHE_DIRECTSYNC &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_CACHE_DIRECTSYNC)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("disk cache mode 'directsync' is not "
- "supported by this QEMU"));
- goto error;
- } else if (disk->cachemode == VIR_DOMAIN_DISK_CACHE_UNSAFE &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_CACHE_UNSAFE)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("disk cache mode 'unsafe' is not "
- "supported by this QEMU"));
- goto error;
- }
+ if (username) {
+ if (secret) {
+ if (virAsprintf(&uri->user, "%s:%s", username,
secret) < 0)
+ goto cleanup;
+ } else {
+ if (VIR_STRDUP(uri->user, username) < 0)
+ goto cleanup;
+ }
+ }
- if (disk->iomode == VIR_DOMAIN_DISK_IO_NATIVE &&
- disk->cachemode != VIR_DOMAIN_DISK_CACHE_DIRECTSYNC &&
- disk->cachemode != VIR_DOMAIN_DISK_CACHE_DISABLE) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("native I/O needs either no disk cache "
- "or directsync cache mode, QEMU will fallback "
- "to aio=threads"));
- goto error;
- }
+ if (VIR_STRDUP(uri->server, src->hosts->name) < 0)
+ goto cleanup;
- virBufferAsprintf(&opt, ",cache=%s", mode);
- } else if (disk->src->shared && !disk->src->readonly) {
- virBufferAddLit(&opt, ",cache=none");
- }
+ ret = virURIFormat(uri);
- if (disk->copy_on_read) {
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_COPY_ON_READ)) {
- virBufferAsprintf(&opt, ",copy-on-read=%s",
- virTristateSwitchTypeToString(disk->copy_on_read));
- } else {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("copy_on_read is not supported by this QEMU
binary"));
- goto error;
- }
- }
+ break;
- if (disk->discard) {
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_DISCARD)) {
- virBufferAsprintf(&opt, ",discard=%s",
- virDomainDiskDiscardTypeToString(disk->discard));
- } else {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("discard is not supported by this QEMU binary"));
- goto error;
- }
- }
+ case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+ if (!src->path) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing disk source for 'sheepdog'
protocol"));
+ goto cleanup;
+ }
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON)) {
- const char *wpolicy = NULL, *rpolicy = NULL;
+ if (src->nhosts == 0) {
+ if (virAsprintf(&ret, "sheepdog:%s", src->path) < 0)
+ goto cleanup;
+ } else if (src->nhosts == 1) {
+ if (virAsprintf(&ret, "sheepdog:%s:%s:%s",
+ src->hosts->name,
+ src->hosts->port ? src->hosts->port :
"7000",
+ src->path) < 0)
+ goto cleanup;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("protocol 'sheepdog' accepts up to one
host"));
+ goto cleanup;
+ }
- if (disk->error_policy)
- wpolicy = virDomainDiskErrorPolicyTypeToString(disk->error_policy);
- if (disk->rerror_policy)
- rpolicy = virDomainDiskErrorPolicyTypeToString(disk->rerror_policy);
+ break;
- if (disk->error_policy == VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE) {
- /* in the case of enospace, the option is spelled
- * differently in qemu, and it's only valid for werror,
- * not for rerror, so leave leave rerror NULL.
- */
- wpolicy = "enospc";
- } else if (!rpolicy) {
- /* for other policies, rpolicy can match wpolicy */
- rpolicy = wpolicy;
- }
+ case VIR_STORAGE_NET_PROTOCOL_RBD:
+ if (strchr(src->path, ':')) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("':' not allowed in RBD source volume name
'%s'"),
+ src->path);
+ goto cleanup;
+ }
- if (wpolicy)
- virBufferAsprintf(&opt, ",werror=%s", wpolicy);
- if (rpolicy)
- virBufferAsprintf(&opt, ",rerror=%s", rpolicy);
- }
+ virBufferStrcat(&buf, "rbd:", src->path, NULL);
- if (disk->iomode) {
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_AIO)) {
- virBufferAsprintf(&opt, ",aio=%s",
- virDomainDiskIoTypeToString(disk->iomode));
- } else {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("disk aio mode not supported with this "
- "QEMU binary"));
- goto error;
- }
- }
+ if (src->snapshot)
+ virBufferEscape(&buf, '\\', ":", "@%s",
src->snapshot);
- /* block I/O throttling */
- if ((disk->blkdeviotune.total_bytes_sec ||
- disk->blkdeviotune.read_bytes_sec ||
- disk->blkdeviotune.write_bytes_sec ||
- disk->blkdeviotune.total_iops_sec ||
- disk->blkdeviotune.read_iops_sec ||
- disk->blkdeviotune.write_iops_sec) &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_IOTUNE)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("block I/O throttling not supported with this "
- "QEMU binary"));
- goto error;
- }
+ if (username) {
+ virBufferEscape(&buf, '\\', ":",
":id=%s", username);
+ virBufferEscape(&buf, '\\', ":",
+ ":key=%s:auth_supported=cephx\\;none",
+ secret);
+ } else {
+ virBufferAddLit(&buf, ":auth_supported=none");
+ }
- /* block I/O throttling 1.7 */
- if ((disk->blkdeviotune.total_bytes_sec_max ||
- disk->blkdeviotune.read_bytes_sec_max ||
- disk->blkdeviotune.write_bytes_sec_max ||
- disk->blkdeviotune.total_iops_sec_max ||
- disk->blkdeviotune.read_iops_sec_max ||
- disk->blkdeviotune.write_iops_sec_max ||
- disk->blkdeviotune.size_iops_sec) &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_IOTUNE_MAX)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("there are some block I/O throttling parameters "
- "that are not supported with this QEMU binary"));
- goto error;
- }
+ if (src->nhosts > 0) {
+ virBufferAddLit(&buf, ":mon_host=");
+ for (i = 0; i < src->nhosts; i++) {
+ if (i)
+ virBufferAddLit(&buf, "\\;");
- if (disk->blkdeviotune.total_bytes_sec > LLONG_MAX ||
- disk->blkdeviotune.read_bytes_sec > LLONG_MAX ||
- disk->blkdeviotune.write_bytes_sec > LLONG_MAX ||
- disk->blkdeviotune.total_iops_sec > LLONG_MAX ||
- disk->blkdeviotune.read_iops_sec > LLONG_MAX ||
- disk->blkdeviotune.write_iops_sec > LLONG_MAX ||
- disk->blkdeviotune.total_bytes_sec_max > LLONG_MAX ||
- disk->blkdeviotune.read_bytes_sec_max > LLONG_MAX ||
- disk->blkdeviotune.write_bytes_sec_max > LLONG_MAX ||
- disk->blkdeviotune.total_iops_sec_max > LLONG_MAX ||
- disk->blkdeviotune.read_iops_sec_max > LLONG_MAX ||
- disk->blkdeviotune.write_iops_sec_max > LLONG_MAX ||
- disk->blkdeviotune.size_iops_sec > LLONG_MAX) {
- virReportError(VIR_ERR_OVERFLOW,
- _("block I/O throttle limit must "
- "be less than %llu using QEMU"), LLONG_MAX);
- goto error;
- }
+ /* assume host containing : is ipv6 */
+ if (strchr(src->hosts[i].name, ':'))
+ virBufferEscape(&buf, '\\', ":",
"[%s]",
+ src->hosts[i].name);
+ else
+ virBufferAsprintf(&buf, "%s",
src->hosts[i].name);
- if (disk->blkdeviotune.total_bytes_sec) {
- virBufferAsprintf(&opt, ",bps=%llu",
- disk->blkdeviotune.total_bytes_sec);
- }
+ if (src->hosts[i].port)
+ virBufferAsprintf(&buf, "\\:%s",
src->hosts[i].port);
+ }
+ }
- if (disk->blkdeviotune.read_bytes_sec) {
- virBufferAsprintf(&opt, ",bps_rd=%llu",
- disk->blkdeviotune.read_bytes_sec);
- }
+ if (src->configFile)
+ virBufferEscape(&buf, '\\', ":",
":conf=%s", src->configFile);
- if (disk->blkdeviotune.write_bytes_sec) {
- virBufferAsprintf(&opt, ",bps_wr=%llu",
- disk->blkdeviotune.write_bytes_sec);
- }
+ if (virBufferCheckError(&buf) < 0)
+ goto cleanup;
- if (disk->blkdeviotune.total_iops_sec) {
- virBufferAsprintf(&opt, ",iops=%llu",
- disk->blkdeviotune.total_iops_sec);
- }
+ ret = virBufferContentAndReset(&buf);
+ break;
- if (disk->blkdeviotune.read_iops_sec) {
- virBufferAsprintf(&opt, ",iops_rd=%llu",
- disk->blkdeviotune.read_iops_sec);
- }
- if (disk->blkdeviotune.write_iops_sec) {
- virBufferAsprintf(&opt, ",iops_wr=%llu",
- disk->blkdeviotune.write_iops_sec);
+ case VIR_STORAGE_NET_PROTOCOL_LAST:
+ case VIR_STORAGE_NET_PROTOCOL_NONE:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unexpected network protocol '%s'"),
+ virStorageNetProtocolTypeToString(src->protocol));
+ goto cleanup;
}
- if (disk->blkdeviotune.total_bytes_sec_max) {
- virBufferAsprintf(&opt, ",bps_max=%llu",
- disk->blkdeviotune.total_bytes_sec_max);
- }
+ cleanup:
+ virBufferFreeAndReset(&buf);
+ virURIFree(uri);
- if (disk->blkdeviotune.read_bytes_sec_max) {
- virBufferAsprintf(&opt, ",bps_rd_max=%llu",
- disk->blkdeviotune.read_bytes_sec_max);
- }
+ return ret;
+}
- if (disk->blkdeviotune.write_bytes_sec_max) {
- virBufferAsprintf(&opt, ",bps_wr_max=%llu",
- disk->blkdeviotune.write_bytes_sec_max);
- }
- if (disk->blkdeviotune.total_iops_sec_max) {
- virBufferAsprintf(&opt, ",iops_max=%llu",
- disk->blkdeviotune.total_iops_sec_max);
- }
+int
+qemuGetDriveSourceString(virStorageSourcePtr src,
+ virConnectPtr conn,
+ char **source)
+{
+ int actualType = virStorageSourceGetActualType(src);
+ char *secret = NULL;
+ char *username = NULL;
+ int ret = -1;
- if (disk->blkdeviotune.read_iops_sec_max) {
- virBufferAsprintf(&opt, ",iops_rd_max=%llu",
- disk->blkdeviotune.read_iops_sec_max);
- }
+ *source = NULL;
- if (disk->blkdeviotune.write_iops_sec_max) {
- virBufferAsprintf(&opt, ",iops_wr_max=%llu",
- disk->blkdeviotune.write_iops_sec_max);
- }
+ /* return 1 for empty sources */
+ if (virStorageSourceIsEmpty(src))
+ return 1;
- if (disk->blkdeviotune.size_iops_sec) {
- virBufferAsprintf(&opt, ",iops_size=%llu",
- disk->blkdeviotune.size_iops_sec);
- }
+ if (conn) {
+ if (actualType == VIR_STORAGE_TYPE_NETWORK &&
+ src->auth &&
+ (src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI ||
+ src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)) {
+ bool encode = false;
+ int secretType = VIR_SECRET_USAGE_TYPE_ISCSI;
+ const char *protocol = virStorageNetProtocolTypeToString(src->protocol);
+ username = src->auth->username;
- if (virBufferCheckError(&opt) < 0)
- goto error;
+ if (src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD) {
+ /* qemu requires the secret to be encoded for RBD */
+ encode = true;
+ secretType = VIR_SECRET_USAGE_TYPE_CEPH;
+ }
- return virBufferContentAndReset(&opt);
+ if (!(secret = qemuGetSecretString(conn,
+ protocol,
+ encode,
+ src->auth,
+ secretType)))
+ goto cleanup;
+ }
+ }
- error:
- VIR_FREE(source);
- virBufferFreeAndReset(&opt);
- return NULL;
-}
+ switch ((virStorageType) actualType) {
+ case VIR_STORAGE_TYPE_BLOCK:
+ case VIR_STORAGE_TYPE_FILE:
+ case VIR_STORAGE_TYPE_DIR:
+ if (VIR_STRDUP(*source, src->path) < 0)
+ goto cleanup;
+ break;
-static bool
-qemuCheckIOThreads(virDomainDefPtr def,
- virDomainDiskDefPtr disk)
-{
- /* Right "type" of disk" */
- if (disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO ||
- (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
- disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("IOThreads only available for virtio pci and "
- "virtio ccw disk"));
- return false;
- }
+ case VIR_STORAGE_TYPE_NETWORK:
+ if (!(*source = qemuBuildNetworkDriveURI(src, username, secret)))
+ goto cleanup;
+ break;
- /* Can we find the disk iothread in the iothreadid list? */
- if (!virDomainIOThreadIDFind(def, disk->iothread)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Disk iothread '%u' not defined in
iothreadid"),
- disk->iothread);
- return false;
+ case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NONE:
+ case VIR_STORAGE_TYPE_LAST:
+ break;
}
- return true;
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(secret);
+ return ret;
}
-char *
-qemuBuildDriveDevStr(virDomainDefPtr def,
- virDomainDiskDefPtr disk,
- int bootindex,
- virQEMUCapsPtr qemuCaps)
+/* Perform disk definition config validity checks */
+int
+qemuCheckDiskConfig(virDomainDiskDefPtr disk)
{
- virBuffer opt = VIR_BUFFER_INITIALIZER;
- const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
- const char *contAlias;
- int controllerModel;
-
- if (qemuCheckDiskConfig(disk) < 0)
+ if (virDiskNameToIndex(disk->dst) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported disk type '%s'"), disk->dst);
goto error;
+ }
- /* Live only checks */
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
- /* make sure that the qemu binary supports type='lun' (SG_IO). */
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_SG_IO)) {
+ if (disk->wwn) {
+ if ((disk->bus != VIR_DOMAIN_DISK_BUS_IDE) &&
+ (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("disk device='lun' is not supported by "
- "this QEMU"));
+ _("Only ide and scsi disk support wwn"));
goto error;
}
}
- if (!qemuCheckCCWS390AddressSupport(def, disk->info, qemuCaps, disk->dst))
- goto error;
-
- if (disk->iothread && !qemuCheckIOThreads(def, disk))
- goto error;
-
- switch (disk->bus) {
- case VIR_DOMAIN_DISK_BUS_IDE:
- if (disk->info.addr.drive.target != 0) {
+ if ((disk->vendor || disk->product) &&
+ disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("target must be 0 for ide controller"));
+ _("Only scsi disk supports vendor and product"));
goto error;
- }
+ }
- if (disk->wwn &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_DRIVE_WWN)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Setting wwn for ide disk is not supported "
- "by this QEMU"));
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
+ /* make sure that both the bus supports type='lun' (SG_IO). */
+ if (disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO &&
+ disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("disk device='lun' is not supported for
bus='%s'"),
+ virDomainDiskQEMUBusTypeToString(disk->bus));
goto error;
}
-
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_CD)) {
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
- virBufferAddLit(&opt, "ide-cd");
- else
- virBufferAddLit(&opt, "ide-hd");
- } else {
- virBufferAddLit(&opt, "ide-drive");
- }
-
- if (!(contAlias = virDomainControllerAliasFind(def,
VIR_DOMAIN_CONTROLLER_TYPE_IDE,
-
disk->info.addr.drive.controller)))
- goto error;
- virBufferAsprintf(&opt, ",bus=%s.%d,unit=%d",
- contAlias,
- disk->info.addr.drive.bus,
- disk->info.addr.drive.unit);
- break;
-
- case VIR_DOMAIN_DISK_BUS_SCSI:
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_BLOCK)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("This QEMU doesn't support scsi-block for
"
- "lun passthrough"));
+ if (disk->src->type == VIR_STORAGE_TYPE_NETWORK) {
+ if (disk->src->protocol != VIR_STORAGE_NET_PROTOCOL_ISCSI) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("disk device='lun' is not supported "
+ "for protocol='%s'"),
+
virStorageNetProtocolTypeToString(disk->src->protocol));
goto error;
}
+ } else if (!virDomainDiskSourceIsBlockType(disk->src, true)) {
+ goto error;
}
-
- if (disk->wwn &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_WWN)) {
+ if (disk->wwn) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Setting wwn for scsi disk is not supported "
- "by this QEMU"));
+ _("Setting wwn is not supported for lun device"));
goto error;
}
-
- /* Properties wwn, vendor and product were introduced in the
- * same QEMU release (1.2.0).
- */
- if ((disk->vendor || disk->product) &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_WWN)) {
+ if (disk->vendor || disk->product) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Setting vendor or product for scsi disk is not "
- "supported by this QEMU"));
+ _("Setting vendor or product is not supported "
+ "for lun device"));
goto error;
}
+ }
+ return 0;
+ error:
+ return -1;
+}
- controllerModel =
- virDomainDeviceFindControllerModel(def, &disk->info,
- VIR_DOMAIN_CONTROLLER_TYPE_SCSI);
- if ((qemuDomainSetSCSIControllerModel(def, qemuCaps,
- &controllerModel)) < 0)
- goto error;
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
- virBufferAddLit(&opt, "scsi-block");
- } else {
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_CD)) {
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
- virBufferAddLit(&opt, "scsi-cd");
- else
- virBufferAddLit(&opt, "scsi-hd");
- } else {
- virBufferAddLit(&opt, "scsi-disk");
- }
+/* Check whether the device address is using either 'ccw' or default s390
+ * address format and whether that's "legal" for the current qemu and/or
+ * guest os.machine type. This is the corollary to the code which doesn't
+ * find the address type set using an emulator that supports either 'ccw'
+ * or s390 and sets the address type based on the capabilities.
+ *
+ * If the address is using 'ccw' or s390 and it's not supported, generate
+ * an error and return false; otherwise, return true.
+ */
+bool
+qemuCheckCCWS390AddressSupport(virDomainDefPtr def,
+ virDomainDeviceInfo info,
+ virQEMUCapsPtr qemuCaps,
+ const char *devicename)
+{
+ if (info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
+ if (!qemuDomainMachineIsS390CCW(def)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("cannot use CCW address type for device "
+ "'%s' using machine type '%s'"),
+ devicename, def->os.machine);
+ return false;
+ } else if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("CCW address type is not supported by "
+ "this QEMU"));
+ return false;
+ }
+ } else if (info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("virtio S390 address type is not supported by "
+ "this QEMU"));
+ return false;
}
+ }
+ return true;
+}
- if (!(contAlias = virDomainControllerAliasFind(def,
VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
-
disk->info.addr.drive.controller)))
- goto error;
- if (controllerModel == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC) {
- if (disk->info.addr.drive.target != 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("target must be 0 for controller "
- "model 'lsilogic'"));
- goto error;
- }
+/* Qemu 1.2 and later have a binary flag -enable-fips that must be
+ * used for VNC auth to obey FIPS settings; but the flag only
+ * exists on Linux, and with no way to probe for it via QMP. Our
+ * solution: if FIPS mode is required, then unconditionally use
+ * the flag, regardless of qemu version, for the following matrix:
+ *
+ * old QEMU new QEMU
+ * FIPS enabled doesn't start VNC auth disabled
+ * FIPS disabled/missing VNC auth enabled VNC auth enabled
+ */
+bool
+qemuCheckFips(void)
+{
+ bool ret = false;
- virBufferAsprintf(&opt, ",bus=%s.%d,scsi-id=%d",
- contAlias,
- disk->info.addr.drive.bus,
- disk->info.addr.drive.unit);
- } else {
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_CHANNEL)) {
- if (disk->info.addr.drive.target > 7) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("This QEMU doesn't support target "
- "greater than 7"));
- goto error;
- }
+ if (virFileExists("/proc/sys/crypto/fips_enabled")) {
+ char *buf = NULL;
- if (disk->info.addr.drive.bus != 0 &&
- disk->info.addr.drive.unit != 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("This QEMU only supports both bus and "
- "unit equal to 0"));
- goto error;
- }
- }
+ if (virFileReadAll("/proc/sys/crypto/fips_enabled", 10, &buf) <
0)
+ return ret;
+ if (STREQ(buf, "1\n"))
+ ret = true;
+ VIR_FREE(buf);
+ }
- virBufferAsprintf(&opt,
",bus=%s.0,channel=%d,scsi-id=%d,lun=%d",
- contAlias,
- disk->info.addr.drive.bus,
- disk->info.addr.drive.target,
- disk->info.addr.drive.unit);
- }
- break;
+ return ret;
+}
- case VIR_DOMAIN_DISK_BUS_SATA:
- if (disk->info.addr.drive.bus != 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("bus must be 0 for ide controller"));
- goto error;
- }
- if (disk->info.addr.drive.target != 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("target must be 0 for ide controller"));
+
+char *
+qemuBuildDriveStr(virConnectPtr conn,
+ virDomainDiskDefPtr disk,
+ bool bootable,
+ virQEMUCapsPtr qemuCaps)
+{
+ virBuffer opt = VIR_BUFFER_INITIALIZER;
+ const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
+ const char *trans =
+ virDomainDiskGeometryTransTypeToString(disk->geometry.trans);
+ int idx = virDiskNameToIndex(disk->dst);
+ int busid = -1, unitid = -1;
+ char *source = NULL;
+ int actualType = virStorageSourceGetActualType(disk->src);
+
+ if (idx < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported disk type '%s'"), disk->dst);
+ goto error;
+ }
+
+ switch (disk->bus) {
+ case VIR_DOMAIN_DISK_BUS_SCSI:
+ if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("unexpected address type for scsi disk"));
goto error;
}
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_CD)) {
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
- virBufferAddLit(&opt, "ide-cd");
- else
- virBufferAddLit(&opt, "ide-hd");
- } else {
- virBufferAddLit(&opt, "ide-drive");
+ /* Setting bus= attr for SCSI drives, causes a controller
+ * to be created. Yes this is slightly odd. It is not possible
+ * to have > 1 bus on a SCSI controller (yet). */
+ if (disk->info.addr.drive.bus != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("SCSI controller only supports 1
bus"));
+ goto error;
}
-
- if (!(contAlias = virDomainControllerAliasFind(def,
VIR_DOMAIN_CONTROLLER_TYPE_SATA,
-
disk->info.addr.drive.controller)))
- goto error;
- virBufferAsprintf(&opt, ",bus=%s.%d",
- contAlias,
- disk->info.addr.drive.unit);
+ busid = disk->info.addr.drive.controller;
+ unitid = disk->info.addr.drive.unit;
break;
- case VIR_DOMAIN_DISK_BUS_VIRTIO:
- if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
- virBufferAddLit(&opt, "virtio-blk-ccw");
- if (disk->iothread)
- virBufferAsprintf(&opt, ",iothread=iothread%u",
disk->iothread);
- } else if (disk->info.type ==
- VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
- virBufferAddLit(&opt, "virtio-blk-s390");
- } else if (disk->info.type ==
- VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) {
- virBufferAddLit(&opt, "virtio-blk-device");
- } else {
- virBufferAddLit(&opt, "virtio-blk-pci");
- if (disk->iothread)
- virBufferAsprintf(&opt, ",iothread=iothread%u",
disk->iothread);
- }
- qemuBuildIoEventFdStr(&opt, disk->ioeventfd, qemuCaps);
- if (disk->event_idx &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_EVENT_IDX)) {
- virBufferAsprintf(&opt, ",event_idx=%s",
- virTristateSwitchTypeToString(disk->event_idx));
- }
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_SCSI)) {
- /* if sg_io is true but the scsi option isn't supported,
- * that means it's just always on in this version of qemu.
- */
- virBufferAsprintf(&opt, ",scsi=%s",
- (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN)
- ? "on" : "off");
+ case VIR_DOMAIN_DISK_BUS_IDE:
+ if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("unexpected address type for ide disk"));
+ goto error;
}
- if (qemuBuildDeviceAddressStr(&opt, def, &disk->info, qemuCaps) <
0)
+ /* We can only have 1 IDE controller (currently) */
+ if (disk->info.addr.drive.controller != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Only 1 %s controller is supported"), bus);
goto error;
+ }
+ busid = disk->info.addr.drive.bus;
+ unitid = disk->info.addr.drive.unit;
break;
- case VIR_DOMAIN_DISK_BUS_USB:
- if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
- disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
+ case VIR_DOMAIN_DISK_BUS_FDC:
+ if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("unexpected address type for usb disk"));
+ _("unexpected address type for fdc disk"));
goto error;
}
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE)) {
+ /* We can only have 1 FDC controller (currently) */
+ if (disk->info.addr.drive.controller != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Only 1 %s controller is supported"), bus);
+ goto error;
+ }
+ /* We can only have 1 FDC bus (currently) */
+ if (disk->info.addr.drive.bus != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Only 1 %s bus is supported"), bus);
+ goto error;
+ }
+ if (disk->info.addr.drive.target != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("This QEMU doesn't support '-device "
- "usb-storage'"));
+ _("target must be 0 for controller fdc"));
goto error;
-
}
- virBufferAddLit(&opt, "usb-storage");
+ unitid = disk->info.addr.drive.unit;
- if (qemuBuildDeviceAddressStr(&opt, def, &disk->info, qemuCaps) <
0)
- goto error;
break;
- default:
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unsupported disk bus '%s' with device
setup"), bus);
- goto error;
- }
+ case VIR_DOMAIN_DISK_BUS_VIRTIO:
+ idx = -1;
+ break;
- virBufferAsprintf(&opt, ",drive=%s%s", QEMU_DRIVE_HOST_PREFIX,
disk->info.alias);
- virBufferAsprintf(&opt, ",id=%s", disk->info.alias);
- if (bootindex && virQEMUCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX))
- virBufferAsprintf(&opt, ",bootindex=%d", bootindex);
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKIO)) {
- if (disk->blockio.logical_block_size > 0)
- virBufferAsprintf(&opt, ",logical_block_size=%u",
- disk->blockio.logical_block_size);
- if (disk->blockio.physical_block_size > 0)
- virBufferAsprintf(&opt, ",physical_block_size=%u",
- disk->blockio.physical_block_size);
+ case VIR_DOMAIN_DISK_BUS_XEN:
+ case VIR_DOMAIN_DISK_BUS_SD:
+ /* Xen and SD have no address type currently, so assign
+ * based on index */
+ break;
}
- if (disk->wwn) {
- if (STRPREFIX(disk->wwn, "0x"))
- virBufferAsprintf(&opt, ",wwn=%s", disk->wwn);
- else
- virBufferAsprintf(&opt, ",wwn=0x%s", disk->wwn);
- }
+ if (qemuGetDriveSourceString(disk->src, conn, &source) < 0)
+ goto error;
- if (disk->vendor)
- virBufferAsprintf(&opt, ",vendor=%s", disk->vendor);
+ if (source &&
+ !((disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY ||
+ disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
+ disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN)) {
- if (disk->product)
- virBufferAsprintf(&opt, ",product=%s", disk->product);
+ virBufferAddLit(&opt, "file=");
- if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_STORAGE_REMOVABLE)) {
- if (disk->removable == VIR_TRISTATE_SWITCH_ON)
- virBufferAddLit(&opt, ",removable=on");
- else
- virBufferAddLit(&opt, ",removable=off");
- } else {
- if (disk->removable != VIR_TRISTATE_SWITCH_ABSENT) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("This QEMU doesn't support setting the "
- "removable flag of USB storage devices"));
+ switch (actualType) {
+ case VIR_STORAGE_TYPE_DIR:
+ /* QEMU only supports magic FAT format for now */
+ if (disk->src->format > 0 &&
+ disk->src->format != VIR_STORAGE_FILE_FAT) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported disk driver type for
'%s'"),
+
virStorageFileFormatTypeToString(disk->src->format));
goto error;
}
- }
- }
- if (virBufferCheckError(&opt) < 0)
- goto error;
+ if (!disk->src->readonly) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot create virtual FAT disks in read-write
mode"));
+ goto error;
+ }
- return virBufferContentAndReset(&opt);
+ virBufferAddLit(&opt, "fat:");
- error:
- virBufferFreeAndReset(&opt);
- return NULL;
-}
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
+ virBufferAddLit(&opt, "floppy:");
+ break;
-char *qemuBuildFSStr(virDomainFSDefPtr fs,
- virQEMUCapsPtr qemuCaps ATTRIBUTE_UNUSED)
-{
- virBuffer opt = VIR_BUFFER_INITIALIZER;
- const char *driver = qemuDomainFSDriverTypeToString(fs->fsdriver);
- const char *wrpolicy = virDomainFSWrpolicyTypeToString(fs->wrpolicy);
+ case VIR_STORAGE_TYPE_BLOCK:
+ if (disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ disk->src->type == VIR_STORAGE_TYPE_VOLUME ?
+ _("tray status 'open' is invalid for block
type volume") :
+ _("tray status 'open' is invalid for block
type disk"));
+ goto error;
+ }
- if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("only supports mount filesystem type"));
- goto error;
+ break;
+
+ default:
+ break;
+ }
+
+ virBufferEscape(&opt, ',', ",", "%s,", source);
+
+ if (disk->src->format > 0 &&
+ disk->src->type != VIR_STORAGE_TYPE_DIR)
+ virBufferAsprintf(&opt, "format=%s,",
+
virStorageFileFormatTypeToString(disk->src->format));
}
+ VIR_FREE(source);
- if (!driver) {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))
+ virBufferAddLit(&opt, "if=none");
+ else
+ virBufferAsprintf(&opt, "if=%s", bus);
+
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
+ if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_CD))
+ virBufferAddLit(&opt, ",media=cdrom");
+ } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_CD))
+ virBufferAddLit(&opt, ",media=cdrom");
+ } else {
+ virBufferAddLit(&opt, ",media=cdrom");
+ }
+ }
+
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
+ virBufferAsprintf(&opt, ",id=%s%s", QEMU_DRIVE_HOST_PREFIX,
disk->info.alias);
+ } else {
+ if (busid == -1 && unitid == -1) {
+ if (idx != -1)
+ virBufferAsprintf(&opt, ",index=%d", idx);
+ } else {
+ if (busid != -1)
+ virBufferAsprintf(&opt, ",bus=%d", busid);
+ if (unitid != -1)
+ virBufferAsprintf(&opt, ",unit=%d", unitid);
+ }
+ }
+ if (bootable &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_BOOT) &&
+ (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK ||
+ disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) &&
+ disk->bus != VIR_DOMAIN_DISK_BUS_IDE)
+ virBufferAddLit(&opt, ",boot=on");
+ if (disk->src->readonly &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_READONLY)) {
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
+ if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("readonly ide disks are not supported"));
+ goto error;
+ }
+ if (disk->bus == VIR_DOMAIN_DISK_BUS_SATA) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("readonly sata disks are not supported"));
+ goto error;
+ }
+ }
+ virBufferAddLit(&opt, ",readonly=on");
+ }
+ if (disk->transient) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Filesystem driver type not supported"));
+ _("transient disks not supported yet"));
goto error;
}
- virBufferAdd(&opt, driver, -1);
- if (fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_PATH ||
- fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_DEFAULT) {
- if (fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_MAPPED) {
- virBufferAddLit(&opt, ",security_model=mapped");
- } else if (fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) {
- virBufferAddLit(&opt, ",security_model=passthrough");
- } else if (fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_SQUASH) {
- virBufferAddLit(&opt, ",security_model=none");
+ /* generate geometry command string */
+ if (disk->geometry.cylinders > 0 &&
+ disk->geometry.heads > 0 &&
+ disk->geometry.sectors > 0) {
+
+ virBufferAsprintf(&opt, ",cyls=%u,heads=%u,secs=%u",
+ disk->geometry.cylinders,
+ disk->geometry.heads,
+ disk->geometry.sectors);
+
+ if (disk->geometry.trans != VIR_DOMAIN_DISK_TRANS_DEFAULT)
+ virBufferAsprintf(&opt, ",trans=%s", trans);
+ }
+
+ if (disk->serial &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_SERIAL)) {
+ if (qemuSafeSerialParamValue(disk->serial) < 0)
+ goto error;
+ if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
+ disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("scsi-block 'lun' devices do not support the
"
+ "serial property"));
+ goto error;
}
- } else {
- /* For other fs drivers, default(passthru) should always
- * be supported */
- if (fs->accessmode != VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) {
+ virBufferAddLit(&opt, ",serial=");
+ virBufferEscape(&opt, '\\', " ", "%s",
disk->serial);
+ }
+
+ if (disk->cachemode) {
+ const char *mode = NULL;
+
+ mode = qemuDiskCacheV2TypeToString(disk->cachemode);
+
+ if (disk->cachemode == VIR_DOMAIN_DISK_CACHE_DIRECTSYNC &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_CACHE_DIRECTSYNC)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("only supports passthrough accessmode"));
+ _("disk cache mode 'directsync' is not "
+ "supported by this QEMU"));
+ goto error;
+ } else if (disk->cachemode == VIR_DOMAIN_DISK_CACHE_UNSAFE &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_CACHE_UNSAFE)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("disk cache mode 'unsafe' is not "
+ "supported by this QEMU"));
+ goto error;
+ }
+
+ if (disk->iomode == VIR_DOMAIN_DISK_IO_NATIVE &&
+ disk->cachemode != VIR_DOMAIN_DISK_CACHE_DIRECTSYNC &&
+ disk->cachemode != VIR_DOMAIN_DISK_CACHE_DISABLE) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("native I/O needs either no disk cache "
+ "or directsync cache mode, QEMU will fallback "
+ "to aio=threads"));
goto error;
}
+
+ virBufferAsprintf(&opt, ",cache=%s", mode);
+ } else if (disk->src->shared && !disk->src->readonly) {
+ virBufferAddLit(&opt, ",cache=none");
}
- if (fs->wrpolicy) {
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_FSDEV_WRITEOUT)) {
- virBufferAsprintf(&opt, ",writeout=%s", wrpolicy);
+ if (disk->copy_on_read) {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_COPY_ON_READ)) {
+ virBufferAsprintf(&opt, ",copy-on-read=%s",
+ virTristateSwitchTypeToString(disk->copy_on_read));
} else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("filesystem writeout not supported"));
+ _("copy_on_read is not supported by this QEMU
binary"));
goto error;
}
}
- virBufferAsprintf(&opt, ",id=%s%s", QEMU_FSDEV_HOST_PREFIX,
fs->info.alias);
- virBufferAsprintf(&opt, ",path=%s", fs->src);
-
- if (fs->readonly) {
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_FSDEV_READONLY)) {
- virBufferAddLit(&opt, ",readonly");
+ if (disk->discard) {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_DISCARD)) {
+ virBufferAsprintf(&opt, ",discard=%s",
+ virDomainDiskDiscardTypeToString(disk->discard));
} else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("readonly filesystem is not supported by this "
- "QEMU binary"));
+ _("discard is not supported by this QEMU binary"));
goto error;
}
}
- if (virBufferCheckError(&opt) < 0)
- goto error;
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON)) {
+ const char *wpolicy = NULL, *rpolicy = NULL;
- return virBufferContentAndReset(&opt);
+ if (disk->error_policy)
+ wpolicy = virDomainDiskErrorPolicyTypeToString(disk->error_policy);
+ if (disk->rerror_policy)
+ rpolicy = virDomainDiskErrorPolicyTypeToString(disk->rerror_policy);
- error:
- virBufferFreeAndReset(&opt);
- return NULL;
-}
+ if (disk->error_policy == VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE) {
+ /* in the case of enospace, the option is spelled
+ * differently in qemu, and it's only valid for werror,
+ * not for rerror, so leave leave rerror NULL.
+ */
+ wpolicy = "enospc";
+ } else if (!rpolicy) {
+ /* for other policies, rpolicy can match wpolicy */
+ rpolicy = wpolicy;
+ }
+ if (wpolicy)
+ virBufferAsprintf(&opt, ",werror=%s", wpolicy);
+ if (rpolicy)
+ virBufferAsprintf(&opt, ",rerror=%s", rpolicy);
+ }
-char *
-qemuBuildFSDevStr(virDomainDefPtr def,
- virDomainFSDefPtr fs,
- virQEMUCapsPtr qemuCaps)
-{
- virBuffer opt = VIR_BUFFER_INITIALIZER;
+ if (disk->iomode) {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_AIO)) {
+ virBufferAsprintf(&opt, ",aio=%s",
+ virDomainDiskIoTypeToString(disk->iomode));
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("disk aio mode not supported with this "
+ "QEMU binary"));
+ goto error;
+ }
+ }
- if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
+ /* block I/O throttling */
+ if ((disk->blkdeviotune.total_bytes_sec ||
+ disk->blkdeviotune.read_bytes_sec ||
+ disk->blkdeviotune.write_bytes_sec ||
+ disk->blkdeviotune.total_iops_sec ||
+ disk->blkdeviotune.read_iops_sec ||
+ disk->blkdeviotune.write_iops_sec) &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_IOTUNE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("can only passthrough directories"));
+ _("block I/O throttling not supported with this "
+ "QEMU binary"));
goto error;
}
- if (fs->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
- virBufferAddLit(&opt, "virtio-9p-ccw");
- else
- virBufferAddLit(&opt, "virtio-9p-pci");
-
- virBufferAsprintf(&opt, ",id=%s", fs->info.alias);
- virBufferAsprintf(&opt, ",fsdev=%s%s", QEMU_FSDEV_HOST_PREFIX,
fs->info.alias);
- virBufferAsprintf(&opt, ",mount_tag=%s", fs->dst);
-
- if (qemuBuildDeviceAddressStr(&opt, def, &fs->info, qemuCaps) < 0)
- goto error;
-
- if (virBufferCheckError(&opt) < 0)
- goto error;
-
- return virBufferContentAndReset(&opt);
+ /* block I/O throttling 1.7 */
+ if ((disk->blkdeviotune.total_bytes_sec_max ||
+ disk->blkdeviotune.read_bytes_sec_max ||
+ disk->blkdeviotune.write_bytes_sec_max ||
+ disk->blkdeviotune.total_iops_sec_max ||
+ disk->blkdeviotune.read_iops_sec_max ||
+ disk->blkdeviotune.write_iops_sec_max ||
+ disk->blkdeviotune.size_iops_sec) &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_IOTUNE_MAX)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("there are some block I/O throttling parameters "
+ "that are not supported with this QEMU binary"));
+ goto error;
+ }
- error:
- virBufferFreeAndReset(&opt);
- return NULL;
-}
+ if (disk->blkdeviotune.total_bytes_sec > LLONG_MAX ||
+ disk->blkdeviotune.read_bytes_sec > LLONG_MAX ||
+ disk->blkdeviotune.write_bytes_sec > LLONG_MAX ||
+ disk->blkdeviotune.total_iops_sec > LLONG_MAX ||
+ disk->blkdeviotune.read_iops_sec > LLONG_MAX ||
+ disk->blkdeviotune.write_iops_sec > LLONG_MAX ||
+ disk->blkdeviotune.total_bytes_sec_max > LLONG_MAX ||
+ disk->blkdeviotune.read_bytes_sec_max > LLONG_MAX ||
+ disk->blkdeviotune.write_bytes_sec_max > LLONG_MAX ||
+ disk->blkdeviotune.total_iops_sec_max > LLONG_MAX ||
+ disk->blkdeviotune.read_iops_sec_max > LLONG_MAX ||
+ disk->blkdeviotune.write_iops_sec_max > LLONG_MAX ||
+ disk->blkdeviotune.size_iops_sec > LLONG_MAX) {
+ virReportError(VIR_ERR_OVERFLOW,
+ _("block I/O throttle limit must "
+ "be less than %llu using QEMU"), LLONG_MAX);
+ goto error;
+ }
+ if (disk->blkdeviotune.total_bytes_sec) {
+ virBufferAsprintf(&opt, ",bps=%llu",
+ disk->blkdeviotune.total_bytes_sec);
+ }
-static int
-qemuControllerModelUSBToCaps(int model)
-{
- switch (model) {
- case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI:
- return QEMU_CAPS_PIIX3_USB_UHCI;
- case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI:
- return QEMU_CAPS_PIIX4_USB_UHCI;
- case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI:
- return QEMU_CAPS_USB_EHCI;
- case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1:
- case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1:
- case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2:
- case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3:
- return QEMU_CAPS_ICH9_USB_EHCI1;
- case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI:
- return QEMU_CAPS_VT82C686B_USB_UHCI;
- case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI:
- return QEMU_CAPS_PCI_OHCI;
- case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI:
- return QEMU_CAPS_NEC_USB_XHCI;
- default:
- return -1;
+ if (disk->blkdeviotune.read_bytes_sec) {
+ virBufferAsprintf(&opt, ",bps_rd=%llu",
+ disk->blkdeviotune.read_bytes_sec);
}
-}
+ if (disk->blkdeviotune.write_bytes_sec) {
+ virBufferAsprintf(&opt, ",bps_wr=%llu",
+ disk->blkdeviotune.write_bytes_sec);
+ }
-static int
-qemuBuildUSBControllerDevStr(virDomainDefPtr domainDef,
- virDomainControllerDefPtr def,
- virQEMUCapsPtr qemuCaps,
- virBuffer *buf)
-{
- const char *smodel;
- int model, flags;
+ if (disk->blkdeviotune.total_iops_sec) {
+ virBufferAsprintf(&opt, ",iops=%llu",
+ disk->blkdeviotune.total_iops_sec);
+ }
- model = def->model;
+ if (disk->blkdeviotune.read_iops_sec) {
+ virBufferAsprintf(&opt, ",iops_rd=%llu",
+ disk->blkdeviotune.read_iops_sec);
+ }
- if (model == -1) {
- if ARCH_IS_PPC64(domainDef->os.arch)
- model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI;
- else
- model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI;
+ if (disk->blkdeviotune.write_iops_sec) {
+ virBufferAsprintf(&opt, ",iops_wr=%llu",
+ disk->blkdeviotune.write_iops_sec);
}
- smodel = qemuControllerModelUSBTypeToString(model);
- flags = qemuControllerModelUSBToCaps(model);
+ if (disk->blkdeviotune.total_bytes_sec_max) {
+ virBufferAsprintf(&opt, ",bps_max=%llu",
+ disk->blkdeviotune.total_bytes_sec_max);
+ }
- if (flags == -1 || !virQEMUCapsGet(qemuCaps, flags)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("%s not supported in this QEMU binary"), smodel);
- return -1;
+ if (disk->blkdeviotune.read_bytes_sec_max) {
+ virBufferAsprintf(&opt, ",bps_rd_max=%llu",
+ disk->blkdeviotune.read_bytes_sec_max);
}
- virBufferAsprintf(buf, "%s", smodel);
+ if (disk->blkdeviotune.write_bytes_sec_max) {
+ virBufferAsprintf(&opt, ",bps_wr_max=%llu",
+ disk->blkdeviotune.write_bytes_sec_max);
+ }
- if (def->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB)
- virBufferAsprintf(buf, ",masterbus=%s.0,firstport=%d",
- def->info.alias, def->info.master.usb.startport);
- else
- virBufferAsprintf(buf, ",id=%s", def->info.alias);
+ if (disk->blkdeviotune.total_iops_sec_max) {
+ virBufferAsprintf(&opt, ",iops_max=%llu",
+ disk->blkdeviotune.total_iops_sec_max);
+ }
- return 0;
+ if (disk->blkdeviotune.read_iops_sec_max) {
+ virBufferAsprintf(&opt, ",iops_rd_max=%llu",
+ disk->blkdeviotune.read_iops_sec_max);
+ }
+
+ if (disk->blkdeviotune.write_iops_sec_max) {
+ virBufferAsprintf(&opt, ",iops_wr_max=%llu",
+ disk->blkdeviotune.write_iops_sec_max);
+ }
+
+ if (disk->blkdeviotune.size_iops_sec) {
+ virBufferAsprintf(&opt, ",iops_size=%llu",
+ disk->blkdeviotune.size_iops_sec);
+ }
+
+ if (virBufferCheckError(&opt) < 0)
+ goto error;
+
+ return virBufferContentAndReset(&opt);
+
+ error:
+ VIR_FREE(source);
+ virBufferFreeAndReset(&opt);
+ return NULL;
}
-char *
-qemuBuildControllerDevStr(virDomainDefPtr domainDef,
- virDomainControllerDefPtr def,
- virQEMUCapsPtr qemuCaps,
- int *nusbcontroller)
-{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- int model = def->model;
- const char *modelName = NULL;
- if (!qemuCheckCCWS390AddressSupport(domainDef, def->info, qemuCaps,
- "controller"))
- return NULL;
+static bool
+qemuCheckIOThreads(virDomainDefPtr def,
+ virDomainDiskDefPtr disk)
+{
+ /* Right "type" of disk" */
+ if (disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO ||
+ (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
+ disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("IOThreads only available for virtio pci and "
+ "virtio ccw disk"));
+ return false;
+ }
- if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
- if ((qemuDomainSetSCSIControllerModel(domainDef, qemuCaps, &model)) < 0)
- return NULL;
+ /* Can we find the disk iothread in the iothreadid list? */
+ if (!virDomainIOThreadIDFind(def, disk->iothread)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Disk iothread '%u' not defined in
iothreadid"),
+ disk->iothread);
+ return false;
}
- if (!(def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
- model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI)) {
- if (def->queues) {
+ return true;
+}
+
+
+char *
+qemuBuildDriveDevStr(virDomainDefPtr def,
+ virDomainDiskDefPtr disk,
+ int bootindex,
+ virQEMUCapsPtr qemuCaps)
+{
+ virBuffer opt = VIR_BUFFER_INITIALIZER;
+ const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
+ const char *contAlias;
+ int controllerModel;
+
+ if (qemuCheckDiskConfig(disk) < 0)
+ goto error;
+
+ /* Live only checks */
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
+ /* make sure that the qemu binary supports type='lun' (SG_IO). */
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_SG_IO)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("'queues' is only supported by virtio-scsi
controller"));
- return NULL;
+ _("disk device='lun' is not supported by "
+ "this QEMU"));
+ goto error;
}
- if (def->cmd_per_lun) {
+ }
+
+ if (!qemuCheckCCWS390AddressSupport(def, disk->info, qemuCaps, disk->dst))
+ goto error;
+
+ if (disk->iothread && !qemuCheckIOThreads(def, disk))
+ goto error;
+
+ switch (disk->bus) {
+ case VIR_DOMAIN_DISK_BUS_IDE:
+ if (disk->info.addr.drive.target != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("'cmd_per_lun' is only supported by virtio-scsi
controller"));
- return NULL;
+ _("target must be 0 for ide controller"));
+ goto error;
}
- if (def->max_sectors) {
+
+ if (disk->wwn &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_DRIVE_WWN)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("'max_sectors' is only supported by virtio-scsi
controller"));
- return NULL;
+ _("Setting wwn for ide disk is not supported "
+ "by this QEMU"));
+ goto error;
}
- if (def->ioeventfd) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("'ioeventfd' is only supported by virtio-scsi
controller"));
- return NULL;
+
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_CD)) {
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
+ virBufferAddLit(&opt, "ide-cd");
+ else
+ virBufferAddLit(&opt, "ide-hd");
+ } else {
+ virBufferAddLit(&opt, "ide-drive");
}
- }
- switch (def->type) {
- case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
- switch (model) {
- case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
- if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
- virBufferAddLit(&buf, "virtio-scsi-ccw");
- else if (def->info.type ==
- VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)
- virBufferAddLit(&buf, "virtio-scsi-s390");
- else if (def->info.type ==
- VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO)
- virBufferAddLit(&buf, "virtio-scsi-device");
- else
- virBufferAddLit(&buf, "virtio-scsi-pci");
- break;
- case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC:
- virBufferAddLit(&buf, "lsi");
- break;
- case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI:
- virBufferAddLit(&buf, "spapr-vscsi");
- break;
- case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1078:
- virBufferAddLit(&buf, "megasas");
- break;
- default:
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Unsupported controller model: %s"),
- virDomainControllerModelSCSITypeToString(def->model));
- }
- virBufferAsprintf(&buf, ",id=%s", def->info.alias);
+ if (!(contAlias = virDomainControllerAliasFind(def,
VIR_DOMAIN_CONTROLLER_TYPE_IDE,
+
disk->info.addr.drive.controller)))
+ goto error;
+ virBufferAsprintf(&opt, ",bus=%s.%d,unit=%d",
+ contAlias,
+ disk->info.addr.drive.bus,
+ disk->info.addr.drive.unit);
break;
- case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
- if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
- virBufferAddLit(&buf, "virtio-serial-pci");
- } else if (def->info.type ==
- VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
- virBufferAddLit(&buf, "virtio-serial-ccw");
- } else if (def->info.type ==
- VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
- virBufferAddLit(&buf, "virtio-serial-s390");
- } else if (def->info.type ==
- VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) {
- virBufferAddLit(&buf, "virtio-serial-device");
- } else {
- virBufferAddLit(&buf, "virtio-serial");
+ case VIR_DOMAIN_DISK_BUS_SCSI:
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_BLOCK)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("This QEMU doesn't support scsi-block for
"
+ "lun passthrough"));
+ goto error;
+ }
}
- virBufferAsprintf(&buf, ",id=%s", def->info.alias);
- if (def->opts.vioserial.ports != -1) {
- virBufferAsprintf(&buf, ",max_ports=%d",
- def->opts.vioserial.ports);
+
+ if (disk->wwn &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_WWN)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Setting wwn for scsi disk is not supported "
+ "by this QEMU"));
+ goto error;
}
- if (def->opts.vioserial.vectors != -1) {
- virBufferAsprintf(&buf, ",vectors=%d",
- def->opts.vioserial.vectors);
+
+ /* Properties wwn, vendor and product were introduced in the
+ * same QEMU release (1.2.0).
+ */
+ if ((disk->vendor || disk->product) &&
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_WWN)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Setting vendor or product for scsi disk is not "
+ "supported by this QEMU"));
+ goto error;
}
- break;
- case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
- virBufferAsprintf(&buf, "usb-ccid,id=%s", def->info.alias);
+ controllerModel =
+ virDomainDeviceFindControllerModel(def, &disk->info,
+ VIR_DOMAIN_CONTROLLER_TYPE_SCSI);
+ if ((qemuDomainSetSCSIControllerModel(def, qemuCaps,
+ &controllerModel)) < 0)
+ goto error;
+
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
+ virBufferAddLit(&opt, "scsi-block");
+ } else {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_CD)) {
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
+ virBufferAddLit(&opt, "scsi-cd");
+ else
+ virBufferAddLit(&opt, "scsi-hd");
+ } else {
+ virBufferAddLit(&opt, "scsi-disk");
+ }
+ }
+
+ if (!(contAlias = virDomainControllerAliasFind(def,
VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
+
disk->info.addr.drive.controller)))
+ goto error;
+
+ if (controllerModel == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC) {
+ if (disk->info.addr.drive.target != 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("target must be 0 for controller "
+ "model 'lsilogic'"));
+ goto error;
+ }
+
+ virBufferAsprintf(&opt, ",bus=%s.%d,scsi-id=%d",
+ contAlias,
+ disk->info.addr.drive.bus,
+ disk->info.addr.drive.unit);
+ } else {
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_CHANNEL)) {
+ if (disk->info.addr.drive.target > 7) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("This QEMU doesn't support target "
+ "greater than 7"));
+ goto error;
+ }
+
+ if (disk->info.addr.drive.bus != 0 &&
+ disk->info.addr.drive.unit != 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("This QEMU only supports both bus and "
+ "unit equal to 0"));
+ goto error;
+ }
+ }
+
+ virBufferAsprintf(&opt,
",bus=%s.0,channel=%d,scsi-id=%d,lun=%d",
+ contAlias,
+ disk->info.addr.drive.bus,
+ disk->info.addr.drive.target,
+ disk->info.addr.drive.unit);
+ }
break;
- case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_AHCI)) {
+ case VIR_DOMAIN_DISK_BUS_SATA:
+ if (disk->info.addr.drive.bus != 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("SATA is not supported with this "
- "QEMU binary"));
+ _("bus must be 0 for ide controller"));
goto error;
}
- virBufferAsprintf(&buf, "ahci,id=%s", def->info.alias);
- break;
-
- case VIR_DOMAIN_CONTROLLER_TYPE_USB:
- if (qemuBuildUSBControllerDevStr(domainDef, def, qemuCaps, &buf) == -1)
+ if (disk->info.addr.drive.target != 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("target must be 0 for ide controller"));
goto error;
+ }
- if (nusbcontroller)
- *nusbcontroller += 1;
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_CD)) {
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
+ virBufferAddLit(&opt, "ide-cd");
+ else
+ virBufferAddLit(&opt, "ide-hd");
+ } else {
+ virBufferAddLit(&opt, "ide-drive");
+ }
+ if (!(contAlias = virDomainControllerAliasFind(def,
VIR_DOMAIN_CONTROLLER_TYPE_SATA,
+
disk->info.addr.drive.controller)))
+ goto error;
+ virBufferAsprintf(&opt, ",bus=%s.%d",
+ contAlias,
+ disk->info.addr.drive.unit);
break;
- case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
- if (def->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT ||
- def->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) {
+ case VIR_DOMAIN_DISK_BUS_VIRTIO:
+ if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
+ virBufferAddLit(&opt, "virtio-blk-ccw");
+ if (disk->iothread)
+ virBufferAsprintf(&opt, ",iothread=iothread%u",
disk->iothread);
+ } else if (disk->info.type ==
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
+ virBufferAddLit(&opt, "virtio-blk-s390");
+ } else if (disk->info.type ==
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) {
+ virBufferAddLit(&opt, "virtio-blk-device");
+ } else {
+ virBufferAddLit(&opt, "virtio-blk-pci");
+ if (disk->iothread)
+ virBufferAsprintf(&opt, ",iothread=iothread%u",
disk->iothread);
+ }
+ qemuBuildIoEventFdStr(&opt, disk->ioeventfd, qemuCaps);
+ if (disk->event_idx &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_EVENT_IDX)) {
+ virBufferAsprintf(&opt, ",event_idx=%s",
+ virTristateSwitchTypeToString(disk->event_idx));
+ }
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_SCSI)) {
+ /* if sg_io is true but the scsi option isn't supported,
+ * that means it's just always on in this version of qemu.
+ */
+ virBufferAsprintf(&opt, ",scsi=%s",
+ (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN)
+ ? "on" : "off");
+ }
+ if (qemuBuildDeviceAddressStr(&opt, def, &disk->info, qemuCaps) <
0)
+ goto error;
+ break;
+
+ case VIR_DOMAIN_DISK_BUS_USB:
+ if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
+ disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("wrong function called for pci-root/pcie-root"));
- return NULL;
+ _("unexpected address type for usb disk"));
+ goto error;
}
- if (def->idx == 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("index for pci controllers of model '%s' must
be > 0"),
- virDomainControllerModelPCITypeToString(def->model));
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("This QEMU doesn't support '-device "
+ "usb-storage'"));
goto error;
+
}
- switch (def->model) {
- case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
- if (def->opts.pciopts.modelName
- == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE ||
- def->opts.pciopts.chassisNr == -1) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("autogenerated pci-bridge options not set"));
- goto error;
- }
+ virBufferAddLit(&opt, "usb-storage");
- modelName =
virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
- if (!modelName) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unknown pci-bridge model name value %d"),
- def->opts.pciopts.modelName);
- goto error;
- }
- if (def->opts.pciopts.modelName
- != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCI_BRIDGE) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("PCI controller model name '%s' "
- "is not valid for a pci-bridge"),
- modelName);
- goto error;
- }
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("the pci-bridge controller "
- "is not supported in this QEMU binary"));
- goto error;
- }
- virBufferAsprintf(&buf, "%s,chassis_nr=%d,id=%s",
- modelName, def->opts.pciopts.chassisNr,
- def->info.alias);
- break;
- case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
- if (def->opts.pciopts.modelName
- == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("autogenerated dmi-to-pci-bridge options not
set"));
- goto error;
- }
-
- modelName =
virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
- if (!modelName) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unknown dmi-to-pci-bridge model name value
%d"),
- def->opts.pciopts.modelName);
- goto error;
- }
- if (def->opts.pciopts.modelName
- != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_I82801B11_BRIDGE) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("PCI controller model name '%s' "
- "is not valid for a dmi-to-pci-bridge"),
- modelName);
- goto error;
- }
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("the dmi-to-pci-bridge (i82801b11-bridge) "
- "controller is not supported in this QEMU
binary"));
- goto error;
- }
- virBufferAsprintf(&buf, "%s,id=%s", modelName,
def->info.alias);
- break;
- case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
- if (def->opts.pciopts.modelName
- == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("autogenerated pcie-root-port options not
set"));
- goto error;
- }
- modelName =
virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
- if (!modelName) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unknown pcie-root-port model name value
%d"),
- def->opts.pciopts.modelName);
- goto error;
- }
- if (def->opts.pciopts.modelName
- != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_IOH3420) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("PCI controller model name '%s' "
- "is not valid for a pcie-root-port"),
- modelName);
- goto error;
- }
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IOH3420)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("the pcie-root-port (ioh3420) "
- "controller is not supported in this QEMU
binary"));
- goto error;
- }
-
- virBufferAsprintf(&buf, "%s,port=0x%x,chassis=%d,id=%s",
- modelName, def->opts.pciopts.port,
- def->opts.pciopts.chassis, def->info.alias);
- break;
- case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
- if (def->opts.pciopts.modelName
- == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("autogenerated pcie-switch-upstream-port options
not set"));
- goto error;
- }
- modelName =
virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
- if (!modelName) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unknown pcie-switch-upstream-port model name value
%d"),
- def->opts.pciopts.modelName);
- goto error;
- }
- if (def->opts.pciopts.modelName
- != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_X3130_UPSTREAM) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("PCI controller model name '%s' "
- "is not valid for a
pcie-switch-upstream-port"),
- modelName);
- goto error;
- }
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_X3130_UPSTREAM)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("the pcie-switch-upstream-port (x3130-upstream)
"
- "controller is not supported in this QEMU
binary"));
- goto error;
- }
-
- virBufferAsprintf(&buf, "%s,id=%s", modelName,
def->info.alias);
- break;
- case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
- if (def->opts.pciopts.modelName
- == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE ||
- def->opts.pciopts.chassis == -1 ||
- def->opts.pciopts.port == -1) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("autogenerated pcie-switch-downstream-port "
- "options not set"));
- goto error;
- }
-
- modelName =
virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
- if (!modelName) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unknown pcie-switch-downstream-port model name
value %d"),
- def->opts.pciopts.modelName);
- goto error;
- }
- if (def->opts.pciopts.modelName
- != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_XIO3130_DOWNSTREAM) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("PCI controller model name '%s' "
- "is not valid for a
pcie-switch-downstream-port"),
- modelName);
- goto error;
- }
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_XIO3130_DOWNSTREAM)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("The pcie-switch-downstream-port "
- "(xio3130-downstream) controller "
- "is not supported in this QEMU binary"));
- goto error;
- }
- virBufferAsprintf(&buf, "%s,port=0x%x,chassis=%d,id=%s",
- modelName, def->opts.pciopts.port,
- def->opts.pciopts.chassis, def->info.alias);
- break;
- }
+ if (qemuBuildDeviceAddressStr(&opt, def, &disk->info, qemuCaps) <
0)
+ goto error;
break;
- case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
- /* Since we currently only support the integrated IDE
- * controller on various boards, if we ever get to here, it's
- * because some other machinetype had an IDE controller
- * specified, or one with a single IDE contraller had multiple
- * ide controllers specified.
- */
- if (qemuDomainMachineHasBuiltinIDE(domainDef))
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Only a single IDE controller is supported "
- "for this machine type"));
- else
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("IDE controllers are unsupported for "
- "this QEMU binary or machine type"));
- goto error;
-
default:
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Unsupported controller type: %s"),
- virDomainControllerTypeToString(def->type));
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported disk bus '%s' with device
setup"), bus);
goto error;
}
- if (def->queues)
- virBufferAsprintf(&buf, ",num_queues=%u", def->queues);
+ virBufferAsprintf(&opt, ",drive=%s%s", QEMU_DRIVE_HOST_PREFIX,
disk->info.alias);
+ virBufferAsprintf(&opt, ",id=%s", disk->info.alias);
+ if (bootindex && virQEMUCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX))
+ virBufferAsprintf(&opt, ",bootindex=%d", bootindex);
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKIO)) {
+ if (disk->blockio.logical_block_size > 0)
+ virBufferAsprintf(&opt, ",logical_block_size=%u",
+ disk->blockio.logical_block_size);
+ if (disk->blockio.physical_block_size > 0)
+ virBufferAsprintf(&opt, ",physical_block_size=%u",
+ disk->blockio.physical_block_size);
+ }
- if (def->cmd_per_lun)
- virBufferAsprintf(&buf, ",cmd_per_lun=%u", def->cmd_per_lun);
+ if (disk->wwn) {
+ if (STRPREFIX(disk->wwn, "0x"))
+ virBufferAsprintf(&opt, ",wwn=%s", disk->wwn);
+ else
+ virBufferAsprintf(&opt, ",wwn=0x%s", disk->wwn);
+ }
- if (def->max_sectors)
- virBufferAsprintf(&buf, ",max_sectors=%u", def->max_sectors);
+ if (disk->vendor)
+ virBufferAsprintf(&opt, ",vendor=%s", disk->vendor);
- qemuBuildIoEventFdStr(&buf, def->ioeventfd, qemuCaps);
+ if (disk->product)
+ virBufferAsprintf(&opt, ",product=%s", disk->product);
- if (qemuBuildDeviceAddressStr(&buf, domainDef, &def->info, qemuCaps) <
0)
- goto error;
+ if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_STORAGE_REMOVABLE)) {
+ if (disk->removable == VIR_TRISTATE_SWITCH_ON)
+ virBufferAddLit(&opt, ",removable=on");
+ else
+ virBufferAddLit(&opt, ",removable=off");
+ } else {
+ if (disk->removable != VIR_TRISTATE_SWITCH_ABSENT) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("This QEMU doesn't support setting the "
+ "removable flag of USB storage devices"));
+ goto error;
+ }
+ }
+ }
- if (virBufferCheckError(&buf) < 0)
+ if (virBufferCheckError(&opt) < 0)
goto error;
- return virBufferContentAndReset(&buf);
+ return virBufferContentAndReset(&opt);
error:
- virBufferFreeAndReset(&buf);
+ virBufferFreeAndReset(&opt);
return NULL;
}
-/**
- * qemuBuildMemoryBackendStr:
- * @size: size of the memory device in kibibytes
- * @pagesize: size of the requested memory page in KiB, 0 for default
- * @guestNode: NUMA node in the guest that the memory object will be attached
- * to, or -1 if NUMA is not used in the guest
- * @hostNodes: map of host nodes to alloc the memory in, NULL for default
- * @autoNodeset: fallback nodeset in case of automatic numa placement
- * @def: domain definition object
- * @qemuCaps: qemu capabilities object
- * @cfg: qemu driver config object
- * @aliasPrefix: prefix string of the alias (to allow for multiple frontents)
- * @id: index of the device (to construct the alias)
- * @backendStr: returns the object string
- *
- * Formats the configuration string for the memory device backend according
- * to the configuration. @pagesize and @hostNodes can be used to override the
- * default source configuration, both are optional.
- *
- * Returns 0 on success, 1 if only the implicit memory-device-ram with no
- * other configuration was used (to detect legacy configurations). Returns
- * -1 in case of an error.
- */
-int
-qemuBuildMemoryBackendStr(unsigned long long size,
- unsigned long long pagesize,
- int guestNode,
- virBitmapPtr userNodeset,
- virBitmapPtr autoNodeset,
- virDomainDefPtr def,
- virQEMUCapsPtr qemuCaps,
- virQEMUDriverConfigPtr cfg,
- const char **backendType,
- virJSONValuePtr *backendProps,
- bool force)
+char *qemuBuildFSStr(virDomainFSDefPtr fs,
+ virQEMUCapsPtr qemuCaps ATTRIBUTE_UNUSED)
{
- virDomainHugePagePtr master_hugepage = NULL;
- virDomainHugePagePtr hugepage = NULL;
- virDomainNumatuneMemMode mode;
- const long system_page_size = virGetSystemPageSizeKB();
- virNumaMemAccess memAccess = VIR_NUMA_MEM_ACCESS_DEFAULT;
- size_t i;
- char *mem_path = NULL;
- virBitmapPtr nodemask = NULL;
- int ret = -1;
- virJSONValuePtr props = NULL;
- bool nodeSpecified = virDomainNumatuneNodeSpecified(def->numa, guestNode);
-
- *backendProps = NULL;
- *backendType = NULL;
-
- if (guestNode >= 0) {
- /* 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;
- }
+ virBuffer opt = VIR_BUFFER_INITIALIZER;
+ const char *driver = qemuDomainFSDriverTypeToString(fs->fsdriver);
+ const char *wrpolicy = virDomainFSWrpolicyTypeToString(fs->wrpolicy);
- memAccess = virDomainNumaGetNodeMemoryAccessMode(def->numa, guestNode);
+ if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("only supports mount filesystem type"));
+ goto error;
}
- if (virDomainNumatuneGetMode(def->numa, guestNode, &mode) < 0 &&
- virDomainNumatuneGetMode(def->numa, -1, &mode) < 0)
- mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
-
- if (pagesize == 0) {
- /* Find the huge page size we want to use */
- for (i = 0; i < def->mem.nhugepages; i++) {
- bool thisHugepage = false;
-
- hugepage = &def->mem.hugepages[i];
-
- if (!hugepage->nodemask) {
- master_hugepage = hugepage;
- continue;
- }
-
- /* just find the master hugepage in case we don't use NUMA */
- if (guestNode < 0)
- continue;
-
- if (virBitmapGetBit(hugepage->nodemask, guestNode,
- &thisHugepage) < 0) {
- /* Ignore this error. It's not an error after all. Well,
- * the nodemask for this <page/> can contain lower NUMA
- * nodes than we are querying in here. */
- continue;
- }
+ if (!driver) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Filesystem driver type not supported"));
+ goto error;
+ }
+ virBufferAdd(&opt, driver, -1);
- if (thisHugepage) {
- /* Hooray, we've found the page size */
- break;
- }
+ if (fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_PATH ||
+ fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_DEFAULT) {
+ if (fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_MAPPED) {
+ virBufferAddLit(&opt, ",security_model=mapped");
+ } else if (fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) {
+ virBufferAddLit(&opt, ",security_model=passthrough");
+ } else if (fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_SQUASH) {
+ virBufferAddLit(&opt, ",security_model=none");
}
-
- if (i == def->mem.nhugepages) {
- /* We have not found specific huge page to be used with this
- * NUMA node. Use the generic setting then (<page/> without any
- * @nodemask) if possible. */
- hugepage = master_hugepage;
+ } else {
+ /* For other fs drivers, default(passthru) should always
+ * be supported */
+ if (fs->accessmode != VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("only supports passthrough accessmode"));
+ goto error;
}
-
- if (hugepage)
- pagesize = hugepage->size;
}
- if (pagesize == system_page_size) {
- /* However, if user specified to use "huge" page
- * of regular system page size, it's as if they
- * hasn't specified any huge pages at all. */
- pagesize = 0;
- hugepage = NULL;
+ if (fs->wrpolicy) {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_FSDEV_WRITEOUT)) {
+ virBufferAsprintf(&opt, ",writeout=%s", wrpolicy);
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("filesystem writeout not supported"));
+ goto error;
+ }
}
- if (!(props = virJSONValueNewObject()))
- return -1;
-
- if (pagesize || hugepage) {
- if (pagesize) {
- /* Now lets see, if the huge page we want to use is even mounted
- * and ready to use */
- for (i = 0; i < cfg->nhugetlbfs; i++) {
- if (cfg->hugetlbfs[i].size == pagesize)
- break;
- }
-
- if (i == cfg->nhugetlbfs) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unable to find any usable hugetlbfs mount for %llu
KiB"),
- pagesize);
- goto cleanup;
- }
+ virBufferAsprintf(&opt, ",id=%s%s", QEMU_FSDEV_HOST_PREFIX,
fs->info.alias);
+ virBufferAsprintf(&opt, ",path=%s", fs->src);
- if (!(mem_path = qemuGetHugepagePath(&cfg->hugetlbfs[i])))
- goto cleanup;
+ if (fs->readonly) {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_FSDEV_READONLY)) {
+ virBufferAddLit(&opt, ",readonly");
} else {
- if (!(mem_path = qemuGetDefaultHugepath(cfg->hugetlbfs,
- cfg->nhugetlbfs)))
- goto cleanup;
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("readonly filesystem is not supported by this "
+ "QEMU binary"));
+ goto error;
}
+ }
- *backendType = "memory-backend-file";
-
- if (virJSONValueObjectAdd(props,
- "b:prealloc", true,
- "s:mem-path", mem_path,
- NULL) < 0)
- goto cleanup;
-
- switch (memAccess) {
- case VIR_NUMA_MEM_ACCESS_SHARED:
- if (virJSONValueObjectAdd(props, "b:share", true, NULL) < 0)
- goto cleanup;
- break;
+ if (virBufferCheckError(&opt) < 0)
+ goto error;
- case VIR_NUMA_MEM_ACCESS_PRIVATE:
- if (virJSONValueObjectAdd(props, "b:share", false, NULL) < 0)
- goto cleanup;
- break;
+ return virBufferContentAndReset(&opt);
- case VIR_NUMA_MEM_ACCESS_DEFAULT:
- case VIR_NUMA_MEM_ACCESS_LAST:
- break;
- }
- } else {
- if (memAccess) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Shared memory mapping is supported "
- "only with hugepages"));
- goto cleanup;
- }
+ error:
+ virBufferFreeAndReset(&opt);
+ return NULL;
+}
- *backendType = "memory-backend-ram";
- }
- if (virJSONValueObjectAdd(props, "U:size", size * 1024, NULL) < 0)
- goto cleanup;
+char *
+qemuBuildFSDevStr(virDomainDefPtr def,
+ virDomainFSDefPtr fs,
+ virQEMUCapsPtr qemuCaps)
+{
+ virBuffer opt = VIR_BUFFER_INITIALIZER;
- if (userNodeset) {
- nodemask = userNodeset;
- } else {
- if (virDomainNumatuneMaybeGetNodeset(def->numa, autoNodeset,
- &nodemask, guestNode) < 0)
- goto cleanup;
+ if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("can only passthrough directories"));
+ goto error;
}
- if (nodemask) {
- if (!virNumaNodesetIsAvailable(nodemask))
- goto cleanup;
- if (virJSONValueObjectAdd(props,
- "m:host-nodes", nodemask,
- "S:policy",
qemuNumaPolicyTypeToString(mode),
- NULL) < 0)
- goto cleanup;
- }
+ if (fs->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
+ virBufferAddLit(&opt, "virtio-9p-ccw");
+ else
+ virBufferAddLit(&opt, "virtio-9p-pci");
- /* If none of the following is requested... */
- if (!pagesize && !userNodeset && !memAccess && !nodeSpecified
&& !force) {
- /* report back that using the new backend is not necessary
- * to achieve the desired configuration */
- ret = 1;
- } else {
- /* otherwise check the required capability */
- if (STREQ(*backendType, "memory-backend-file") &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("this qemu doesn't support the "
- "memory-backend-file object"));
- goto cleanup;
- } else if (STREQ(*backendType, "memory-backend-ram") &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("this qemu doesn't support the "
- "memory-backend-ram object"));
- goto cleanup;
- }
+ virBufferAsprintf(&opt, ",id=%s", fs->info.alias);
+ virBufferAsprintf(&opt, ",fsdev=%s%s", QEMU_FSDEV_HOST_PREFIX,
fs->info.alias);
+ virBufferAsprintf(&opt, ",mount_tag=%s", fs->dst);
- ret = 0;
- }
+ if (qemuBuildDeviceAddressStr(&opt, def, &fs->info, qemuCaps) < 0)
+ goto error;
- *backendProps = props;
- props = NULL;
+ if (virBufferCheckError(&opt) < 0)
+ goto error;
- cleanup:
- virJSONValueFree(props);
- VIR_FREE(mem_path);
+ return virBufferContentAndReset(&opt);
- return ret;
+ error:
+ virBufferFreeAndReset(&opt);
+ return NULL;
}
static int
-qemuBuildMemoryCellBackendStr(virDomainDefPtr def,
- virQEMUCapsPtr qemuCaps,
- virQEMUDriverConfigPtr cfg,
- size_t cell,
- virBitmapPtr auto_nodeset,
- char **backendStr)
+qemuControllerModelUSBToCaps(int model)
{
- virJSONValuePtr props = NULL;
- char *alias = NULL;
- const char *backendType;
- int ret = -1;
- int rc;
- unsigned long long memsize = virDomainNumaGetNodeMemorySize(def->numa,
- cell);
+ switch (model) {
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI:
+ return QEMU_CAPS_PIIX3_USB_UHCI;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI:
+ return QEMU_CAPS_PIIX4_USB_UHCI;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI:
+ return QEMU_CAPS_USB_EHCI;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1:
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1:
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2:
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3:
+ return QEMU_CAPS_ICH9_USB_EHCI1;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI:
+ return QEMU_CAPS_VT82C686B_USB_UHCI;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI:
+ return QEMU_CAPS_PCI_OHCI;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI:
+ return QEMU_CAPS_NEC_USB_XHCI;
+ default:
+ return -1;
+ }
+}
- *backendStr = NULL;
- if (virAsprintf(&alias, "ram-node%zu", cell) < 0)
- goto cleanup;
+static int
+qemuBuildUSBControllerDevStr(virDomainDefPtr domainDef,
+ virDomainControllerDefPtr def,
+ virQEMUCapsPtr qemuCaps,
+ virBuffer *buf)
+{
+ const char *smodel;
+ int model, flags;
- if ((rc = qemuBuildMemoryBackendStr(memsize, 0, cell, NULL, auto_nodeset,
- def, qemuCaps, cfg, &backendType,
- &props, false)) < 0)
- goto cleanup;
+ model = def->model;
- if (!(*backendStr = qemuBuildObjectCommandlineFromJSON(backendType,
- alias,
- props)))
- goto cleanup;
+ if (model == -1) {
+ if ARCH_IS_PPC64(domainDef->os.arch)
+ model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI;
+ else
+ model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI;
+ }
- ret = rc;
+ smodel = qemuControllerModelUSBTypeToString(model);
+ flags = qemuControllerModelUSBToCaps(model);
- cleanup:
- VIR_FREE(alias);
- virJSONValueFree(props);
+ if (flags == -1 || !virQEMUCapsGet(qemuCaps, flags)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("%s not supported in this QEMU binary"), smodel);
+ return -1;
+ }
- return ret;
-}
+ virBufferAsprintf(buf, "%s", smodel);
+ if (def->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB)
+ virBufferAsprintf(buf, ",masterbus=%s.0,firstport=%d",
+ def->info.alias, def->info.master.usb.startport);
+ else
+ virBufferAsprintf(buf, ",id=%s", def->info.alias);
-static char *
-qemuBuildMemoryDimmBackendStr(virDomainMemoryDefPtr mem,
- virDomainDefPtr def,
- virQEMUCapsPtr qemuCaps,
- virQEMUDriverConfigPtr cfg)
+ return 0;
+}
+
+char *
+qemuBuildControllerDevStr(virDomainDefPtr domainDef,
+ virDomainControllerDefPtr def,
+ virQEMUCapsPtr qemuCaps,
+ int *nusbcontroller)
{
- virJSONValuePtr props = NULL;
- char *alias = NULL;
- const char *backendType;
- char *ret = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int model = def->model;
+ const char *modelName = NULL;
- if (!mem->info.alias) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("memory device alias is not assigned"));
+ if (!qemuCheckCCWS390AddressSupport(domainDef, def->info, qemuCaps,
+ "controller"))
return NULL;
+
+ if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
+ if ((qemuDomainSetSCSIControllerModel(domainDef, qemuCaps, &model)) < 0)
+ return NULL;
}
- if (virAsprintf(&alias, "mem%s", mem->info.alias) < 0)
- goto cleanup;
+ if (!(def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
+ model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI)) {
+ if (def->queues) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("'queues' is only supported by virtio-scsi
controller"));
+ return NULL;
+ }
+ if (def->cmd_per_lun) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("'cmd_per_lun' is only supported by virtio-scsi
controller"));
+ return NULL;
+ }
+ if (def->max_sectors) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("'max_sectors' is only supported by virtio-scsi
controller"));
+ return NULL;
+ }
+ if (def->ioeventfd) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("'ioeventfd' is only supported by virtio-scsi
controller"));
+ return NULL;
+ }
+ }
- if (qemuBuildMemoryBackendStr(mem->size, mem->pagesize,
- mem->targetNode, mem->sourceNodes, NULL,
- def, qemuCaps, cfg,
- &backendType, &props, true) < 0)
- goto cleanup;
+ switch (def->type) {
+ case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
+ switch (model) {
+ case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
+ if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
+ virBufferAddLit(&buf, "virtio-scsi-ccw");
+ else if (def->info.type ==
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)
+ virBufferAddLit(&buf, "virtio-scsi-s390");
+ else if (def->info.type ==
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO)
+ virBufferAddLit(&buf, "virtio-scsi-device");
+ else
+ virBufferAddLit(&buf, "virtio-scsi-pci");
+ break;
+ case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC:
+ virBufferAddLit(&buf, "lsi");
+ break;
+ case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI:
+ virBufferAddLit(&buf, "spapr-vscsi");
+ break;
+ case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1078:
+ virBufferAddLit(&buf, "megasas");
+ break;
+ default:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unsupported controller model: %s"),
+ virDomainControllerModelSCSITypeToString(def->model));
+ }
+ virBufferAsprintf(&buf, ",id=%s", def->info.alias);
+ break;
- ret = qemuBuildObjectCommandlineFromJSON(backendType, alias, props);
+ case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
+ if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+ virBufferAddLit(&buf, "virtio-serial-pci");
+ } else if (def->info.type ==
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
+ virBufferAddLit(&buf, "virtio-serial-ccw");
+ } else if (def->info.type ==
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
+ virBufferAddLit(&buf, "virtio-serial-s390");
+ } else if (def->info.type ==
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) {
+ virBufferAddLit(&buf, "virtio-serial-device");
+ } else {
+ virBufferAddLit(&buf, "virtio-serial");
+ }
+ virBufferAsprintf(&buf, ",id=%s", def->info.alias);
+ if (def->opts.vioserial.ports != -1) {
+ virBufferAsprintf(&buf, ",max_ports=%d",
+ def->opts.vioserial.ports);
+ }
+ if (def->opts.vioserial.vectors != -1) {
+ virBufferAsprintf(&buf, ",vectors=%d",
+ def->opts.vioserial.vectors);
+ }
+ break;
- cleanup:
- VIR_FREE(alias);
- virJSONValueFree(props);
+ case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
+ virBufferAsprintf(&buf, "usb-ccid,id=%s", def->info.alias);
+ break;
- return ret;
-}
+ case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_AHCI)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("SATA is not supported with this "
+ "QEMU binary"));
+ goto error;
+ }
+ virBufferAsprintf(&buf, "ahci,id=%s", def->info.alias);
+ break;
+ case VIR_DOMAIN_CONTROLLER_TYPE_USB:
+ if (qemuBuildUSBControllerDevStr(domainDef, def, qemuCaps, &buf) == -1)
+ goto error;
-char *
-qemuBuildMemoryDeviceStr(virDomainMemoryDefPtr mem)
-{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
+ if (nusbcontroller)
+ *nusbcontroller += 1;
+
+ break;
+
+ case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
+ if (def->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT ||
+ def->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("wrong function called for pci-root/pcie-root"));
+ return NULL;
+ }
+ if (def->idx == 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("index for pci controllers of model '%s' must
be > 0"),
+ virDomainControllerModelPCITypeToString(def->model));
+ goto error;
+ }
+ switch (def->model) {
+ case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
+ if (def->opts.pciopts.modelName
+ == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE ||
+ def->opts.pciopts.chassisNr == -1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("autogenerated pci-bridge options not set"));
+ goto error;
+ }
+
+ modelName =
virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
+ if (!modelName) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown pci-bridge model name value %d"),
+ def->opts.pciopts.modelName);
+ goto error;
+ }
+ if (def->opts.pciopts.modelName
+ != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCI_BRIDGE) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("PCI controller model name '%s' "
+ "is not valid for a pci-bridge"),
+ modelName);
+ goto error;
+ }
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("the pci-bridge controller "
+ "is not supported in this QEMU binary"));
+ goto error;
+ }
+ virBufferAsprintf(&buf, "%s,chassis_nr=%d,id=%s",
+ modelName, def->opts.pciopts.chassisNr,
+ def->info.alias);
+ break;
+ case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
+ if (def->opts.pciopts.modelName
+ == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("autogenerated dmi-to-pci-bridge options not
set"));
+ goto error;
+ }
+
+ modelName =
virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
+ if (!modelName) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown dmi-to-pci-bridge model name value
%d"),
+ def->opts.pciopts.modelName);
+ goto error;
+ }
+ if (def->opts.pciopts.modelName
+ != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_I82801B11_BRIDGE) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("PCI controller model name '%s' "
+ "is not valid for a dmi-to-pci-bridge"),
+ modelName);
+ goto error;
+ }
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("the dmi-to-pci-bridge (i82801b11-bridge) "
+ "controller is not supported in this QEMU
binary"));
+ goto error;
+ }
+ virBufferAsprintf(&buf, "%s,id=%s", modelName,
def->info.alias);
+ break;
+ case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
+ if (def->opts.pciopts.modelName
+ == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("autogenerated pcie-root-port options not
set"));
+ goto error;
+ }
+ modelName =
virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
+ if (!modelName) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown pcie-root-port model name value
%d"),
+ def->opts.pciopts.modelName);
+ goto error;
+ }
+ if (def->opts.pciopts.modelName
+ != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_IOH3420) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("PCI controller model name '%s' "
+ "is not valid for a pcie-root-port"),
+ modelName);
+ goto error;
+ }
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IOH3420)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("the pcie-root-port (ioh3420) "
+ "controller is not supported in this QEMU
binary"));
+ goto error;
+ }
+
+ virBufferAsprintf(&buf, "%s,port=0x%x,chassis=%d,id=%s",
+ modelName, def->opts.pciopts.port,
+ def->opts.pciopts.chassis, def->info.alias);
+ break;
+ case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
+ if (def->opts.pciopts.modelName
+ == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("autogenerated pcie-switch-upstream-port options
not set"));
+ goto error;
+ }
+ modelName =
virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
+ if (!modelName) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown pcie-switch-upstream-port model name value
%d"),
+ def->opts.pciopts.modelName);
+ goto error;
+ }
+ if (def->opts.pciopts.modelName
+ != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_X3130_UPSTREAM) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("PCI controller model name '%s' "
+ "is not valid for a
pcie-switch-upstream-port"),
+ modelName);
+ goto error;
+ }
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_X3130_UPSTREAM)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("the pcie-switch-upstream-port (x3130-upstream)
"
+ "controller is not supported in this QEMU
binary"));
+ goto error;
+ }
+
+ virBufferAsprintf(&buf, "%s,id=%s", modelName,
def->info.alias);
+ break;
+ case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
+ if (def->opts.pciopts.modelName
+ == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE ||
+ def->opts.pciopts.chassis == -1 ||
+ def->opts.pciopts.port == -1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("autogenerated pcie-switch-downstream-port "
+ "options not set"));
+ goto error;
+ }
- if (!mem->info.alias) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("missing alias for memory device"));
- return NULL;
- }
+ modelName =
virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
+ if (!modelName) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown pcie-switch-downstream-port model name
value %d"),
+ def->opts.pciopts.modelName);
+ goto error;
+ }
+ if (def->opts.pciopts.modelName
+ != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_XIO3130_DOWNSTREAM) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("PCI controller model name '%s' "
+ "is not valid for a
pcie-switch-downstream-port"),
+ modelName);
+ goto error;
+ }
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_XIO3130_DOWNSTREAM)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("The pcie-switch-downstream-port "
+ "(xio3130-downstream) controller "
+ "is not supported in this QEMU binary"));
+ goto error;
+ }
+ virBufferAsprintf(&buf, "%s,port=0x%x,chassis=%d,id=%s",
+ modelName, def->opts.pciopts.port,
+ def->opts.pciopts.chassis, def->info.alias);
+ break;
+ }
+ break;
- switch ((virDomainMemoryModel) mem->model) {
- case VIR_DOMAIN_MEMORY_MODEL_DIMM:
- virBufferAddLit(&buf, "pc-dimm,");
+ case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
+ /* Since we currently only support the integrated IDE
+ * controller on various boards, if we ever get to here, it's
+ * because some other machinetype had an IDE controller
+ * specified, or one with a single IDE contraller had multiple
+ * ide controllers specified.
+ */
+ if (qemuDomainMachineHasBuiltinIDE(domainDef))
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Only a single IDE controller is supported "
+ "for this machine type"));
+ else
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("IDE controllers are unsupported for "
+ "this QEMU binary or machine type"));
+ goto error;
- if (mem->targetNode >= 0)
- virBufferAsprintf(&buf, "node=%d,", mem->targetNode);
+ default:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unsupported controller type: %s"),
+ virDomainControllerTypeToString(def->type));
+ goto error;
+ }
- virBufferAsprintf(&buf, "memdev=mem%s,id=%s",
- mem->info.alias, mem->info.alias);
+ if (def->queues)
+ virBufferAsprintf(&buf, ",num_queues=%u", def->queues);
- if (mem->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM) {
- virBufferAsprintf(&buf, ",slot=%d",
mem->info.addr.dimm.slot);
- virBufferAsprintf(&buf, ",addr=%llu",
mem->info.addr.dimm.base);
- }
+ if (def->cmd_per_lun)
+ virBufferAsprintf(&buf, ",cmd_per_lun=%u", def->cmd_per_lun);
- break;
+ if (def->max_sectors)
+ virBufferAsprintf(&buf, ",max_sectors=%u", def->max_sectors);
- case VIR_DOMAIN_MEMORY_MODEL_NONE:
- case VIR_DOMAIN_MEMORY_MODEL_LAST:
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("invalid memory device type"));
- break;
+ qemuBuildIoEventFdStr(&buf, def->ioeventfd, qemuCaps);
- }
+ if (qemuBuildDeviceAddressStr(&buf, domainDef, &def->info, qemuCaps) <
0)
+ goto error;
if (virBufferCheckError(&buf) < 0)
- return NULL;
+ goto error;
return virBufferContentAndReset(&buf);
+
+ error:
+ virBufferFreeAndReset(&buf);
+ return NULL;
}
@@ -5483,148 +5671,6 @@ qemuBuildClockArgStr(virDomainClockDefPtr def)
}
static int
-qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg,
- virDomainDefPtr def,
- virCommandPtr cmd,
- virQEMUCapsPtr qemuCaps,
- virBitmapPtr auto_nodeset)
-{
- size_t i;
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- char *cpumask = NULL, *tmpmask = NULL, *next = NULL;
- char **nodeBackends = NULL;
- bool needBackend = false;
- int rc;
- int ret = -1;
- size_t ncells = virDomainNumaGetNodeCount(def->numa);
- const long system_page_size = virGetSystemPageSizeKB();
-
- if (virDomainNumatuneHasPerNodeBinding(def->numa) &&
- !(virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM) ||
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE))) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Per-node memory binding is not supported "
- "with this QEMU"));
- goto cleanup;
- }
-
- if (def->mem.nhugepages &&
- def->mem.hugepages[0].size != system_page_size &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("huge pages per NUMA node are not "
- "supported with this QEMU"));
- goto cleanup;
- }
-
- if (!virDomainNumatuneNodesetIsAvailable(def->numa, auto_nodeset))
- goto cleanup;
-
- for (i = 0; i < def->mem.nhugepages; i++) {
- ssize_t next_bit, pos = 0;
-
- if (!def->mem.hugepages[i].nodemask) {
- /* This is the master hugepage to use. Skip it as it has no
- * nodemask anyway. */
- continue;
- }
-
- if (ncells) {
- /* Fortunately, we allow only guest NUMA nodes to be continuous
- * starting from zero. */
- pos = ncells - 1;
- }
-
- next_bit = virBitmapNextSetBit(def->mem.hugepages[i].nodemask, pos);
- if (next_bit >= 0) {
- virReportError(VIR_ERR_XML_DETAIL,
- _("hugepages: node %zd not found"),
- next_bit);
- goto cleanup;
- }
- }
-
- if (VIR_ALLOC_N(nodeBackends, ncells) < 0)
- goto cleanup;
-
- /* using of -numa memdev= cannot be combined with -numa mem=, thus we
- * need to check which approach to use */
- for (i = 0; i < ncells; i++) {
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM) ||
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) {
- if ((rc = qemuBuildMemoryCellBackendStr(def, qemuCaps, cfg, i,
- auto_nodeset,
- &nodeBackends[i])) < 0)
- goto cleanup;
-
- if (rc == 0)
- needBackend = true;
- } else {
- if (virDomainNumaGetNodeMemoryAccessMode(def->numa, i)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Shared memory mapping is not supported "
- "with this QEMU"));
- goto cleanup;
- }
- }
- }
-
- if (!needBackend &&
- qemuBuildMemPathStr(cfg, def, qemuCaps, cmd) < 0)
- goto cleanup;
-
- for (i = 0; i < ncells; i++) {
- VIR_FREE(cpumask);
- if (!(cpumask = virBitmapFormat(virDomainNumaGetNodeCpumask(def->numa, i))))
- goto cleanup;
-
- if (strchr(cpumask, ',') &&
- !virQEMUCapsGet(qemuCaps, QEMU_CAPS_NUMA)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("disjoint NUMA cpu ranges are not supported "
- "with this QEMU"));
- goto cleanup;
- }
-
- if (needBackend)
- virCommandAddArgList(cmd, "-object", nodeBackends[i], NULL);
-
- virCommandAddArg(cmd, "-numa");
- virBufferAsprintf(&buf, "node,nodeid=%zu", i);
-
- for (tmpmask = cpumask; tmpmask; tmpmask = next) {
- if ((next = strchr(tmpmask, ',')))
- *(next++) = '\0';
- virBufferAddLit(&buf, ",cpus=");
- virBufferAdd(&buf, tmpmask, -1);
- }
-
- if (needBackend)
- virBufferAsprintf(&buf, ",memdev=ram-node%zu", i);
- else
- virBufferAsprintf(&buf, ",mem=%llu",
- virDomainNumaGetNodeMemorySize(def->numa, i) / 1024);
-
- virCommandAddArgBuffer(cmd, &buf);
- }
- ret = 0;
-
- cleanup:
- VIR_FREE(cpumask);
-
- if (nodeBackends) {
- for (i = 0; i < ncells; i++)
- VIR_FREE(nodeBackends[i]);
-
- VIR_FREE(nodeBackends);
- }
-
- virBufferFreeAndReset(&buf);
- return ret;
-}
-
-
-static int
qemuBuildGraphicsVNCCommandLine(virQEMUDriverConfigPtr cfg,
virCommandPtr cmd,
virDomainDefPtr def,
@@ -6963,32 +7009,8 @@ qemuBuildCommandLine(virConnectPtr conn,
if (qemuBuildIOThreadCommandLine(cmd, def, qemuCaps) < 0)
goto error;
- if (virDomainNumaGetNodeCount(def->numa) &&
- 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]))) {
- VIR_FREE(backStr);
- goto error;
- }
-
- virCommandAddArgList(cmd, "-object", backStr, "-device",
dimmStr, NULL);
-
- VIR_FREE(backStr);
- VIR_FREE(dimmStr);
- }
+ if (qemuBuildNumaCommandLine(cmd, cfg, def, qemuCaps, nodeset) < 0)
+ goto error;
virCommandAddArgList(cmd, "-uuid", uuid, NULL);
--
2.5.0