[libvirt] [PATCH 3/4] qemu: Refactor qemuMonitorGetBlockInfo

Jiri Denemark jdenemar at redhat.com
Mon Jan 23 13:30:56 UTC 2012


QEMU always sends details about all available block devices as an answer
for "info block"/"query-block" command. On the other hand, our
qemuMonitorGetBlockInfo was made for a single block devices queries
only. Thus, when asking for multiple devices, we asked qemu multiple
times to always get the same answer from which different parts were
filtered. This patch makes qemuMonitorGetBlockInfo return a hash table
of all block devices, which may later be used for getting details about
specific devices.
---
 src/qemu/qemu_hotplug.c      |   22 +++++++++++--------
 src/qemu/qemu_monitor.c      |   43 +++++++++++++++++++++++++++++++-------
 src/qemu/qemu_monitor.h      |    9 +++++--
 src/qemu/qemu_monitor_json.c |   28 ++++++++++--------------
 src/qemu/qemu_monitor_json.h |    3 +-
 src/qemu/qemu_monitor_text.c |   47 ++++++++++++++++++++++++-----------------
 src/qemu/qemu_monitor_text.h |    3 +-
 7 files changed, 95 insertions(+), 60 deletions(-)

diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 4b60839..b4870be 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -155,34 +155,38 @@ qemuDomainCheckEjectableMedia(struct qemud_driver *driver,
                              virDomainObjPtr vm)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    virHashTablePtr table;
     int ret = -1;
     int i;
 
+    qemuDomainObjEnterMonitor(driver, vm);
+    table = qemuMonitorGetBlockInfo(priv->mon);
+    qemuDomainObjExitMonitor(driver, vm);
+
+    if (!table)
+        goto cleanup;
+
     for (i = 0; i < vm->def->ndisks; i++) {
         virDomainDiskDefPtr disk = vm->def->disks[i];
-        struct qemuDomainDiskInfo info;
+        struct qemuDomainDiskInfo *info;
 
         if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK ||
             disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
                  continue;
         }
 
-        memset(&info, 0, sizeof(info));
-
-        qemuDomainObjEnterMonitor(driver, vm);
-        if (qemuMonitorGetBlockInfo(priv->mon, disk->info.alias, &info) < 0) {
-            qemuDomainObjExitMonitor(driver, vm);
+        info = qemuMonitorBlockInfoLookup(table, disk->info.alias);
+        if (!info)
             goto cleanup;
-        }
-        qemuDomainObjExitMonitor(driver, vm);
 
-        if (info.tray_open && disk->src)
+        if (info->tray_open && disk->src)
             VIR_FREE(disk->src);
     }
 
     ret = 0;
 
 cleanup:
+    virHashFree(table);
     return ret;
 }
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index ad7e2a5..dda0521 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1227,24 +1227,51 @@ int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
     return ret;
 }
 
-int qemuMonitorGetBlockInfo(qemuMonitorPtr mon,
-                            const char *devname,
-                            struct qemuDomainDiskInfo *info)
+virHashTablePtr
+qemuMonitorGetBlockInfo(qemuMonitorPtr mon)
 {
     int ret;
+    virHashTablePtr table;
+
+    VIR_DEBUG("mon=%p", mon);
 
-    VIR_DEBUG("mon=%p dev=%p info=%p", mon, devname, info);
     if (!mon) {
         qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                         _("monitor must not be NULL"));
-        return -1;
+        return NULL;
     }
 
+    if (!(table = virHashCreate(32, (virHashDataFree) free)))
+        return NULL;
+
     if (mon->json)
-        ret = qemuMonitorJSONGetBlockInfo(mon, devname, info);
+        ret = qemuMonitorJSONGetBlockInfo(mon, table);
     else
-        ret = qemuMonitorTextGetBlockInfo(mon, devname, info);
-    return ret;
+        ret = qemuMonitorTextGetBlockInfo(mon, table);
+
+    if (ret < 0) {
+        virHashFree(table);
+        return NULL;
+    }
+
+    return table;
+}
+
+struct qemuDomainDiskInfo *
+qemuMonitorBlockInfoLookup(virHashTablePtr blockInfo,
+                           const char *devname)
+{
+    struct qemuDomainDiskInfo *info;
+
+    VIR_DEBUG("blockInfo=%p dev=%s", blockInfo, NULLSTR(devname));
+
+    if (!(info = virHashLookup(blockInfo, devname))) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("cannot find info for device '%s'"),
+                        NULLSTR(devname));
+    }
+
+    return info;
 }
 
 int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 15acf8b..4d52f06 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -235,9 +235,12 @@ int qemuMonitorGetBalloonInfo(qemuMonitorPtr mon,
 int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
                               virDomainMemoryStatPtr stats,
                               unsigned int nr_stats);
-int qemuMonitorGetBlockInfo(qemuMonitorPtr mon,
-                            const char *devname,
-                            struct qemuDomainDiskInfo *info);
+
+virHashTablePtr qemuMonitorGetBlockInfo(qemuMonitorPtr mon);
+struct qemuDomainDiskInfo *
+qemuMonitorBlockInfoLookup(virHashTablePtr blockInfo,
+                           const char *devname);
+
 int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
                                  const char *dev_name,
                                  long long *rd_req,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 4a76fc0..3afcff3 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1357,11 +1357,9 @@ cleanup:
 
 
 int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
