[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH v3 3/5] qemu: Implement virDomainGetDiskErrors



---
 src/qemu/qemu_conf.h         |    1 +
 src/qemu/qemu_driver.c       |   86 ++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_monitor.c      |   40 +++++++++++++++++++
 src/qemu/qemu_monitor.h      |    1 +
 src/qemu/qemu_monitor_json.c |    8 ++++
 src/qemu/qemu_monitor_text.c |   15 +++++++
 6 files changed, 151 insertions(+), 0 deletions(-)

diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 7d79823..0b65d7d 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -175,6 +175,7 @@ struct qemuDomainDiskInfo {
     bool removable;
     bool locked;
     bool tray_open;
+    int io_status;
 };
 
 #endif /* __QEMUD_CONF_H */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1b147a9..a7ac75a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -11740,6 +11740,91 @@ cleanup:
     return ret;
 }
 
+static int
+qemuDomainGetDiskErrors(virDomainPtr dom,
+                        virDomainDiskErrorPtr errors,
+                        unsigned int nerrors,
+                        unsigned int flags)
+{
+    struct qemud_driver *driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    qemuDomainObjPrivatePtr priv;
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    virHashTablePtr table = NULL;
+    int ret = -1;
+    int i;
+    int n = 0;
+
+    virCheckFlags(0, -1);
+
+    qemuDriverLock(driver);
+    virUUIDFormat(dom->uuid, uuidstr);
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+    qemuDriverUnlock(driver);
+
+    if (!vm) {
+        qemuReportError(VIR_ERR_NO_DOMAIN,
+                        _("no domain with matching uuid '%s'"), uuidstr);
+        goto cleanup;
+    }
+
+    priv = vm->privateData;
+
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        qemuReportError(VIR_ERR_OPERATION_INVALID,
+                        "%s", _("domain is not running"));
+        goto endjob;
+    }
+
+    if (!errors) {
+        ret = vm->def->ndisks;
+        goto endjob;
+    }
+
+    qemuDomainObjEnterMonitor(driver, vm);
+    table = qemuMonitorGetBlockInfo(priv->mon);
+    qemuDomainObjExitMonitor(driver, vm);
+    if (!table)
+        goto endjob;
+
+    for (i = n = 0; i < vm->def->ndisks; i++) {
+        struct qemuDomainDiskInfo *info;
+        virDomainDiskDefPtr disk = vm->def->disks[i];
+
+        if ((info = virHashLookup(table, disk->info.alias)) &&
+            info->io_status != VIR_DOMAIN_DISK_ERROR_NONE) {
+            if (n == nerrors)
+                break;
+
+            if (!(errors[n].disk = strdup(disk->dst))) {
+                virReportOOMError();
+                goto endjob;
+            }
+            errors[n].error = info->io_status;
+            n++;
+        }
+    }
+
+    ret = n;
+
+endjob:
+    if (qemuDomainObjEndJob(driver, vm) == 0)
+        vm = NULL;
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    virHashFree(table);
+    if (ret < 0) {
+        for (i = 0; i < n; i++)
+            VIR_FREE(errors[i].disk);
+    }
+    return ret;
+}
+
 static virDriver qemuDriver = {
     .no = VIR_DRV_QEMU,
     .name = "QEMU",
@@ -11893,6 +11978,7 @@ static virDriver qemuDriver = {
     .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.9 */
     .domainGetInterfaceParameters = qemuDomainGetInterfaceParameters, /* 0.9.9 */
     .domainSetInterfaceParameters = qemuDomainSetInterfaceParameters, /* 0.9.9 */
+    .domainGetDiskErrors = qemuDomainGetDiskErrors, /* 0.9.10 */
 };
 
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index dda0521..7872e3d 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -87,6 +87,20 @@ VIR_ENUM_IMPL(qemuMonitorVMStatus,
               "postmigrate", "prelaunch", "finish-migrate", "restore-vm",
               "running", "save-vm", "shutdown", "watchdog")
 
+typedef enum {
+    QEMU_MONITOR_BLOCK_IO_STATUS_OK,
+    QEMU_MONITOR_BLOCK_IO_STATUS_FAILED,
+    QEMU_MONITOR_BLOCK_IO_STATUS_NOSPACE,
+
+    QEMU_MONITOR_BLOCK_IO_STATUS_LAST
+} qemuMonitorBlockIOStatus;
+
+VIR_ENUM_DECL(qemuMonitorBlockIOStatus)
+
+VIR_ENUM_IMPL(qemuMonitorBlockIOStatus,
+              QEMU_MONITOR_BLOCK_IO_STATUS_LAST,
+              "ok", "failed", "nospace")
+
 char *qemuMonitorEscapeArg(const char *in)
 {
     int len = 0;
@@ -1227,6 +1241,32 @@ int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
     return ret;
 }
 
+int
+qemuMonitorBlockIOStatusToError(const char *status)
+{
+    int st = qemuMonitorBlockIOStatusTypeFromString(status);
+
+    if (st < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("unknown block IO status: %s"), status);
+        return -1;
+    }
+
+    switch ((qemuMonitorBlockIOStatus) st) {
+    case QEMU_MONITOR_BLOCK_IO_STATUS_OK:
+        return VIR_DOMAIN_DISK_ERROR_NONE;
+    case QEMU_MONITOR_BLOCK_IO_STATUS_FAILED:
+        return VIR_DOMAIN_DISK_ERROR_UNSPEC;
+    case QEMU_MONITOR_BLOCK_IO_STATUS_NOSPACE:
+        return VIR_DOMAIN_DISK_ERROR_NO_SPACE;
+
+    /* unreachable */
+    case QEMU_MONITOR_BLOCK_IO_STATUS_LAST:
+        break;
+    }
+    return -1;
+}
+
 virHashTablePtr
 qemuMonitorGetBlockInfo(qemuMonitorPtr mon)
 {
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index a9471fe..5945d3e 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -236,6 +236,7 @@ int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
                               virDomainMemoryStatPtr stats,
                               unsigned int nr_stats);
 
