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>
<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>
{
int ret = -1;
char *snapshot = NULL;
+ char *type = NULL;
xmlNodePtr cur;
def->name = virXMLPropString(node, "name");
}
}
- 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)
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;
ret = 0;
cleanup:
VIR_FREE(snapshot);
+ VIR_FREE(type);
if (ret < 0)
virDomainSnapshotDiskDefClear(def);
return ret;
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;
}
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"),
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",
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");
}
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 */
int
qemuSnapshotDiskGetActualType(virDomainSnapshotDiskDefPtr def)
{
- if (def->type == -1)
- return VIR_DOMAIN_DISK_TYPE_FILE;
-
return def->type;
}
}
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;
}
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:
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:
<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>
<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>
<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>
<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>