[libvirt] [PATCH 3/6] Introduce new XMLs to specify disk source using storage pool/vol

Osier Yang jyang at redhat.com
Wed Jan 23 11:04:35 UTC 2013


With this patch, one can specify the disk source using storage
pool/volume like:

  <disk type='file' device='disk'>
    <driver name='qemu' type='raw' cache='none'/>
    <source type='pool'>
      <volume key='/var/lib/libvirt/images/foo.img'/>
      <seclabel relabel='no'/>
    </source>
    <target dev='vdb' bus='virtio'/>
  </disk>

  <disk type='file' device='disk'>
    <driver name='qemu' type='raw' cache='none'/>
    <source type='pool'>
      <volume path='/var/lib/libvirt/images/foo.img'/>
      <seclabel relabel='no'/>
    </source>
    <target dev='vdb' bus='virtio'/>
  </disk>

  <disk type='file' device='disk'>
    <driver name='qemu' type='raw' cache='none'/>
    <source type='pool'>
      <pool uuid|name="$var"/>
      <volume name='foo.img'/>
      <seclabel relabel='no'/>
    </source>
    <target dev='vdb' bus='virtio'/>
  </disk>

Element <pool> is optional when the volume is specified by "path"
or "key", but mandatory if the volume is specified by "name", since
the volume name is not unique even locally (on host).

docs/formatdomain.html.in:
  * Add documents for new XMLs
docs/schemas/domaincommon.rng:
  * Add rng for new XMLs;
  * Abstract schema for network disk source as "diskSourceNetwork"
src/conf/domain_conf.h:
  * New member source_type to indicate the disk source type
  * New struct for pool type disk source (virDomainDiskSourcePoolDef)
  * New enum virDomainDiskSourceType for disk source type (default|pool)
  * New enum virDomainDiskSourcePoolType to represent how the pool
    is specified (name|uuid)
  * New enum virDomainDiskSourceVolType to represent how the volume
    is specified (name|path|key)
  * VIR_ENUM_DECL eum virDomainDiskSourceType
src/conf/domain_conf.c:
  * VIR_ENUM_IMPL enum virDomainDiskSourceType
  * New helper virDomainDiskSourcePoolDefParse to parse the 'pool'
    type source.
  * New helper virDomainDiskSourcePoolDefFree to free the 'pool'
    type source def
  * New helper virDomainDiskSourceDefFormat to format the disk source.
src/libvirt_private.syms:
  * Export the symbols produced by enum virDomainDiskSourceType
tests/qemuxml2argvdata/qemuxml2argv-disk-source-pool.xml:
tests/qemuxml2xmltest.c:
  * New test
---
 docs/formatdomain.html.in                          |   31 ++-
 docs/schemas/domaincommon.rng                      |  156 +++++---
 src/conf/domain_conf.c                             |  426 ++++++++++++++++----
 src/conf/domain_conf.h                             |   46 +++
 src/libvirt_private.syms                           |    2 +
 .../qemuxml2argv-disk-source-pool.xml              |   36 ++
 tests/qemuxml2xmltest.c                            |    1 +
 7 files changed, 554 insertions(+), 144 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-source-pool.xml

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index bb0b199..f418edb 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1367,6 +1367,17 @@
       <blockio logical_block_size='512' physical_block_size='4096'/>
       <target dev='hda' bus='ide'/>
     </disk>
+    <disk type='file' device='disk'>
+      <driver name='qemu' type='raw'/>
+      <source type='pool'/>
+        <pool name='nfspool0'/>
+        <volume name='nfspool0-vol0'/>
+      </source>
+      <geometry cyls='16383' heads='16' secs='63' trans='lba'/>
+      <blockio logical_block_size='512' physical_block_size='4096'/>
+      <target dev='hda' bus='ide'/>
+    </disk>
+
   </devices>
   ...</pre>
 
@@ -1424,9 +1435,23 @@
         "network" attribute since 0.8.7; "snapshot" since
         0.9.5</span></dd>
       <dt><code>source</code></dt>
