[libvirt] [PATCH v2 07/12] qemu: refactor blockinfo data gathering

Eric Blake eblake at redhat.com
Tue Dec 16 08:04:13 UTC 2014


Create a helper function that can be reused for gathering block
info from virDomainListGetStats.

* src/qemu/qemu_driver.c (qemuDomainGetBlockInfo): Split guts...
(qemuStorageLimitsRefresh): ...into new helper function.

Signed-off-by: Eric Blake <eblake at redhat.com>
---
 src/qemu/qemu_driver.c | 207 ++++++++++++++++++++++++++-----------------------
 1 file changed, 110 insertions(+), 97 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5e9c133..13ec903 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10992,65 +10992,23 @@ qemuDomainMemoryPeek(virDomainPtr dom,
 }


+/* Refresh the capacity and allocation limits of a given storage
+ * source.  Assumes that the caller has already obtained a domain
+ * job. */
 static int
-qemuDomainGetBlockInfo(virDomainPtr dom,
-                       const char *path,
-                       virDomainBlockInfoPtr info,
-                       unsigned int flags)
+qemuStorageLimitsRefresh(virQEMUDriverPtr driver, virQEMUDriverConfigPtr cfg,
+                         virDomainObjPtr vm, virDomainDiskDefPtr disk,
+                         virStorageSourcePtr src)
 {
-    virQEMUDriverPtr driver = dom->conn->privateData;
-    virDomainObjPtr vm;
     int ret = -1;
     int fd = -1;
     off_t end;
     virStorageSourcePtr meta = NULL;
-    virDomainDiskDefPtr disk = NULL;
     struct stat sb;
-    int idx;
-    int format;
-    bool activeFail = false;
-    virQEMUDriverConfigPtr cfg = NULL;
+    int format = src->format;
     char *buf = NULL;
     ssize_t len;

-    virCheckFlags(0, -1);
-
-    if (!(vm = qemuDomObjFromDomain(dom)))
-        return -1;
-
-    cfg = virQEMUDriverGetConfig(driver);
-
-    if (virDomainGetBlockInfoEnsureACL(dom->conn, vm->def) < 0)
-        goto cleanup;
-
-    if (!path || path[0] == '\0') {
-        virReportError(VIR_ERR_INVALID_ARG, "%s", _("NULL or empty path"));
-        goto cleanup;
-    }
-
-    /* Technically, we only need a job if we are going to query the
-     * monitor, which is only for active domains that are using
-     * non-raw block devices.  But it is easier to share code if we
-     * always grab a job; furthermore, grabbing the job ensures that
-     * hot-plug won't change disk behind our backs.  */
-    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
-        goto cleanup;
-
-    /* Check the path belongs to this domain. */
-    if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("invalid path %s not assigned to domain"), path);
-        goto endjob;
-    }
-
-    disk = vm->def->disks[idx];
-    if (virStorageSourceIsEmpty(disk->src)) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("disk '%s' does not currently have a source assigned"),
-                       path);
-        goto endjob;
-    }
-
     /* FIXME: For an offline domain, we always want to check current
      * on-disk statistics (as users have been known to change offline
      * images behind our backs).  For a running domain, however, it
@@ -11071,51 +11029,51 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
      * punching holes), and physical size of a non-raw file can
      * change.
      */
