]> xenbits.xensource.com Git - libvirt.git/commitdiff
snapshot: Add support for specifying snapshot disk backing type
authorPeter Krempa <pkrempa@redhat.com>
Tue, 12 Nov 2013 13:15:51 +0000 (14:15 +0100)
committerPeter Krempa <pkrempa@redhat.com>
Wed, 29 Jan 2014 11:56:35 +0000 (12:56 +0100)
Add support for specifying various types when doing snapshots. This will
later allow to do snapshots on network backed volumes. Disks of type
'volume' are not supported by snapshots (yet).

Also amend the test suite to check parsing of the various new disk
types that can now be specified.

docs/formatsnapshot.html.in
docs/schemas/domainsnapshot.rng
src/conf/snapshot_conf.c
src/conf/snapshot_conf.h
src/qemu/qemu_conf.c
src/qemu/qemu_driver.c
tests/domainsnapshotxml2xmlin/disk_snapshot.xml
tests/domainsnapshotxml2xmlout/disk_driver_name_null.xml
tests/domainsnapshotxml2xmlout/disk_snapshot.xml
tests/domainsnapshotxml2xmlout/disk_snapshot_redefine.xml

index 76689cbcb4587a11ac79254a90f1061395bf6948..44ed4fdab03ff6deeb33d285acb4e510751178e3 100644 (file)
             snapshots, the original file name becomes the read-only
             snapshot, and the new file name contains the read-write
             delta of all disk changes since the snapshot.
+
+            <span class="since">Since 1.2.2</span> the <code>disk</code> element
+            supports an optional attribute <code>type</code> if the
+            <code>snapshot</code> attribute is set to <code>external</code>.
+            This attribute specifies the snapshot target storage type and allows
+            to overwrite the default <code>file</code> type. The <code>type</code>
+            attribute along with the format of the <code>source</code>
+            sub-element is identical to the <code>source</code> element used in
+            domain disk definitions. See the
+            <a href="formatdomain.html#elementsDisks">disk devices</a> section
+            documentation for further information.
+
+            Libvirt currently supports the <code>type</code> element in the qemu
+            driver and supported values are <code>file</code> and
+            <code>block</code> <span class="since">(since 1.2.2)</span>.
           </dd>
         </dl>
       </dd>
index 169fcfb1ddffdd6ced804a13f64bb5ceb57ecbd9..824a18616a250b7ccbb39f1bb349aadd421801d2 100644 (file)
               <value>external</value>
             </attribute>
           </optional>
-          <interleave>
-            <ref name='disksnapshotdriver'/>
-            <optional>
-              <element name='source'>
+          <choice>
+            <group>
+              <optional>
+                <attribute name='type'>
+                  <value>file</value>
+                </attribute>
+              </optional>
+              <interleave>
                 <optional>
-                  <attribute name='file'>
-                    <ref name='absFilePath'/>
-                  </attribute>
+                  <element name='source'>
+                    <optional>
+                      <attribute name='file'>
+                        <ref name='absFilePath'/>
+                      </attribute>
+                    </optional>
+                    <empty/>
+                  </element>
                 </optional>
-                <empty/>
-              </element>
-            </optional>
-          </interleave>
+                <ref name='disksnapshotdriver'/>
+              </interleave>
+            </group>
+            <group>
+              <attribute name='type'>
+                <value>block</value>
+              </attribute>
+              <interleave>
+                <optional>
+                  <element name="source">
+                    <attribute name="dev">
+                      <ref name="absFilePath"/>
+                    </attribute>
+                    <empty/>
+                  </element>
+                </optional>
+                <ref name='disksnapshotdriver'/>
+              </interleave>
+            </group>
+            <group>
+              <attribute name="type">
+                <value>network</value>
+              </attribute>
+              <interleave>
+                <optional>
+                  <element name="source">
+                    <ref name='diskSourceNetwork'/>
+                  </element>
+                </optional>
+                <ref name='disksnapshotdriver'/>
+              </interleave>
+            </group>
+          </choice>
         </group>
       </choice>
     </element>
index fb0b4cc16fa14751866efeb0d9e217f234b3ed22..bb732a134750ee7485cfc1293194ac4290b8401f 100644 (file)
@@ -108,6 +108,7 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
 {
     int ret = -1;
     char *snapshot = NULL;
+    char *type = NULL;
     xmlNodePtr cur;
 
     def->name = virXMLPropString(node, "name");
@@ -128,7 +129,17 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
         }
     }
 