-      <dd>If the disk <code>type</code> is "file", then
-        the <code>file</code> attribute specifies the fully-qualified
-        path to the file holding the disk. If the disk
+      <dd>Attribute <code>type</code> (<span class="since">since 1.0.3</span>),
+        specifies the disk source type, the only valid value is 'pool'.
+        'pool' source type has two sub-elements: <code>pool</code> and
+         <code>volume</code> (both <span class="since">since 1.0.3</span>).
+        Element <code>pool</code> specifies the storage pool (managed by
+        libvirt) where the disk source resides, it has two exclusive
+        attributes: <code>name</code> and <code>uuid</code>.  Element
+        <code>volume</code> specifies the storage volume (managed by libvirt)
+        that which as the disk source, it has three exclusive attributes:
+        <code>name</code>, <code>path</code>, and <code>key</code>.
+        <code>pool</code> must be specified by either <code>name</code> or
+        <code>uuid</code> if <code>volume</code> is specified by
+        <code>name</code>.
+        Except the 'pool' type, one can also specify the disk source
+        straightforward with following methods: If the disk <code>type</code>
+        is "file", then the <code>file</code> attribute specifies the
+        fully-qualified path to the file holding the disk. If the disk
         <code>type</code> is "block", then the <code>dev</code>
         attribute specifies the path to the host device to serve as
         the disk. With both "file" and "block", one or more optional
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 67ae864..b221647 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -1018,11 +1018,14 @@
           <interleave>
             <optional>
               <element name="source">
-                <optional>
-                  <attribute name="file">
-                    <ref name="absFilePath"/>
-                  </attribute>
-                </optional>
+                <choice>
+                  <optional>
+                    <attribute name="file">
+                      <ref name="absFilePath"/>
+                    </attribute>
+                  </optional>
+                  <ref name="diskSourcePool"/>
+                </choice>
                 <optional>
                   <ref name="startupPolicy"/>
                 </optional>
@@ -1041,9 +1044,12 @@
           <interleave>
             <optional>
               <element name="source">
-                <attribute name="dev">
-                  <ref name="absFilePath"/>
-                </attribute>
+                <choice>
+                  <attribute name="dev">
+                    <ref name="absFilePath"/>
+                  </attribute>
+                  <ref name="diskSourcePool"/>
+                </choice>
                 <optional>
                   <ref name='devSeclabel'/>
                 </optional>
@@ -1059,9 +1065,12 @@
           <interleave>
             <optional>
               <element name="source">
-                <attribute name="dir">
-                  <ref name="absFilePath"/>
-                </attribute>
+                <choice>
+                  <attribute name="dir">
+                    <ref name="absFilePath"/>
+                  </attribute>
+                  <ref name="diskSourcePool"/>
+                </choice>
                 <empty/>
               </element>
             </optional>
@@ -1075,48 +1084,10 @@
           <interleave>
             <optional>
               <element name="source">
-                <attribute name="protocol">
-                  <choice>
-                    <value>nbd</value>
-                    <value>rbd</value>
-                    <value>sheepdog</value>
-                    <value>gluster</value>
-                  </choice>
-                </attribute>
-                <optional>
-                  <attribute name="name"/>
-                </optional>
-                <zeroOrMore>
-                  <element name="host">
-                    <choice>
-                      <group>
-                        <optional>
-                          <attribute name="transport">
-                            <choice>
-                              <value>tcp</value>
-                              <value>rdma</value>
-                            </choice>
-                          </attribute>
-                        </optional>
-                        <attribute name="name">
-                          <ref name="dnsName"/>
-                        </attribute>
-                        <attribute name="port">
-                          <ref name="unsignedInt"/>
-                        </attribute>
-                      </group>
-                      <group>
-                        <attribute name="transport">
-                          <value>unix</value>
-                        </attribute>
-                        <attribute name="socket">
-                          <ref name="absFilePath"/>
-                        </attribute>
-                      </group>
-                    </choice>
-                  </element>
-                </zeroOrMore>
-                <empty/>
+                <choice>
+                  <ref name="diskSourceNetwork"/>
+                  <ref name="diskSourcePool"/>
+                </choice>
               </element>
             </optional>
             <ref name="diskspec"/>
@@ -1160,6 +1131,85 @@
       </optional>
     </element>
   </define>
