[libvirt] [PATCHv4 44/51] snapshot: also support disks by path

Eric Blake eblake at redhat.com
Fri Sep 2 04:25:21 UTC 2011


I got confused when 'virsh domblkinfo dom disk' required the
path to a disk (which can be ambiguous, since a single file
can back multiple disks), rather than the unambiguous target
device name that I was using in disk snapshots.  So, in true
developer fashion, I went for the best of both worlds - all
interfaces that operate on a disk (aka block) now accept
either the target name or the unambiguous path to the backing
file used by the disk.

* src/conf/domain_conf.h (virDomainDiskIndexByName): Add
parameter.
(virDomainDiskPathByName): New prototype.
* src/libvirt_private.syms (domain_conf.h): Export it.
* src/conf/domain_conf.c (virDomainDiskIndexByName): Also allow
searching by path, and decide whether ambiguity is okay.
(virDomainDiskPathByName): New function.
(virDomainDiskRemoveByName, virDomainSnapshotAlignDisks): Update
callers.
* src/qemu/qemu_driver.c (qemudDomainBlockPeek)
(qemuDomainAttachDeviceConfig, qemuDomainUpdateDeviceConfig)
(qemuDomainGetBlockInfo, qemuDiskPathToAlias): Likewise.
* src/qemu/qemu_process.c (qemuProcessFindDomainDiskByPath):
Likewise.
* src/libxl/libxl_driver.c (libxlDomainAttachDeviceDiskLive)
(libxlDomainDetachDeviceDiskLive, libxlDomainAttachDeviceConfig)
(libxlDomainUpdateDeviceConfig): Likewise.
* src/uml/uml_driver.c (umlDomainBlockPeek): Likewise.
* src/xen/xend_internal.c (xenDaemonDomainBlockPeek): Likewise.
* docs/formatsnapshot.html.in: Update documentation.
* tools/virsh.pod (domblkstat, domblkinfo): Likewise.
* docs/schemas/domaincommon.rng (diskTarget): Tighten pattern on
disk targets.
* docs/schemas/domainsnapshot.rng (disksnapshot): Update to match.
* tests/domainsnapshotxml2xmlin/disk_snapshot.xml: Update test.
---
 docs/formatsnapshot.html.in                     |    7 +-
 docs/schemas/domaincommon.rng                   |    7 ++-
 docs/schemas/domainsnapshot.rng                 |    5 +-
 src/conf/domain_conf.c                          |   57 ++++++++++---
 src/conf/domain_conf.h                          |    4 +-
 src/libvirt_private.syms                        |    1 +
 src/libxl/libxl_driver.c                        |   11 ++-
 src/qemu/qemu_driver.c                          |  102 ++++++++++------------
 src/qemu/qemu_process.c                         |   11 +--
 src/uml/uml_driver.c                            |   56 ++++++-------
 src/xen/xend_internal.c                         |   12 +--
 tests/domainsnapshotxml2xmlin/disk_snapshot.xml |    2 +-
 tools/virsh.pod                                 |    8 ++-
 13 files changed, 154 insertions(+), 129 deletions(-)

diff --git a/docs/formatsnapshot.html.in b/docs/formatsnapshot.html.in
index 9c7631c..ffc626b 100644
--- a/docs/formatsnapshot.html.in
+++ b/docs/formatsnapshot.html.in
@@ -125,8 +125,9 @@
           <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
@@ -198,7 +199,7 @@
 <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'/>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 0af9e0f..e1c6a95 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -770,10 +770,15 @@
       </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">
diff --git a/docs/schemas/domainsnapshot.rng b/docs/schemas/domainsnapshot.rng
index 671fbe0..0ef0631 100644
--- a/docs/schemas/domainsnapshot.rng
+++ b/docs/schemas/domainsnapshot.rng
@@ -82,7 +82,10 @@
   <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'>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index aa0ad83..f9ca99c 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -5518,17 +5518,44 @@ virDomainChrTargetTypeToString(int deviceType,
     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,
@@ -5604,7 +5631,7 @@ void virDomainDiskRemove(virDomainDefPtr def, size_t i)

 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);
@@ -11229,11 +11256,12 @@ disksorter(const void *a, const void *b)

 /* 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,
@@ -11271,7 +11299,7 @@ virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def,
     /* 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) {
@@ -11309,6 +11337,13 @@ virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def,
                                  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.  */
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 2e34ace..f45711b 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1562,7 +1562,9 @@ int virDomainVcpuPinAdd(virDomainDefPtr def,

 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,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 1aa33ef..8c036ce 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -284,6 +284,7 @@ virDomainDiskInsert;
 virDomainDiskInsertPreAlloced;
 virDomainDiskIoTypeFromString;
 virDomainDiskIoTypeToString;
+virDomainDiskPathByName;
 virDomainDiskRemove;
 virDomainDiskRemoveByName;
 virDomainDiskSnapshotTypeFromString;
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 91da438..4302c8b 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -2929,7 +2929,7 @@ libxlDomainAttachDeviceDiskLive(libxlDomainObjPrivatePtr priv,
             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;
@@ -2991,7 +2991,8 @@ libxlDomainDetachDeviceDiskLive(libxlDomainObjPrivatePtr priv,
             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;
@@ -3061,7 +3062,7 @@ libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
     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;
@@ -3172,9 +3173,9 @@ libxlDomainUpdateDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
     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];
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d3968cf..c7e195f 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5443,7 +5443,7 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
     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;
@@ -5561,10 +5561,10 @@ qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
     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];
@@ -7303,7 +7303,8 @@ qemudDomainBlockPeek (virDomainPtr dom,
 {
     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);

@@ -7325,42 +7326,35 @@ qemudDomainBlockPeek (virDomainPtr dom,
         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)
@@ -7475,8 +7469,8 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
     virStorageFileMetadata *meta = NULL;
     virDomainDiskDefPtr disk = NULL;
     struct stat sb;
-    int i;
     int format;
+    const char *actual;

     virCheckFlags(0, -1);

@@ -7498,19 +7492,12 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
     }

     /* 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);
@@ -9782,23 +9769,26 @@ static const char *
 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"));
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index c22974f..f36efea 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -192,15 +192,10 @@ static virDomainDiskDefPtr
 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"),
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index 19b6c55..75c8f27 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -2175,7 +2175,8 @@ umlDomainBlockPeek(virDomainPtr dom,
 {
     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);

@@ -2196,41 +2197,34 @@ umlDomainBlockPeek(virDomainPtr dom,
     }

     /* 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)
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
index 0a7fb48..8e21701 100644
--- a/src/xen/xend_internal.c
+++ b/src/xen/xend_internal.c
@@ -3849,11 +3849,11 @@ xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path,
     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;

@@ -3889,18 +3889,12 @@ xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path,
                              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);
diff --git a/tests/domainsnapshotxml2xmlin/disk_snapshot.xml b/tests/domainsnapshotxml2xmlin/disk_snapshot.xml
index 1f0beb6..ee6b46a 100644
--- a/tests/domainsnapshotxml2xmlin/disk_snapshot.xml
+++ b/tests/domainsnapshotxml2xmlin/disk_snapshot.xml
@@ -2,7 +2,7 @@
   <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'>
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 30548b4..c40e9f3 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -503,7 +503,9 @@ snapshot metadata with B<snapshot-create>.

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

@@ -515,7 +517,9 @@ Get memory stats for a running domain.

 =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>]

-- 
1.7.4.4




More information about the libvir-list mailing list