-                                const char *devname,
-                                struct qemuDomainDiskInfo *info)
+                                virHashTablePtr table)
 {
-    int ret = 0;
-    bool found = false;
+    int ret;
     int i;
 
     virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-block",
@@ -1389,6 +1387,7 @@ int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
 
     for (i = 0; i < virJSONValueArraySize(devices); i++) {
         virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
+        struct qemuDomainDiskInfo *info;
         const char *thisdev;
 
         if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
@@ -1406,10 +1405,16 @@ int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
         if (STRPREFIX(thisdev, QEMU_DRIVE_HOST_PREFIX))
             thisdev += strlen(QEMU_DRIVE_HOST_PREFIX);
 
-        if (STRNEQ(thisdev, devname))
-            continue;
+        if (VIR_ALLOC(info) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        if (virHashAddEntry(table, thisdev, info) < 0) {
+            VIR_FREE(info);
+            goto cleanup;
+        }
 
-        found = true;
         if (virJSONValueObjectGetBoolean(dev, "removable", &info->removable) < 0) {
             qemuReportError(VIR_ERR_INTERNAL_ERROR,
                             _("cannot read %s value"),
@@ -1429,15 +1434,6 @@ int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
          */
         ignore_value(virJSONValueObjectGetBoolean(dev, "tray-open",
                                                   &info->tray_open));
-
-        break;
-    }
-
-    if (!found) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("cannot find info for device '%s'"),
-                        devname);
-        goto cleanup;
     }
 
     ret = 0;
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 5991790..d221e59 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -63,8 +63,7 @@ int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
                                   virDomainMemoryStatPtr stats,
                                   unsigned int nr_stats);
 int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
-                                const char *devname,
-                                struct qemuDomainDiskInfo *info);
+                                virHashTablePtr table);
 int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
                                      const char *dev_name,
                                      long long *rd_req,
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 2c68be8..a33d192 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -772,14 +772,14 @@ int qemuMonitorTextGetMemoryStats(qemuMonitorPtr mon,
 
 
 int qemuMonitorTextGetBlockInfo(qemuMonitorPtr mon,
-                                const char *devname,
-                                struct qemuDomainDiskInfo *info)
+                                virHashTablePtr table)
 {
+    struct qemuDomainDiskInfo *info;
     char *reply = NULL;
     int ret = -1;
     char *dummy;
-    const char *p, *eol;
-    int devnamelen = strlen(devname);
+    char *p, *eol;
+    char *dev;
     int tmp;
 
     if (qemuMonitorHMPCommand(mon, "info block", &reply) < 0) {
@@ -805,16 +805,22 @@ int qemuMonitorTextGetBlockInfo(qemuMonitorPtr mon,
         if (STRPREFIX(p, QEMU_DRIVE_HOST_PREFIX))
             p += strlen(QEMU_DRIVE_HOST_PREFIX);
 
-        if (STREQLEN(p, devname, devnamelen) &&
-            p[devnamelen] == ':' && p[devnamelen+1] == ' ') {
+        eol = strchr(p, '\n');
+        if (!eol)
+            eol = p + strlen(p) - 1;
 
-            eol = strchr(p, '\n');
-            if (!eol)
-                eol = p + strlen(p);
+        dev = p;
+        p = strchr(p, ':');
+        if (p && p < eol && *(p + 1) == ' ') {
+            if (VIR_ALLOC(info) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
 
-            p += devnamelen + 2; /* Skip to first label. */
+            *p = '\0';
+            p += 2;
 
-            while (*p) {
+            while (p < eol) {
                 if (STRPREFIX(p, "removable=")) {
                     p += strlen("removable=");
                     if (virStrToLong_i(p, &dummy, 10, &tmp) == -1)
@@ -839,24 +845,25 @@ int qemuMonitorTextGetBlockInfo(qemuMonitorPtr mon,
 
                 /* skip to next label */
                 p = strchr(p, ' ');
-                if (!p || p >= eol) break;
+                if (!p)
+                    break;
                 p++;
             }
 
-            ret = 0;
-            goto cleanup;
+            if (virHashAddEntry(table, dev, info) < 0)
+                goto cleanup;
+            else
+                info = NULL;
         }
 
-        /* skip to next line */
-        p = strchr(p, '\n');
-        if (!p) break;
-        p++;
+        /* skip to the next line */
+        p = eol + 1;
     }
 
-    qemuReportError(VIR_ERR_INVALID_ARG,
-                    _("no info for device '%s'"), devname);
+    ret = 0;
 
 cleanup:
+    VIR_FREE(info);
     VIR_FREE(reply);
     return ret;
 }
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index dee2980..ba1b0d0 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -60,8 +60,7 @@ int qemuMonitorTextGetMemoryStats(qemuMonitorPtr mon,
                                   virDomainMemoryStatPtr stats,
                                   unsigned int nr_stats);
 int qemuMonitorTextGetBlockInfo(qemuMonitorPtr mon,
-                                const char *devname,
-                                struct qemuDomainDiskInfo *info);
+                                virHashTablePtr table);
 int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
                                      const char *dev_name,
                                      long long *rd_req,
-- 
1.7.8.4




More information about the libvir-list mailing list