+  <define name="diskSourceNetwork">
+    <attribute name="protocol">
+      <choice>
+        <value>nbd</value>
+        <value>rbd</value>
+        <value>sheepdog</value>
+        <value>gluster</value>
+      </choice>
+    </attribute>
+    <optional>
+      <attribute name="name"/>
+    </optional>
+    <zeroOrMore>
+      <element name="host">
+        <choice>
+          <group>
+            <optional>
+              <attribute name="transport">
+                <choice>
+                  <value>tcp</value>
+                   <value>rdma</value>
+                </choice>
+              </attribute>
+            </optional>
+            <attribute name="name">
+              <ref name="dnsName"/>
+            </attribute>
+            <attribute name="port">
+              <ref name="unsignedInt"/>
+            </attribute>
+          </group>
+          <group>
+            <attribute name="transport">
+              <value>unix</value>
+            </attribute>
+            <attribute name="socket">
+              <ref name="absFilePath"/>
+            </attribute>
+          </group>
+        </choice>
+      </element>
+    </zeroOrMore>
+    <empty/>
+  </define>
+  <define name="diskSourcePool">
+    <optional>
+      <attribute name="type">
+        <value>pool</value>
+      </attribute>
+    </optional>
+    <optional>
+      <element name="pool">
+        <choice>
+          <attribute name="uuid">
+            <ref name="UUID"/>
+          </attribute>
+          <attribute name="name">
+            <ref name="genericName"/>
+          </attribute>
+        </choice>
+      </element>
+    </optional>
+    <optional>
+      <element name="volume">
+        <choice>
+          <attribute name="name">
+            <ref name="volName"/>
+          </attribute>
+          <attribute name="key">
+            <text/>
+          </attribute>
+          <attribute name="path">
+            <data type='anyURI'/>
+          </attribute>
+        </choice>
+      </element>
+    </optional>
+  </define>
+
   <define name="geometry">
     <element name="geometry">
       <attribute name="cyls">
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 0b9ba13..4a66cd3 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -692,6 +692,12 @@ VIR_ENUM_IMPL(virDomainNumatuneMemPlacementMode,
               "static",
               "auto");
 
+VIR_ENUM_IMPL(virDomainDiskSourceType,
+              VIR_DOMAIN_DISK_SOURCE_TYPE_LAST,
+              "default",
+              "pool");
+
+
 #define VIR_DOMAIN_XML_WRITE_FLAGS  VIR_DOMAIN_XML_SECURE
 #define VIR_DOMAIN_XML_READ_FLAGS   VIR_DOMAIN_XML_INACTIVE
 
@@ -987,6 +993,25 @@ void virDomainLeaseDefFree(virDomainLeaseDefPtr def)
     VIR_FREE(def);
 }
 
+static void
+virDomainDiskSourcePoolDefFree(virDomainDiskSourcePoolDefPtr def)
+{
+    if (!def)
+        return;
+
+    if (def->poolType == VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_NAME)
+        VIR_FREE(def->pool.name);
+
+    if (def->volType == VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_NAME)
+        VIR_FREE(def->vol.name);
+    else if (def->volType == VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_PATH)
+        VIR_FREE(def->vol.path);
+    else if (def->volType == VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_KEY)
+        VIR_FREE(def->vol.key);
+
+    VIR_FREE(def);
+}
+
 void virDomainDiskDefFree(virDomainDiskDefPtr def)
 {
     unsigned int i;
@@ -996,6 +1021,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def)
 
     VIR_FREE(def->serial);
     VIR_FREE(def->src);
+    virDomainDiskSourcePoolDefFree(def->srcpool);
     VIR_FREE(def->dst);
     VIR_FREE(def->driverName);
     virStorageFileFreeMetadata(def->backingChain);
@@ -3575,6 +3601,112 @@ cleanup:
     goto cleanup;
 }
 
