[libvirt] [PATCH 10/10] qemu: Reorganize -numa arguments

John Ferlan jferlan at redhat.com
Wed Feb 17 00:44:20 UTC 2016


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 at 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




More information about the libvir-list mailing list