+int qemuMonitorBlockIOStatusToError(const char *status);
 virHashTablePtr qemuMonitorGetBlockInfo(qemuMonitorPtr mon);
 struct qemuDomainDiskInfo *
 qemuMonitorBlockInfoLookup(virHashTablePtr blockInfo,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 0bd9f46..b0ae570 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1389,6 +1389,7 @@ int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
         virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
         struct qemuDomainDiskInfo *info;
         const char *thisdev;
+        const char *status;
 
         if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
             qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -1434,6 +1435,13 @@ int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
          */
         ignore_value(virJSONValueObjectGetBoolean(dev, "tray-open",
                                                   &info->tray_open));
+
+        /* Missing io-status indicates no error */
+        if ((status = virJSONValueObjectGetString(dev, "io-status"))) {
+            info->io_status = qemuMonitorBlockIOStatusToError(status);
+            if (info->io_status < 0)
+                goto cleanup;
+        }
     }
 
     ret = 0;
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index edeb435..f051a86 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -839,6 +839,21 @@ int qemuMonitorTextGetBlockInfo(qemuMonitorPtr mon,
                         VIR_DEBUG("error reading tray_open: %s", p);
                     else
                         info->tray_open = (tmp != 0);
+                } else if (STRPREFIX(p, "io-status=")) {
+                    char *end;
+                    char c;
+
+                    p += strlen("io-status=");
+                    end = strchr(p, ' ');
+                    if (!end || end > eol)
+                        end = eol;
+
+                    c = *end;
+                    *end = '\0';
+                    info->io_status = qemuMonitorBlockIOStatusToError(p);
+                    *end = c;
+                    if (info->io_status < 0)
+                        goto cleanup;
                 } else {
                     /* ignore because we don't parse all options */
                 }
-- 
1.7.8.4


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]