+static virDomainDiskSourcePoolDefPtr
+virDomainDiskSourcePoolDefParse(xmlNodePtr node)
+{
+    virDomainDiskSourcePoolDefPtr srcpool = NULL;
+    xmlNodePtr child;
+    virDomainDiskSourcePoolDefPtr ret = NULL;
+
+    if (VIR_ALLOC(srcpool) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    child = node->children;
+    while (child != NULL) {
+        if (child->type != XML_ELEMENT_NODE) {
+            child = child->next;
+            continue;
+        }
+
+        if (xmlStrEqual(child->name, BAD_CAST "pool")) {
+            char *name = NULL;
+            char *uuid = NULL;
+
+            name = virXMLPropString(child, "name");
+            uuid = virXMLPropString(child, "uuid");
+
+            if (name && uuid) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("Only one of 'name' or 'uuid' "
+                                 "is allowed"));
+                VIR_FREE(name);
+                VIR_FREE(uuid);
+                goto cleanup;
+            }
+
+            if (name) {
+                srcpool->poolType = VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_NAME;
+                srcpool->pool.name = name;
+            } else if (uuid) {
+                if (virUUIDParse(uuid,
+                                 srcpool->pool.uuid) < 0) {
+                    virReportError(VIR_ERR_XML_ERROR,
+                                   _("malformed uuid %s"), uuid);
+                    VIR_FREE(uuid);
+                    goto cleanup;
+                }
+                VIR_FREE(uuid);
+
+                srcpool->poolType = VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_UUID;
+            }
+        } else if (xmlStrEqual(child->name, BAD_CAST "volume")) {
+            char *name = NULL;
+            char *key = NULL;
+            char *path = NULL;
+
+            name = virXMLPropString(child, "name");
+            key = virXMLPropString(child, "key");
+            path = virXMLPropString(child, "path");
+
+            if ((name && key) ||
+                (name && path) ||
+                (key && path)) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("only one of 'name', 'key', 'path' is allowed"));
+                VIR_FREE(name);
+                VIR_FREE(key);
+                VIR_FREE(path);
+            }
+
+            if (name) {
+                srcpool->volType = VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_NAME;
+                srcpool->vol.name = name;
+            } else if (key) {
+                srcpool->volType = VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_KEY;
+                srcpool->vol.key = key;
+            } else if (path) {
+                srcpool->volType = VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_PATH;
+                srcpool->vol.name = path;
+            }
+        }
+        child = child->next;
+    }
+
+    if (srcpool->volType == VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_NAME &&
+        srcpool->poolType == VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_NONE) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("'pool' must be specified if 'volume' "
+                         "is specified by 'name'"));
+        goto cleanup;
+    }
+
+    if (srcpool->poolType == VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_NONE &&
+        srcpool->volType == VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_NONE) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("Neither 'pool' nor 'volume' is specified"));
+        goto cleanup;
+    }
+
+    ret = srcpool;
+
+cleanup:
+    if (!ret)
+        virDomainDiskSourcePoolDefFree(srcpool);
+    return ret;
+}
+
 #define VENDOR_LEN  8
 #define PRODUCT_LEN 16
 
@@ -3633,6 +3765,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
     char *wwn = NULL;
     char *vendor = NULL;
     char *product = NULL;