-    if (virStorageSourceIsLocalStorage(disk->src)) {
+    if (virStorageSourceIsLocalStorage(src)) {
         /* Yes, this is a mild TOCTTOU race, but if someone is
          * changing files in the background behind libvirt's back,
          * they deserve bogus information.  */
-        if (stat(disk->src->path, &sb) < 0) {
+        if (stat(src->path, &sb) < 0) {
             virReportSystemError(errno,
-                                 _("cannot stat file '%s'"), disk->src->path);
-            goto endjob;
+                                 _("cannot stat file '%s'"), src->path);
+            goto cleanup;
         }

-        if ((fd = qemuOpenFile(driver, vm, disk->src->path, O_RDONLY,
+        if ((fd = qemuOpenFile(driver, vm, src->path, O_RDONLY,
                                NULL, NULL)) == -1)
-            goto endjob;
+            goto cleanup;

         if ((len = virFileReadHeaderFD(fd, VIR_STORAGE_MAX_HEADER, &buf)) < 0) {
             virReportSystemError(errno, _("cannot read header '%s'"),
-                                 disk->src->path);
-            goto endjob;
+                                 src->path);
+            goto cleanup;
         }
     } else {
-        if (virStorageFileInitAs(disk->src, cfg->user, cfg->group) < 0)
-            goto endjob;
+        if (virStorageFileInitAs(src, cfg->user, cfg->group) < 0)
+            goto cleanup;

-        if (virStorageFileStat(disk->src, &sb) < 0) {
+        if (virStorageFileStat(src, &sb) < 0) {
             virReportSystemError(errno, _("failed to stat remote file '%s'"),
-                                 NULLSTR(disk->src->path));
-            goto endjob;
+                                 NULLSTR(src->path));
+            goto cleanup;
         }

-        if ((len = virStorageFileReadHeader(disk->src, VIR_STORAGE_MAX_HEADER,
+        if ((len = virStorageFileReadHeader(src, VIR_STORAGE_MAX_HEADER,
                                             &buf)) < 0)
-            goto endjob;
+            goto cleanup;
     }

     /* Get info for normal formats */
     if (S_ISREG(sb.st_mode) || fd == -1) {
 #ifndef WIN32
-        disk->src->allocation = (unsigned long long)sb.st_blocks *
+        src->allocation = (unsigned long long)sb.st_blocks *
             (unsigned long long)DEV_BSIZE;
 #else
-        disk->src->allocation = sb.st_size;
+        src->allocation = sb.st_size;
 #endif
         /* Allocation tracks when the file is sparse, physical is the
          * last offset of the file. */
-        disk->src->physical = sb.st_size;
+        src->physical = sb.st_size;
     } else {
         /* NB. Because we configure with AC_SYS_LARGEFILE, off_t
          * should be 64 bits on all platforms.  For block devices, we
@@ -11127,11 +11085,11 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
         end = lseek(fd, 0, SEEK_END);
         if (end == (off_t)-1) {
             virReportSystemError(errno,
-                                 _("failed to seek to end of %s"), path);
-            goto endjob;
+                                 _("failed to seek to end of %s"), src->path);
+            goto cleanup;
         }
-        disk->src->physical = end;
-        disk->src->allocation = end;
+        src->physical = end;
+        src->allocation = end;
     }

     /* Raw files: capacity is physical size.  For all other files: if
@@ -11141,29 +11099,96 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
         if (!cfg->allowDiskFormatProbing) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("no disk format for %s and probing is disabled"),
-                           path);
-            goto endjob;
+                           src->path);
+            goto cleanup;
         }

-        if ((format = virStorageFileProbeFormatFromBuf(disk->src->path,
+        if ((format = virStorageFileProbeFormatFromBuf(src->path,
                                                        buf, len)) < 0)
-            goto endjob;
+            goto cleanup;
     }
     if (format == VIR_STORAGE_FILE_RAW) {
-        disk->src->capacity = disk->src->physical;
-    } else if (!(meta = virStorageFileGetMetadataFromBuf(disk->src->path, buf,
+        src->capacity = src->physical;
+    } else if (!(meta = virStorageFileGetMetadataFromBuf(src->path, buf,
                                                          len, format, NULL))) {
-        goto endjob;
-        disk->src->capacity = meta->capacity ? meta->capacity
-            : disk->src->physical;
+        goto cleanup;
+        src->capacity = meta->capacity ? meta->capacity : src->physical;
     }

     /* If guest is not using raw disk format and on a block device,
      * then query highest allocated extent from QEMU
      */
-    if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_BLOCK &&
+    if (virStorageSourceGetActualType(src) == VIR_STORAGE_TYPE_BLOCK &&
         format != VIR_STORAGE_FILE_RAW &&
-        S_ISBLK(sb.st_mode)) {
+        S_ISBLK(sb.st_mode))
+        src->allocation = 0;
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(buf);
+    virStorageSourceFree(meta);
+    VIR_FORCE_CLOSE(fd);
+    virStorageFileDeinit(src);
+    return ret;
+}
+
+
+static int
+qemuDomainGetBlockInfo(virDomainPtr dom,
+                       const char *path,
+                       virDomainBlockInfoPtr info,
+                       unsigned int flags)
+{
+    virQEMUDriverPtr driver = dom->conn->privateData;
+    virDomainObjPtr vm;
+    int ret = -1;
+    virDomainDiskDefPtr disk = NULL;
+    int idx;
+    bool activeFail = false;
+    virQEMUDriverConfigPtr cfg = NULL;
+
+    virCheckFlags(0, -1);
+
+    if (!(vm = qemuDomObjFromDomain(dom)))
+        return -1;
+
+    cfg = virQEMUDriverGetConfig(driver);
+
+    if (virDomainGetBlockInfoEnsureACL(dom->conn, vm->def) < 0)
+        goto cleanup;
+
+    if (!path || path[0] == '\0') {
+        virReportError(VIR_ERR_INVALID_ARG, "%s", _("NULL or empty path"));
+        goto cleanup;
+    }
+
+    /* Technically, we only need a job if we are going to query the
+     * monitor, which is only for active domains that are using
+     * non-raw block devices.  But it is easier to share code if we
+     * always grab a job; furthermore, grabbing the job ensures that
+     * hot-plug won't change disk behind our backs.  */
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
+        goto cleanup;
+
+    /* Check the path belongs to this domain. */
+    if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("invalid path %s not assigned to domain"), path);
+        goto endjob;
+    }
+
+    disk = vm->def->disks[idx];
+    if (virStorageSourceIsEmpty(disk->src)) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("disk '%s' does not currently have a source assigned"),
+                       path);
+        goto endjob;
+    }
+
+    if ((ret = qemuStorageLimitsRefresh(driver, cfg, vm, disk, disk->src)) < 0)
+        goto endjob;
+
+    if (!disk->src->allocation) {
         qemuDomainObjPrivatePtr priv = vm->privateData;

         /* If the guest is not running, then success/failure return
@@ -11171,7 +11196,6 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
          */
         if (!virDomainObjIsActive(vm)) {
             activeFail = true;
-            ret = 0;
             goto endjob;
         }

@@ -11180,27 +11204,16 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
                                         disk->info.alias,
                                         &disk->src->allocation);
         qemuDomainObjExitMonitor(driver, vm);
-
-    } else {
-        ret = 0;
     }

-    if (ret == 0) {
-        info->capacity = disk->src->capacity;
-        info->allocation = disk->src->allocation;
-        info->physical = disk->src->physical;
-    }
+    info->capacity = disk->src->capacity;
+    info->allocation = disk->src->allocation;
+    info->physical = disk->src->physical;

  endjob:
     if (!qemuDomainObjEndJob(driver, vm))
         vm = NULL;
  cleanup:
-    VIR_FREE(buf);
-    virStorageSourceFree(meta);
-    VIR_FORCE_CLOSE(fd);
-    if (disk)
-        virStorageFileDeinit(disk->src);
-
     /* If we failed to get data from a domain because it's inactive and
      * it's not a persistent domain, then force failure.
      */
-- 
1.9.3




More information about the libvir-list mailing list