-    def->type = -1;
+    if ((type = virXMLPropString(node, "type"))) {
+        if ((def->type = virDomainDiskTypeFromString(type)) < 0 ||
+            def->type == VIR_DOMAIN_DISK_TYPE_VOLUME ||
+            def->type == VIR_DOMAIN_DISK_TYPE_DIR) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("unknown disk snapshot type '%s'"), type);
+            goto cleanup;
+        }
+    } else {
+        def->type = VIR_DOMAIN_DISK_TYPE_FILE;
+    }
 
     for (cur = node->children; cur; cur = cur->next) {
         if (cur->type != XML_ELEMENT_NODE)
@@ -137,17 +148,12 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
         if (!def->file &&
             xmlStrEqual(cur->name, BAD_CAST "source")) {
 
-            int backingtype = def->type;
-
-            if (backingtype < 0)
-                backingtype = VIR_DOMAIN_DISK_TYPE_FILE;
-
             if (virDomainDiskSourceDefParse(cur,
-                                            backingtype,
+                                            def->type,
                                             &def->file,
-                                            NULL,
-                                            NULL,
-                                            NULL,
+                                            &def->protocol,
+                                            &def->nhosts,
+                                            &def->hosts,
                                             NULL) < 0)
                 goto cleanup;
 
@@ -174,6 +180,7 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
     ret = 0;
 cleanup:
     VIR_FREE(snapshot);
+    VIR_FREE(type);
     if (ret < 0)
         virDomainSnapshotDiskDefClear(def);
     return ret;
@@ -532,7 +539,7 @@ virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def,
             goto cleanup;
         disk->index = i;
         disk->snapshot = def->dom->disks[i]->snapshot;
-        disk->type = -1;
+        disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
         if (!disk->snapshot)
             disk->snapshot = default_snapshot;
     }
@@ -550,8 +557,7 @@ virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def,
             const char *tmp;
             struct stat sb;
 
-            if (disk->type != VIR_DOMAIN_DISK_TYPE_FILE &&
-                disk->type != -1) {
+            if (disk->type != VIR_DOMAIN_DISK_TYPE_FILE) {
                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                _("cannot generate external snapshot name "
                                  "for disk '%s' on a '%s' device"),
@@ -614,15 +620,12 @@ virDomainSnapshotDiskDefFormat(virBufferPtr buf,
         virBufferAsprintf(buf, " snapshot='%s'",
                           virDomainSnapshotLocationTypeToString(disk->snapshot));
 
-    if (type < 0)
-        type = VIR_DOMAIN_DISK_TYPE_FILE;
-
     if (!disk->file && disk->format == 0) {
         virBufferAddLit(buf, "/>\n");
         return;
     }
 
-    virBufferAddLit(buf, ">\n");
+    virBufferAsprintf(buf, " type='%s'>\n", virDomainDiskTypeToString(type));
 
     if (disk->format > 0)
         virBufferEscapeString(buf, "      <driver type='%s'/>\n",
@@ -630,7 +633,11 @@ virDomainSnapshotDiskDefFormat(virBufferPtr buf,
     virDomainDiskSourceDefFormatInternal(buf,
                                          type,
                                          disk->file,
-                                         0, 0, 0, NULL, 0, NULL, NULL, 0);
+                                         0,
+                                         disk->protocol,
+                                         disk->nhosts,
+                                         disk->hosts,
+                                         0, NULL, NULL, 0);
 
     virBufferAddLit(buf, "    </disk>\n");
 }
index 241d63cafe5b201281ccf080f0c2a6df4a8f9c9a..bcd92dc62fa809ae52bd2603fa4d794190d30e3f 100644 (file)
@@ -48,12 +48,15 @@ enum virDomainSnapshotState {
 typedef struct _virDomainSnapshotDiskDef virDomainSnapshotDiskDef;
 typedef virDomainSnapshotDiskDef *virDomainSnapshotDiskDefPtr;
 struct _virDomainSnapshotDiskDef {
-    char *name; /* name matching the <target dev='...' of the domain */
-    int index; /* index within snapshot->dom->disks that matches name */
-    int snapshot; /* enum virDomainSnapshotLocation */
-    int type; /* enum virDomainDiskType */
-    char *file; /* new source file when snapshot is external */
-    int format; /* enum virStorageFileFormat */
+    char *name;     /* name matching the <target dev='...' of the domain */
+    int index;      /* index within snapshot->dom->disks that matches name */
+    int snapshot;   /* enum virDomainSnapshotLocation */
+    int type;       /* enum virDomainDiskType */
+    char *file;     /* new source file when snapshot is external */
+    int format;     /* enum virStorageFileFormat */
+    int protocol;   /* network source protocol */
+    size_t nhosts;  /* network source hosts count */
+    virDomainDiskHostDefPtr hosts; /* network source hosts */
 };
 
 /* Stores the complete snapshot metadata */
index ac53f6df651350453f761efed98764bb69294a35..bf69ee54a5cc8152325c12e1bb85eb43a88bc637 100644 (file)
@@ -1473,9 +1473,6 @@ cleanup:
 int
 qemuSnapshotDiskGetActualType(virDomainSnapshotDiskDefPtr def)
 {
-    if (def->type == -1)
-        return VIR_DOMAIN_DISK_TYPE_FILE;
-
     return def->type;
 }
 
index a5554705fdc95e8ef605d5a811a3e44afd16f0a8..6b3825aed06c32f58c211bc7ada5e0cc3e1b0133 100644 (file)
@@ -12623,33 +12623,47 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver,
     }
 
     if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0 ||
-        VIR_STRDUP(source, snap->file) < 0 ||
         (persistDisk && VIR_STRDUP(persistSource, source) < 0))
         goto cleanup;
 
-    /* create the stub file and set selinux labels; manipulate disk in
-     * place, in a way that can be reverted on failure. */
-    if (!reuse) {
-        fd = qemuOpenFile(driver, vm, source, O_WRONLY | O_TRUNC | O_CREAT,
-                          &need_unlink, NULL);
-        if (fd < 0)
-            goto cleanup;
-        VIR_FORCE_CLOSE(fd);
-    }
-
     /* XXX Here, we know we are about to alter disk->backingChain if
-     * successful, so we nuke the existing chain so that future
-     * commands will recompute it.  Better would be storing the chain
-     * ourselves rather than reprobing, but this requires modifying
-     * domain_conf and our XML to fully track the chain across
-     * libvirtd restarts.  */
+     * successful, so we nuke the existing chain so that future commands will
+     * recompute it.  Better would be storing the chain ourselves rather than
+     * reprobing, but this requires modifying domain_conf and our XML to fully
+     * track the chain across libvirtd restarts.  */
     virStorageFileFreeMetadata(disk->backingChain);
     disk->backingChain = NULL;
 
-    if (qemuDomainPrepareDiskChainElement(driver, vm, disk, source,
-                                          VIR_DISK_CHAIN_READ_WRITE) < 0) {
-        qemuDomainPrepareDiskChainElement(driver, vm, disk, source,
-                                          VIR_DISK_CHAIN_NO_ACCESS);
+    switch (snap->type) {
+    case VIR_DOMAIN_DISK_TYPE_BLOCK:
+        reuse = true;
+        /* fallthrough */
+    case VIR_DOMAIN_DISK_TYPE_FILE:
+        if (VIR_STRDUP(source, snap->file) < 0)
+            goto cleanup;
+
+        /* create the stub file and set selinux labels; manipulate disk in
+         * place, in a way that can be reverted on failure. */
+        if (!reuse) {
+            fd = qemuOpenFile(driver, vm, source, O_WRONLY | O_TRUNC | O_CREAT,
+                              &need_unlink, NULL);
+            if (fd < 0)
+                goto cleanup;
+            VIR_FORCE_CLOSE(fd);
+        }
+
+        if (qemuDomainPrepareDiskChainElement(driver, vm, disk, source,
+                                              VIR_DISK_CHAIN_READ_WRITE) < 0) {
+            qemuDomainPrepareDiskChainElement(driver, vm, disk, source,
+                                              VIR_DISK_CHAIN_NO_ACCESS);
+            goto cleanup;
+        }
+        break;
+
+    default:
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+                       _("snapshots are not supported on '%s' volumes"),
+                       virDomainDiskTypeToString(snap->type));
         goto cleanup;
     }
 
@@ -12685,11 +12699,13 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver,
     disk->src = source;
     source = NULL;
     disk->format = format;
+    disk->type = snap->type;
     if (persistDisk) {
         VIR_FREE(persistDisk->src);
         persistDisk->src = persistSource;
         persistSource = NULL;
         persistDisk->format = format;
+        persistDisk->type = snap->type;
     }
 
 cleanup:
@@ -12731,11 +12747,13 @@ qemuDomainSnapshotUndoSingleDiskActive(virQEMUDriverPtr driver,
     disk->src = source;
     source = NULL;
     disk->format = origdisk->format;
+    disk->type = origdisk->type;
     if (persistDisk) {
         VIR_FREE(persistDisk->src);
         persistDisk->src = persistSource;
         persistSource = NULL;
         persistDisk->format = origdisk->format;
+        persistDisk->type = origdisk->type;
     }
 
 cleanup:
index ee6b46a86345794131004a9c07bb64b862d09d4b..aa1522a4506fc044765adec3a33a1506adfa6905 100644 (file)
     <disk name='hde' snapshot='external'>
       <source file='/path/to/new'/>
     </disk>
+    <disk name='hde' snapshot='external' type='file'>
+      <source file='/path/to/new2'/>
+    </disk>
+    <disk name='hdf' snapshot='external' type='block'>
+      <source dev='/path/to/new3'/>
+    </disk>
+    <disk name='hdg' snapshot='external' type='network'>
+      <source protocol='gluster' name='volume/path'>
+        <host name='host' port='1234'/>
+      </source>
+    </disk>
+    <disk name='hdh' snapshot='external' type='network'>
+      <source protocol='rbd' name='name'>
+        <host name='host' port='1234'/>
+        <host name='host2' port='1234' transport='rdma'/>
+        <host name='host3' port='1234'/>
+      </source>
+    </disk>
   </disks>
 </domainsnapshot>
index 41961f14111acb79ede2906e98b2b660479a0da0..ddd350de65c447df8ac79b44edfaef8d54231d26 100644 (file)
@@ -2,7 +2,7 @@
   <name>asdf</name>
   <description>adsf</description>
   <disks>
-    <disk name='vda' snapshot='external'>
+    <disk name='vda' snapshot='external' type='file'>
       <source file='/tmp/foo'/>
     </disk>
   </disks>
index 1a1fc0254fc8a5473d82bf107089debfffef14a9..c2e77d7aca123777c0a8e8398c4f81b24a0b1525 100644 (file)
@@ -5,11 +5,29 @@
     <disk name='/dev/HostVG/QEMUGuest1'/>
     <disk name='hdb' snapshot='no'/>
     <disk name='hdc' snapshot='internal'/>
-    <disk name='hdd' snapshot='external'>
+    <disk name='hdd' snapshot='external' type='file'>
       <driver type='qed'/>
     </disk>
-    <disk name='hde' snapshot='external'>
+    <disk name='hde' snapshot='external' type='file'>
       <source file='/path/to/new'/>
     </disk>
+    <disk name='hde' snapshot='external' type='file'>
+      <source file='/path/to/new2'/>
+    </disk>
+    <disk name='hdf' snapshot='external' type='block'>
+      <source dev='/path/to/new3'/>
+    </disk>
+    <disk name='hdg' snapshot='external' type='network'>
+      <source protocol='gluster' name='volume/path'>
+        <host name='host' port='1234'/>
+      </source>
+    </disk>
+    <disk name='hdh' snapshot='external' type='network'>
+      <source protocol='rbd' name='name'>
+        <host name='host' port='1234'/>
+        <host name='host2' port='1234' transport='rdma'/>
+        <host name='host3' port='1234'/>
+      </source>
+    </disk>
   </disks>
 </domainsnapshot>
index 5f42bf5dde504ef905db3ed9c06858db613e2387..c267db5281f5825d8f7a5c22794e83b3eabcc165 100644 (file)
     <disk name='hda' snapshot='no'/>
     <disk name='hdb' snapshot='no'/>
     <disk name='hdc' snapshot='internal'/>
-    <disk name='hdd' snapshot='external'>
+    <disk name='hdd' snapshot='external' type='file'>
       <driver type='qed'/>
       <source file='/path/to/generated4'/>
     </disk>
-    <disk name='hde' snapshot='external'>
+    <disk name='hde' snapshot='external' type='file'>
       <driver type='qcow2'/>
       <source file='/path/to/new'/>
     </disk>
-    <disk name='hdf' snapshot='external'>
+    <disk name='hdf' snapshot='external' type='file'>
       <driver type='qcow2'/>
       <source file='/path/to/generated5'/>
     </disk>