+    virDomainDiskSourcePoolDefPtr srcpool = NULL;
 
     if (VIR_ALLOC(def) < 0) {
         virReportOOMError();
@@ -3668,11 +3801,31 @@ virDomainDiskDefParseXML(virCapsPtr caps,
     cur = node->children;
     while (cur != NULL) {
         if (cur->type == XML_ELEMENT_NODE) {
-            if (!source && !hosts &&
+            if (!source && !hosts && !srcpool &&
                 xmlStrEqual(cur->name, BAD_CAST "source")) {
-
+                char *source_type = NULL;
                 sourceNode = cur;
 
+                if ((source_type = virXMLPropString(cur, "type"))) {
+                    if ((def->source_type =
+                         virDomainDiskSourceTypeTypeFromString(source_type)) < 0) {
+                        virReportError(VIR_ERR_XML_ERROR,
+                                       _("Unknown disk source type '%s'"),
+                                       source_type);
+                        VIR_FREE(source_type);
+                        goto error;
+                    }
+                    VIR_FREE(source_type);
+
+                    if (!(srcpool = virDomainDiskSourcePoolDefParse(cur)))
+                        goto error;
+
+                    if (def->type == VIR_DOMAIN_DISK_TYPE_FILE)
+                        startupPolicy = virXMLPropString(cur, "startupPolicy");
+
+                    continue;
+                }
+
                 switch (def->type) {
                 case VIR_DOMAIN_DISK_TYPE_FILE:
                     source = virXMLPropString(cur, "file");
@@ -4052,7 +4205,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
 
     /* Only CDROM and Floppy devices are allowed missing source path
      * to indicate no media present */
-    if (source == NULL && hosts == NULL &&
+    if (!source && !hosts && !srcpool &&
         def->device != VIR_DOMAIN_DISK_DEVICE_CDROM &&
         def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
         virReportError(VIR_ERR_NO_SOURCE,
@@ -4074,9 +4227,40 @@ virDomainDiskDefParseXML(virCapsPtr caps,
     }
 
     if (target == NULL) {
-        virReportError(VIR_ERR_NO_TARGET,
-                       source ? "%s" : NULL, source);
-        goto error;
+        if (def->source_type == VIR_DOMAIN_DISK_SOURCE_TYPE_POOL) {
+            virBuffer buf = VIR_BUFFER_INITIALIZER;
+            char uuidstr[VIR_UUID_STRING_BUFLEN];
+            char *str;
+
+            if (srcpool->poolType == VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_UUID) {
+                virUUIDFormat(def->srcpool->pool.uuid, uuidstr);
+                virBufferAsprintf(&buf, "pool uuid='%s', ", uuidstr);
+            } else if (srcpool->poolType == VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_NAME) {
+                virBufferAsprintf(&buf, "pool name='%s', ", srcpool->pool.name);
+            }
+
+            if (srcpool->volType == VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_NAME)
+                virBufferAsprintf(&buf, "volume name='%s', ", srcpool->vol.name);
+            else if (srcpool->volType == VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_PATH)
+                virBufferAsprintf(&buf, "volume path='%s', ", srcpool->vol.path);
+            else if (srcpool->volType == VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_KEY)
+                virBufferAsprintf(&buf, "volume key='%s', ", srcpool->vol.key);
+
+            if (virBufferError(&buf)) {
+                virReportOOMError();
+                virBufferFreeAndReset(&buf);
+                goto error;
+            }
+
+            str = virBufferContentAndReset(&buf);
+            virReportError(VIR_ERR_NO_TARGET, "%s", str);
+            VIR_FREE(str);
+            goto error;
+        } else {
+            virReportError(VIR_ERR_NO_TARGET,
+                           source ? "%s" : NULL, source);
+            goto error;
+        }
     }
 
     if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
@@ -4325,6 +4509,8 @@ virDomainDiskDefParseXML(virCapsPtr caps,
     hosts = NULL;
     def->nhosts = nhosts;
     nhosts = 0;
+    def->srcpool = srcpool;
+    srcpool = NULL;
     def->auth.username = authUsername;
     authUsername = NULL;
     def->driverName = driverName;
@@ -4385,6 +4571,7 @@ cleanup:
     VIR_FREE(sgio);
     VIR_FREE(target);
     VIR_FREE(source);
+    virDomainDiskSourcePoolDefFree(srcpool);
     VIR_FREE(tray);
     VIR_FREE(trans);
     while (nhosts > 0) {
@@ -12153,6 +12340,149 @@ static void virDomainDiskBlockIoDefFormat(virBufferPtr buf,
     }
 }
 
+static int
+virDomainDiskSourceDefFormat(virBufferPtr buf,
+                             virDomainDiskDefPtr def)
+{
+    int n;
+    const char *startupPolicy = virDomainStartupPolicyTypeToString(def->startupPolicy);
+
+
+    if (def->source_type == VIR_DOMAIN_DISK_SOURCE_TYPE_POOL) {
+        virBufferAddLit(buf, "      <source");
+        virBufferAsprintf(buf, " type='%s'",
+                          virDomainDiskSourceTypeTypeToString(def->source_type));
+
+        if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
+            if (def->startupPolicy)
+                virBufferEscapeString(buf, " startupPolicy='%s'",
+                                      startupPolicy);
+        }
+
+        virBufferAddLit(buf, ">\n");
+        virBufferAdjustIndent(buf, 8);
+
+        if (def->srcpool->poolType !=
+            VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_NONE) {
+            virBufferAddLit(buf, "<pool");
+            if (def->srcpool->poolType ==
+                VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_UUID) {
+                char uuidstr[VIR_UUID_STRING_BUFLEN];
+                virUUIDFormat(def->srcpool->pool.uuid, uuidstr);
+                virBufferAsprintf(buf, " uuid='%s'/>\n", uuidstr);
+            } else if (def->srcpool->poolType ==
+                       VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_NAME) {
+                virBufferAsprintf(buf, " name='%s'/>\n", def->srcpool->pool.name);
+            }
+        }
+
+        if (def->srcpool->volType !=
+            VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_NONE) {
+            virBufferAddLit(buf, "<volume");
+            if (def->srcpool->volType ==
+                       VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_NAME) {
+                virBufferAsprintf(buf, " name='%s'/>\n", def->srcpool->vol.name);
+            } else if (def->srcpool->volType ==
+                       VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_PATH) {
+                virBufferAsprintf(buf, " path='%s'/>\n", def->srcpool->vol.path);
+            } else if (def->srcpool->volType ==
+                VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_KEY) {
+                virBufferAsprintf(buf, " key='%s'/>\n", def->srcpool->vol.key);
+            }
+        }
+
+        if ((def->type == VIR_DOMAIN_DISK_TYPE_FILE ||
+             def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) &&
+             def->nseclabels) {
+            for (n = 0; n < def->nseclabels; n++)
+                virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]);
+        }
+        virBufferAdjustIndent(buf, -8);
+        virBufferAddLit(buf, "      </source>\n");
+        return 0;
+    }
+
+    if (def->src || def->nhosts > 0 ||
+        def->startupPolicy) {
+        switch (def->type) {
+        case VIR_DOMAIN_DISK_TYPE_FILE:
+            if (def->src)
+                virBufferEscapeString(buf, "      <source file='%s'", def->src);
+            if (def->startupPolicy)
+                virBufferEscapeString(buf, " startupPolicy='%s'",
+                                      startupPolicy);
+            if (def->nseclabels) {
+                virBufferAddLit(buf, ">\n");
+                virBufferAdjustIndent(buf, 8);
+                for (n = 0; n < def->nseclabels; n++)
+                    virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]);
+                virBufferAdjustIndent(buf, -8);
+                virBufferAddLit(buf, "      </source>\n");
+            } else {
+                virBufferAddLit(buf, "/>\n");
+            }
+            break;
+        case VIR_DOMAIN_DISK_TYPE_BLOCK:
+            virBufferEscapeString(buf, "      <source dev='%s'",
+                                  def->src);
+            if (def->nseclabels) {
+                virBufferAddLit(buf, ">\n");
+                virBufferAdjustIndent(buf, 8);
+                for (n = 0; n < def->nseclabels; n++)
+                    virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]);
+                virBufferAdjustIndent(buf, -8);
+                virBufferAddLit(buf, "      </source>\n");
+            } else {
+                virBufferAddLit(buf, "/>\n");
+            }
+            break;
+        case VIR_DOMAIN_DISK_TYPE_DIR:
+            virBufferEscapeString(buf, "      <source dir='%s'/>\n",
+                                  def->src);
+            break;
+        case VIR_DOMAIN_DISK_TYPE_NETWORK:
+            virBufferAsprintf(buf, "      <source protocol='%s'",
+                              virDomainDiskProtocolTypeToString(def->protocol));
+            if (def->src) {
+                virBufferEscapeString(buf, " name='%s'", def->src);
+            }
+            if (def->nhosts == 0) {
+                virBufferAddLit(buf, "/>\n");
+            } else {
+                int i;
+
+                virBufferAddLit(buf, ">\n");
+                for (i = 0; i < def->nhosts; i++) {
+                    virBufferAddLit(buf, "        <host");
+                    if (def->hosts[i].name) {
+                        virBufferEscapeString(buf, " name='%s'", def->hosts[i].name);
+                    }
+                    if (def->hosts[i].port) {
+                        virBufferEscapeString(buf, " port='%s'",
+                                              def->hosts[i].port);
+                    }
+                    if (def->hosts[i].transport) {
+                        virBufferAsprintf(buf, " transport='%s'",
+                                          virDomainDiskProtocolTransportTypeToString(def->hosts[i].transport));
+                    }
+                    if (def->hosts[i].socket) {
+                        virBufferEscapeString(buf, " socket='%s'", def->hosts[i].socket);
+                    }
+                    virBufferAddLit(buf, "/>\n");
+                }
+                virBufferAddLit(buf, "      </source>\n");
+            }
+            break;
+        default:
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("unexpected disk type %s"),
+                           virDomainDiskTypeToString(def->type));
+            return -1;
+        }
+    }
+
+    return 0;
+}
 
 static int
 virDomainDiskDefFormat(virBufferPtr buf,
@@ -12169,10 +12499,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
     const char *ioeventfd = virDomainIoEventFdTypeToString(def->ioeventfd);
     const char *event_idx = virDomainVirtioEventIdxTypeToString(def->event_idx);
     const char *copy_on_read = virDomainVirtioEventIdxTypeToString(def->copy_on_read);
-    const char *startupPolicy = virDomainStartupPolicyTypeToString(def->startupPolicy);
     const char *sgio = virDomainDiskSGIOTypeToString(def->sgio);
 
-    int n;
     char uuidstr[VIR_UUID_STRING_BUFLEN];
 
     if (!type) {
@@ -12268,86 +12596,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
         virBufferAddLit(buf, "      </auth>\n");
     }
 
-    if (def->src || def->nhosts > 0 ||
-        def->startupPolicy) {
-        switch (def->type) {
-        case VIR_DOMAIN_DISK_TYPE_FILE:
-            virBufferAddLit(buf,"      <source");
-            if (def->src)
-                virBufferEscapeString(buf, " file='%s'", def->src);
-            if (def->startupPolicy)
-                virBufferEscapeString(buf, " startupPolicy='%s'",
-                                      startupPolicy);
-            if (def->nseclabels) {
-                virBufferAddLit(buf, ">\n");
-                virBufferAdjustIndent(buf, 8);
-                for (n = 0; n < def->nseclabels; n++)
-                    virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]);
-                virBufferAdjustIndent(buf, -8);
-                virBufferAddLit(buf, "      </source>\n");
-            } else {
-                virBufferAddLit(buf, "/>\n");
-            }
-            break;
-        case VIR_DOMAIN_DISK_TYPE_BLOCK:
-            virBufferEscapeString(buf, "      <source dev='%s'",
-                                  def->src);
-            if (def->nseclabels) {
-                virBufferAddLit(buf, ">\n");
-                virBufferAdjustIndent(buf, 8);
-                for (n = 0; n < def->nseclabels; n++)
-                    virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]);
-                virBufferAdjustIndent(buf, -8);
-                virBufferAddLit(buf, "      </source>\n");
-            } else {
-                virBufferAddLit(buf, "/>\n");
-            }
-            break;
-        case VIR_DOMAIN_DISK_TYPE_DIR:
-            virBufferEscapeString(buf, "      <source dir='%s'/>\n",
-                                  def->src);
-            break;
-        case VIR_DOMAIN_DISK_TYPE_NETWORK:
-            virBufferAsprintf(buf, "      <source protocol='%s'",
-                              virDomainDiskProtocolTypeToString(def->protocol));
-            if (def->src) {
-                virBufferEscapeString(buf, " name='%s'", def->src);
-            }
-            if (def->nhosts == 0) {
-                virBufferAddLit(buf, "/>\n");
-            } else {
-                int i;
-
-                virBufferAddLit(buf, ">\n");
-                for (i = 0; i < def->nhosts; i++) {
-                    virBufferAddLit(buf, "        <host");
-                    if (def->hosts[i].name) {
-                        virBufferEscapeString(buf, " name='%s'", def->hosts[i].name);
-                    }
-                    if (def->hosts[i].port) {
-                        virBufferEscapeString(buf, " port='%s'",
-                                              def->hosts[i].port);
-                    }
-                    if (def->hosts[i].transport) {
-                        virBufferAsprintf(buf, " transport='%s'",
-                                          virDomainDiskProtocolTransportTypeToString(def->hosts[i].transport));
-                    }
-                    if (def->hosts[i].socket) {
-                        virBufferEscapeString(buf, " socket='%s'", def->hosts[i].socket);
-                    }
-                    virBufferAddLit(buf, "/>\n");
-                }
-                virBufferAddLit(buf, "      </source>\n");
-            }
-            break;
-        default:
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("unexpected disk type %s"),
-                           virDomainDiskTypeToString(def->type));
-            return -1;
-        }
-    }
-
+    if (virDomainDiskSourceDefFormat(buf, def) < 0)
+        return -1;
     virDomainDiskGeometryDefFormat(buf, def);
     virDomainDiskBlockIoDefFormat(buf, def);
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index ce36003..1909f62 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -585,9 +585,53 @@ struct _virDomainBlockIoTuneInfo {
 };
 typedef virDomainBlockIoTuneInfo *virDomainBlockIoTuneInfoPtr;
 
