<dt><code>disk</code></dt>
<dd>This sub-element describes the snapshot properties of a
specific disk. The attribute <code>name</code> is
- mandatory, and must match the <code><target
- dev='name'/></code> of one of
+ mandatory, and must match either the <code><target
+ dev='name'/></code> or an unambiguous <code><source
+ file='name'/></code> of one of
the <a href="formatdomain.html#elementsDisks">disk
devices</a> specified for the domain at the time of the
snapshot. The attribute <code>snapshot</code> is
<domainsnapshot>
<description>Snapshot of OS install and updates</description>
<disks>
- <disk name='vda'>
+ <disk name='/path/to/old'>
<source file='/path/to/new'/>
</disk>
<disk name='vdb' snapshot='no'/>
</choice>
</element>
</define>
+ <define name="diskTarget">
+ <data type="string">
+ <param name="pattern">(ioemu:)?(fd|hd|sd|vd|xvd|ubd)[a-zA-Z0-9_]+</param>
+ </data>
+ </define>
<define name="target">
<element name="target">
<attribute name="dev">
- <ref name="deviceName"/>
+ <ref name="diskTarget"/>
</attribute>
<optional>
<attribute name="bus">
<define name='disksnapshot'>
<element name='disk'>
<attribute name='name'>
- <ref name='deviceName'/>
+ <choice>
+ <ref name='diskTarget'/>
+ <ref name='absFilePath'/>
+ </choice>
</attribute>
<choice>
<attribute name='snapshot'>
return type;
}
-int virDomainDiskIndexByName(virDomainDefPtr def, const char *name)
+int
+virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
+ bool allow_ambiguous)
{
virDomainDiskDefPtr vdisk;
int i;
+ int candidate = -1;
+ /* We prefer the <target dev='name'/> name (it's shorter, required
+ * for all disks, and should be unambiguous), but also support
+ * <source file='name'/> (if unambiguous). Assume dst if there is
+ * no leading slash, source name otherwise. */
for (i = 0; i < def->ndisks; i++) {
vdisk = def->disks[i];
- if (STREQ(vdisk->dst, name))
- return i;
+ if (*name != '/') {
+ if (STREQ(vdisk->dst, name))
+ return i;
+ } else if (vdisk->src &&
+ STREQ(vdisk->src, name)) {
+ if (allow_ambiguous)
+ return i;
+ if (candidate >= 0)
+ return -1;
+ candidate = i;
+ }
}
- return -1;
+ return candidate;
+}
+
+/* Return the path to a disk image if a string identifies at least one
+ * disk belonging to the domain (both device strings 'vda' and paths
+ * '/path/to/file' are converted into '/path/to/file'). */
+const char *
+virDomainDiskPathByName(virDomainDefPtr def, const char *name)
+{
+ int i = virDomainDiskIndexByName(def, name, true);
+
+ return i < 0 ? NULL : def->disks[i]->src;
}
int virDomainDiskInsert(virDomainDefPtr def,
int virDomainDiskRemoveByName(virDomainDefPtr def, const char *name)
{
- int i = virDomainDiskIndexByName(def, name);
+ int i = virDomainDiskIndexByName(def, name, false);
if (i < 0)
return -1;
virDomainDiskRemove(def, i);
/* Align def->disks to def->domain. Sort the list of def->disks,
* filling in any missing disks or snapshot state defaults given by
- * the domain, with a fallback to a passed in default. Issue an error
- * and return -1 if any def->disks[n]->name appears more than once or
- * does not map to dom->disks. If require_match, also require that
- * existing def->disks snapshot states do not override explicit
- * def->dom settings. */
+ * the domain, with a fallback to a passed in default. Convert paths
+ * to disk targets for uniformity. Issue an error and return -1 if
+ * any def->disks[n]->name appears more than once or does not map to
+ * dom->disks. If require_match, also require that existing
+ * def->disks snapshot states do not override explicit def->dom
+ * settings. */
int
virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def,
int default_snapshot,
/* Double check requested disks. */
for (i = 0; i < def->ndisks; i++) {
virDomainSnapshotDiskDefPtr disk = &def->disks[i];
- int idx = virDomainDiskIndexByName(def->dom, disk->name);
+ int idx = virDomainDiskIndexByName(def->dom, disk->name, false);
int disk_snapshot;
if (idx < 0) {
disk->file, disk->name);
goto cleanup;
}
+ if (STRNEQ(disk->name, def->dom->disks[idx]->dst)) {
+ VIR_FREE(disk->name);
+ if (!(disk->name = strdup(def->dom->disks[idx]->dst))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
}
/* Provide defaults for all remaining disks. */
int virDomainVcpuPinDel(virDomainDefPtr def, int vcpu);
-int virDomainDiskIndexByName(virDomainDefPtr def, const char *name);
+int virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
+ bool allow_ambiguous);
+const char *virDomainDiskPathByName(virDomainDefPtr, const char *name);
int virDomainDiskInsert(virDomainDefPtr def,
virDomainDiskDefPtr disk);
void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
virDomainDiskInsertPreAlloced;
virDomainDiskIoTypeFromString;
virDomainDiskIoTypeToString;
+virDomainDiskPathByName;
virDomainDiskRemove;
virDomainDiskRemoveByName;
virDomainDiskSnapshotTypeFromString;
break;
case VIR_DOMAIN_DISK_DEVICE_DISK:
if (l_disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
- if (virDomainDiskIndexByName(vm->def, l_disk->dst) >= 0) {
+ if (virDomainDiskIndexByName(vm->def, l_disk->dst, true) >= 0) {
libxlError(VIR_ERR_OPERATION_FAILED,
_("target %s already exists"), l_disk->dst);
goto cleanup;
if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
if ((i = virDomainDiskIndexByName(vm->def,
- dev->data.disk->dst)) < 0) {
+ dev->data.disk->dst,
+ false)) < 0) {
libxlError(VIR_ERR_OPERATION_FAILED,
_("disk %s not found"), dev->data.disk->dst);
goto cleanup;
switch (dev->type) {
case VIR_DOMAIN_DEVICE_DISK:
disk = dev->data.disk;
- if (virDomainDiskIndexByName(vmdef, disk->dst) >= 0) {
+ if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
libxlError(VIR_ERR_INVALID_ARG,
_("target %s already exists."), disk->dst);
return -1;
switch (dev->type) {
case VIR_DOMAIN_DEVICE_DISK:
disk = dev->data.disk;
- if ((i = virDomainDiskIndexByName(vmdef, disk->dst)) < 0) {
+ if ((i = virDomainDiskIndexByName(vmdef, disk->dst, false)) < 0) {
libxlError(VIR_ERR_INVALID_ARG,
- _("target %s doesn't exists."), disk->dst);
+ _("target %s doesn't exist."), disk->dst);
goto cleanup;
}
orig = vmdef->disks[i];
switch (dev->type) {
case VIR_DOMAIN_DEVICE_DISK:
disk = dev->data.disk;
- if (virDomainDiskIndexByName(vmdef, disk->dst) >= 0) {
+ if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
qemuReportError(VIR_ERR_INVALID_ARG,
_("target %s already exists."), disk->dst);
return -1;
switch (dev->type) {
case VIR_DOMAIN_DEVICE_DISK:
disk = dev->data.disk;
- pos = virDomainDiskIndexByName(vmdef, disk->dst);
+ pos = virDomainDiskIndexByName(vmdef, disk->dst, false);
if (pos < 0) {
qemuReportError(VIR_ERR_INVALID_ARG,
- _("target %s doesn't exists."), disk->dst);
+ _("target %s doesn't exist."), disk->dst);
return -1;
}
orig = vmdef->disks[pos];
{
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
- int fd = -1, ret = -1, i;
+ int fd = -1, ret = -1;
+ const char *actual;
virCheckFlags(0, -1);
goto cleanup;
}
- /* Check the path belongs to this domain. */
- for (i = 0 ; i < vm->def->ndisks ; i++) {
- if (vm->def->disks[i]->src != NULL &&
- STREQ (vm->def->disks[i]->src, path)) {
- ret = 0;
- break;
- }
+ /* Check the path belongs to this domain. */
+ if (!(actual = virDomainDiskPathByName(vm->def, path))) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("invalid path '%s'"), path);
+ goto cleanup;
}
+ path = actual;
- if (ret == 0) {
- ret = -1;
- /* The path is correct, now try to open it and get its size. */
- fd = open (path, O_RDONLY);
- if (fd == -1) {
- virReportSystemError(errno,
- _("%s: failed to open"), path);
- goto cleanup;
- }
-
- /* Seek and read. */
- /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
- * be 64 bits on all platforms.
- */
- if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
- saferead (fd, buffer, size) == (ssize_t) -1) {
- virReportSystemError(errno,
- _("%s: failed to seek or read"), path);
- goto cleanup;
- }
+ /* The path is correct, now try to open it and get its size. */
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ virReportSystemError(errno,
+ _("%s: failed to open"), path);
+ goto cleanup;
+ }
- ret = 0;
- } else {
- qemuReportError(VIR_ERR_INVALID_ARG,
- "%s", _("invalid path"));
+ /* Seek and read. */
+ /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
+ * be 64 bits on all platforms.
+ */
+ if (lseek(fd, offset, SEEK_SET) == (off_t) -1 ||
+ saferead(fd, buffer, size) == (ssize_t) -1) {
+ virReportSystemError(errno,
+ _("%s: failed to seek or read"), path);
+ goto cleanup;
}
+ ret = 0;
+
cleanup:
VIR_FORCE_CLOSE(fd);
if (vm)
qemuDomainObjExitMonitor(driver, vm);
/* Read the memory file into buffer. */
- if (saferead (fd, buffer, size) == (ssize_t) -1) {
+ if (saferead(fd, buffer, size) == (ssize_t) -1) {
virReportSystemError(errno,
_("failed to read temporary file "
"created with template %s"), tmp);
virStorageFileMetadata *meta = NULL;
virDomainDiskDefPtr disk = NULL;
struct stat sb;
- int i;
int format;
+ const char *actual;
virCheckFlags(0, -1);
}
/* Check the path belongs to this domain. */
- for (i = 0 ; i < vm->def->ndisks ; i++) {
- if (vm->def->disks[i]->src != NULL &&
- STREQ (vm->def->disks[i]->src, path)) {
- disk = vm->def->disks[i];
- break;
- }
- }
-
- if (!disk) {
+ if (!(actual = virDomainDiskPathByName(vm->def, path))) {
qemuReportError(VIR_ERR_INVALID_ARG,
_("invalid path %s not assigned to domain"), path);
goto cleanup;
}
+ path = actual;
/* The path is correct, now try to open it and get its size. */
- fd = open (path, O_RDONLY);
+ fd = open(path, O_RDONLY);
if (fd == -1) {
virReportSystemError(errno,
_("failed to open path '%s'"), path);
/* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
* be 64 bits on all platforms.
*/
- end = lseek (fd, 0, SEEK_END);
+ end = lseek(fd, 0, SEEK_END);
if (end == (off_t)-1) {
virReportSystemError(errno,
_("failed to seek to end of %s"), path);
qemuDiskPathToAlias(virDomainObjPtr vm, const char *path) {
int i;
char *ret = NULL;
+ virDomainDiskDefPtr disk;
- for (i = 0 ; i < vm->def->ndisks ; i++) {
- virDomainDiskDefPtr disk = vm->def->disks[i];
+ i = virDomainDiskIndexByName(vm->def, path, true);
+ if (i < 0)
+ goto cleanup;
- if (disk->type != VIR_DOMAIN_DISK_TYPE_BLOCK &&
- disk->type != VIR_DOMAIN_DISK_TYPE_FILE)
- continue;
+ disk = vm->def->disks[i];
- if (disk->src != NULL && STREQ(disk->src, path)) {
- if (virAsprintf(&ret, "drive-%s", disk->info.alias) < 0) {
- virReportOOMError();
- return NULL;
- }
- break;
+ if (disk->type != VIR_DOMAIN_DISK_TYPE_BLOCK &&
+ disk->type != VIR_DOMAIN_DISK_TYPE_FILE)
+ goto cleanup;
+
+ if (disk->src) {
+ if (virAsprintf(&ret, "drive-%s", disk->info.alias) < 0) {
+ virReportOOMError();
+ return NULL;
}
}
+cleanup:
if (!ret) {
qemuReportError(VIR_ERR_INVALID_ARG,
"%s", _("No device found for specified path"));
qemuProcessFindDomainDiskByPath(virDomainObjPtr vm,
const char *path)
{
- int i;
-
- for (i = 0; i < vm->def->ndisks; i++) {
- virDomainDiskDefPtr disk;
+ int i = virDomainDiskIndexByName(vm->def, path, true);
- disk = vm->def->disks[i];
- if (disk->src != NULL && STREQ(disk->src, path))
- return disk;
- }
+ if (i >= 0)
+ return vm->def->disks[i];
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("no disk found with path %s"),
{
struct uml_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
- int fd = -1, ret = -1, i;
+ int fd = -1, ret = -1;
+ const char *actual;
virCheckFlags(0, -1);
}
/* Check the path belongs to this domain. */
- for (i = 0 ; i < vm->def->ndisks ; i++) {
- if (vm->def->disks[i]->src != NULL &&
- STREQ (vm->def->disks[i]->src, path)) {
- ret = 0;
- break;
- }
+ if (!(actual = virDomainDiskPathByName(vm->def, path))) {
+ umlReportError(VIR_ERR_INVALID_ARG,
+ _("invalid path '%s'"), path);
+ goto cleanup;
}
+ path = actual;
- if (ret == 0) {
- ret = -1;
- /* The path is correct, now try to open it and get its size. */
- fd = open (path, O_RDONLY);
- if (fd == -1) {
- virReportSystemError(errno,
- _("cannot open %s"), path);
- goto cleanup;
- }
-
- /* Seek and read. */
- /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
- * be 64 bits on all platforms.
- */
- if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
- saferead (fd, buffer, size) == (ssize_t) -1) {
- virReportSystemError(errno,
- _("cannot read %s"), path);
- goto cleanup;
- }
+ /* The path is correct, now try to open it and get its size. */
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ virReportSystemError(errno,
+ _("cannot open %s"), path);
+ goto cleanup;
+ }
- ret = 0;
- } else {
- umlReportError(VIR_ERR_INVALID_ARG, "%s",
- _("invalid path"));
+ /* Seek and read. */
+ /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
+ * be 64 bits on all platforms.
+ */
+ if (lseek(fd, offset, SEEK_SET) == (off_t) -1 ||
+ saferead(fd, buffer, size) == (ssize_t) -1) {
+ virReportSystemError(errno,
+ _("cannot read %s"), path);
+ goto cleanup;
}
+ ret = 0;
+
cleanup:
VIR_FORCE_CLOSE(fd);
if (vm)
xenUnifiedPrivatePtr priv;
struct sexpr *root = NULL;
int fd = -1, ret = -1;
- int found = 0, i;
virDomainDefPtr def;
int id;
char * tty;
int vncport;
+ const char *actual;
priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
vncport)))
goto cleanup;
- for (i = 0 ; i < def->ndisks ; i++) {
- if (def->disks[i]->src &&
- STREQ(def->disks[i]->src, path)) {
- found = 1;
- break;
- }
- }
- if (!found) {
+ if (!(actual = virDomainDiskPathByName(def, path))) {
virXendError(VIR_ERR_INVALID_ARG,
_("%s: invalid path"), path);
goto cleanup;
}
+ path = actual;
/* The path is correct, now try to open it and get its size. */
fd = open (path, O_RDONLY);
<name>my snap name</name>
<description>!@#$%^</description>
<disks>
- <disk name='hda'/>
+ <disk name='/dev/HostVG/QEMUGuest1'/>
<disk name='hdb' snapshot='no'/>
<disk name='hdc' snapshot='internal'/>
<disk name='hdd' snapshot='external'>
=item B<domblkstat> I<domain> I<block-device>
-Get device block stats for a running domain.
+Get device block stats for a running domain. A I<block-device> corresponds
+to a unique target name (<target dev='name'/>) or source file (<source
+file='name'/>) for one of the disk devices attached to I<domain>.
=item B<domifstat> I<domain> I<interface-device>
=item B<domblkinfo> I<domain> I<block-device>
-Get block device size info for a domain.
+Get block device size info for a domain. A I<block-device> corresponds
+to a unique target name (<target dev='name'/>) or source file (<source
+file='name'/>) for one of the disk devices attached to I<domain>.
=item B<blockpull> I<domain> I<path> [I<bandwidth>]