+
+enum virDomainDiskSourceType {
+    VIR_DOMAIN_DISK_SOURCE_TYPE_DEFAULT = 0,
+    VIR_DOMAIN_DISK_SOURCE_TYPE_POOL,
+
+    VIR_DOMAIN_DISK_SOURCE_TYPE_LAST
+};
+
+enum virDomainDiskSourcePoolType {
+    VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_NONE = 0,
+    VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_NAME,
+    VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_UUID,
+
+    VIR_DOMAIN_DISK_SOURCE_POOL_TYPE_LAST
+};
+
+enum virDomainDiskSourceVolType {
+    VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_NONE = 0,
+    VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_NAME,
+    VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_PATH,
+    VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_KEY,
+
+    VIR_DOMAIN_DISK_SOURCE_VOL_TYPE_LAST
+};
+
+typedef struct _virDomainDiskSourcePoolDef virDomainDiskSourcePoolDef;
+struct _virDomainDiskSourcePoolDef {
+    int poolType; /* enum virDomainDiskSourcePoolType */
+    int volType;  /* enum virDomainDiskSourceVolType */
+
+    union {
+        char *name;
+        unsigned char uuid[VIR_UUID_BUFLEN];
+    } pool;
+
+    union {
+        char *name;
+        char *key;
+        char *path;
+    } vol;
+};
+typedef virDomainDiskSourcePoolDef *virDomainDiskSourcePoolDefPtr;
+
 /* Stores the virtual disk configuration */
 struct _virDomainDiskDef {
     int type;
+    int source_type; /* enum virDomainDiskSourceType */
     int device;
     int bus;
     char *src;
@@ -596,6 +640,7 @@ struct _virDomainDiskDef {
     int protocol;
     size_t nhosts;
     virDomainDiskHostDefPtr hosts;
+    virDomainDiskSourcePoolDefPtr srcpool;
     struct {
         char *username;
         int secretType; /* enum virDomainDiskSecretType */
@@ -2252,6 +2297,7 @@ VIR_ENUM_DECL(virDomainDiskTray)
 VIR_ENUM_DECL(virDomainIoEventFd)
 VIR_ENUM_DECL(virDomainVirtioEventIdx)
 VIR_ENUM_DECL(virDomainDiskCopyOnRead)
+VIR_ENUM_DECL(virDomainDiskSourceType)
 VIR_ENUM_DECL(virDomainController)
 VIR_ENUM_DECL(virDomainControllerModelSCSI)
 VIR_ENUM_DECL(virDomainControllerModelUSB)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 521f8e0..d14be41 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -368,6 +368,8 @@ virDomainDiskProtocolTransportTypeFromString;
 virDomainDiskProtocolTransportTypeToString;
 virDomainDiskRemove;
 virDomainDiskRemoveByName;
+virDomainDiskSourceTypeTypeFromString;
+virDomainDiskSourceTypeTypeToString;
 virDomainDiskTypeFromString;
 virDomainDiskTypeToString;
 virDomainEmulatorPinAdd;
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-source-pool.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-source-pool.xml
new file mode 100644
index 0000000..5913403
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-source-pool.xml
@@ -0,0 +1,36 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='cdrom'>
+      <source type='pool'>
+        <pool uuid='92c7b3b8-a290-afd2-5b8b-1336579b8457'/>
+        <volume name='blk-pool0-vol0'/>
+      </source>
+      <target dev='hda' bus='ide'/>
+      <readonly/>
+      <address type='drive' controller='0' bus='0' target='0' unit='1'/>
+    </disk>
+    <disk type='file' device='disk'>
+      <source file='/tmp/idedisk.img'/>
+      <target dev='hdc' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='2'/>
+    </disk>
+    <controller type='usb' index='0'/>
+    <controller type='ide' index='0'/>
+    <controller type='ide' index='1'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 160e958..7e174dd 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -241,6 +241,7 @@ mymain(void)
     DO_TEST("disk-scsi-lun-passthrough-sgio");
 
     DO_TEST("disk-scsi-disk-vpd");
+    DO_TEST("disk-source-pool");
 
     /* These tests generate different XML */
     DO_TEST_DIFFERENT("balloon-device-auto");
-- 
1.7.7.6




More information about the libvir-list mailing list