Current qemu is able to give us detailed domain status (not just if it
is running or not) which we can translate into a status reason.
---
 src/qemu/qemu_monitor.c      |   66 +++++++++++++++++++++++++++++++++++++++--
 src/qemu/qemu_monitor.h      |   25 +++++++++++++++-
 src/qemu/qemu_monitor_json.c |   15 +++++++++-
 src/qemu/qemu_monitor_json.h |    4 ++-
 src/qemu/qemu_monitor_text.c |   20 ++++++++++++-
 src/qemu/qemu_monitor_text.h |    4 ++-
 src/qemu/qemu_process.c      |   15 ++++++----
 7 files changed, 134 insertions(+), 15 deletions(-)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index b4c43ae..6e84131 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -81,6 +81,12 @@ VIR_ENUM_IMPL(qemuMonitorMigrationStatus,
               QEMU_MONITOR_MIGRATION_STATUS_LAST,
               "inactive", "active", "completed", "failed", "cancelled")
 
+VIR_ENUM_IMPL(qemuMonitorVMStatus,
+              QEMU_MONITOR_VM_STATUS_LAST,
+              "debug", "inmigrate", "internal-error", "io-error", "paused",
+              "postmigrate", "prelaunch", "finish-migrate", "restore-vm",
+              "running", "save-vm", "shutdown", "watchdog")
+
 char *qemuMonitorEscapeArg(const char *in)
 {
     int len = 0;
@@ -1059,10 +1065,12 @@ qemuMonitorStopCPUs(qemuMonitorPtr mon)
 
 
 int
-qemuMonitorGetStatus(qemuMonitorPtr mon, bool *running)
+qemuMonitorGetStatus(qemuMonitorPtr mon,
+                     bool *running,
+                     virDomainPausedReason *reason)
 {
     int ret;
-    VIR_DEBUG("mon=%p, running=%p", mon, running);
+    VIR_DEBUG("mon=%p, running=%p, reason=%p", mon, running, reason);
 
     if (!mon || !running) {
         qemuReportError(VIR_ERR_INVALID_ARG, "%s",
@@ -1071,9 +1079,9 @@ qemuMonitorGetStatus(qemuMonitorPtr mon, bool *running)
     }
 
     if (mon->json)
-        ret = qemuMonitorJSONGetStatus(mon, running);
+        ret = qemuMonitorJSONGetStatus(mon, running, reason);
     else
-        ret = qemuMonitorTextGetStatus(mon, running);
+        ret = qemuMonitorTextGetStatus(mon, running, reason);
     return ret;
 }
 
@@ -2553,3 +2561,53 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon,
         ret = qemuMonitorTextBlockJob(mon, device, bandwidth, info, mode);
     return ret;
 }
+
+int qemuMonitorVMStatusToPausedReason(const char *status)
+{
+    int st;
+
+    if (!status)
+        return VIR_DOMAIN_PAUSED_UNKNOWN;
+
+    if ((st = qemuMonitorVMStatusTypeFromString(status)) < 0) {
+        VIR_WARN("Qemu reported unknown VM status: '%s'", status);
+        return VIR_DOMAIN_PAUSED_UNKNOWN;
+    }
+
+    switch ((qemuMonitorVMStatus) st) {
+    case QEMU_MONITOR_VM_STATUS_DEBUG:
+    case QEMU_MONITOR_VM_STATUS_INTERNAL_ERROR:
+    case QEMU_MONITOR_VM_STATUS_RESTORE_VM:
+        return VIR_DOMAIN_PAUSED_UNKNOWN;
+
+    case QEMU_MONITOR_VM_STATUS_INMIGRATE:
+    case QEMU_MONITOR_VM_STATUS_POSTMIGRATE:
+    case QEMU_MONITOR_VM_STATUS_FINISH_MIGRATE:
+        return VIR_DOMAIN_PAUSED_MIGRATION;
+
+    case QEMU_MONITOR_VM_STATUS_IO_ERROR:
+        return VIR_DOMAIN_PAUSED_IOERROR;
+
+    case QEMU_MONITOR_VM_STATUS_PAUSED:
+    case QEMU_MONITOR_VM_STATUS_PRELAUNCH:
+        return VIR_DOMAIN_PAUSED_USER;
+
+    case QEMU_MONITOR_VM_STATUS_RUNNING:
+        VIR_WARN("Qemu reports the guest is paused but status is 'running'");
+        return VIR_DOMAIN_PAUSED_UNKNOWN;
+
+    case QEMU_MONITOR_VM_STATUS_SAVE_VM:
+        return VIR_DOMAIN_PAUSED_SAVE;
+
+    case QEMU_MONITOR_VM_STATUS_SHUTDOWN:
+        return VIR_DOMAIN_PAUSED_SHUTTING_DOWN;
+
+    case QEMU_MONITOR_VM_STATUS_WATCHDOG:
+        return VIR_DOMAIN_PAUSED_WATCHDOG;
+
+    /* unreachable from this point on */
+    case QEMU_MONITOR_VM_STATUS_LAST:
+        ;
+    }
+    return VIR_DOMAIN_PAUSED_UNKNOWN;
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 477767f..a64c2c3 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -198,7 +198,30 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
 int qemuMonitorStartCPUs(qemuMonitorPtr mon,
                          virConnectPtr conn);
 int qemuMonitorStopCPUs(qemuMonitorPtr mon);
-int qemuMonitorGetStatus(qemuMonitorPtr mon, bool *running);
+
+typedef enum {
+    QEMU_MONITOR_VM_STATUS_DEBUG,
+    QEMU_MONITOR_VM_STATUS_INMIGRATE,
+    QEMU_MONITOR_VM_STATUS_INTERNAL_ERROR,
+    QEMU_MONITOR_VM_STATUS_IO_ERROR,
+    QEMU_MONITOR_VM_STATUS_PAUSED,
+    QEMU_MONITOR_VM_STATUS_POSTMIGRATE,
+    QEMU_MONITOR_VM_STATUS_PRELAUNCH,
+    QEMU_MONITOR_VM_STATUS_FINISH_MIGRATE,
+    QEMU_MONITOR_VM_STATUS_RESTORE_VM,
+    QEMU_MONITOR_VM_STATUS_RUNNING,
+    QEMU_MONITOR_VM_STATUS_SAVE_VM,
+    QEMU_MONITOR_VM_STATUS_SHUTDOWN,
+    QEMU_MONITOR_VM_STATUS_WATCHDOG,
+
+    QEMU_MONITOR_VM_STATUS_LAST
+} qemuMonitorVMStatus;
+VIR_ENUM_DECL(qemuMonitorVMStatus)
+int qemuMonitorVMStatusToPausedReason(const char *status);
+
+int qemuMonitorGetStatus(qemuMonitorPtr mon,
+                         bool *running,
+                         virDomainPausedReason *reason);
 
 int qemuMonitorSystemReset(qemuMonitorPtr mon);
 int qemuMonitorSystemPowerdown(qemuMonitorPtr mon);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index e38c2ed..b720617 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -896,13 +896,19 @@ qemuMonitorJSONStopCPUs(qemuMonitorPtr mon)
 
 
 int
-qemuMonitorJSONGetStatus(qemuMonitorPtr mon, bool *running)
+qemuMonitorJSONGetStatus(qemuMonitorPtr mon,
+                         bool *running,
+                         virDomainPausedReason *reason)
 {
     int ret;
+    const char *status;
     virJSONValuePtr cmd;
     virJSONValuePtr reply = NULL;
     virJSONValuePtr data;
 
+    if (reason)
+        *reason = VIR_DOMAIN_PAUSED_UNKNOWN;
+
     if (!(cmd = qemuMonitorJSONMakeCommand("query-status", NULL)))
         return -1;
 
@@ -928,6 +934,13 @@ qemuMonitorJSONGetStatus(qemuMonitorPtr mon, bool *running)
         goto cleanup;
     }
 
+    if ((status = virJSONValueObjectGetString(data, "status"))) {
+        if (!*running && reason)
+            *reason = qemuMonitorVMStatusToPausedReason(status);
+    } else if (!*running) {
+        VIR_DEBUG("query-status reply was missing status details");
+    }
+
     ret = 0;
 
 cleanup:
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 673444f..1a40716 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -46,7 +46,9 @@ int qemuMonitorJSONCheckHMP(qemuMonitorPtr mon);
 int qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
                              virConnectPtr conn);
 int qemuMonitorJSONStopCPUs(qemuMonitorPtr mon);
-int qemuMonitorJSONGetStatus(qemuMonitorPtr mon, bool *running);
+int qemuMonitorJSONGetStatus(qemuMonitorPtr mon,
+                             bool *running,
+                             virDomainPausedReason *reason);
 
 int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon);
 int qemuMonitorJSONSystemReset(qemuMonitorPtr mon);
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index cedf582..57e74a8 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -392,11 +392,16 @@ qemuMonitorTextStopCPUs(qemuMonitorPtr mon) {
 
 
 int
-qemuMonitorTextGetStatus(qemuMonitorPtr mon, bool *running)
+qemuMonitorTextGetStatus(qemuMonitorPtr mon,
+                         bool *running,
+                         virDomainPausedReason *reason)
 {
     char *reply;
     int ret = -1;
 
+    if (reason)
+        *reason = VIR_DOMAIN_PAUSED_UNKNOWN;
+
     if (qemuMonitorHMPCommand(mon, "info status", &reply) < 0) {
         qemuReportError(VIR_ERR_OPERATION_FAILED,
                         "%s", _("cannot get status info"));
@@ -406,6 +411,19 @@ qemuMonitorTextGetStatus(qemuMonitorPtr mon, bool *running)
     if (strstr(reply, "running")) {
         *running = true;
     } else if (strstr(reply, "paused")) {
+        char *status;
+
+        if ((status = strchr(reply, '('))) {
+            char *end = strchr(status, ')');
+            if (end)
+                *end = '\0';
+            else
+                status = NULL;
+        }
+        if (!status)
+            VIR_DEBUG("info status was missing status details");
+        else if (reason)
+            *reason = qemuMonitorVMStatusToPausedReason(status);
         *running = false;
     } else {
         qemuReportError(VIR_ERR_OPERATION_FAILED,
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index 4651a17..207001d 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -43,7 +43,9 @@ int qemuMonitorTextCommandWithFd(qemuMonitorPtr mon,
 int qemuMonitorTextStartCPUs(qemuMonitorPtr mon,
                              virConnectPtr conn);
 int qemuMonitorTextStopCPUs(qemuMonitorPtr mon);
-int qemuMonitorTextGetStatus(qemuMonitorPtr mon, bool *running);
+int qemuMonitorTextGetStatus(qemuMonitorPtr mon,
+                             bool *running,
+                             virDomainPausedReason *reason);
 
 int qemuMonitorTextSystemPowerdown(qemuMonitorPtr mon);
 int qemuMonitorTextSystemReset(qemuMonitorPtr mon);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index c8f22e2..21e6fbf 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -2321,11 +2321,12 @@ qemuProcessUpdateState(struct qemud_driver *driver, 
virDomainObjPtr vm)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
     virDomainState state;
+    virDomainPausedReason reason;
     bool running;
     int ret;
 
     qemuDomainObjEnterMonitorWithDriver(driver, vm);
-    ret = qemuMonitorGetStatus(priv->mon, &running);
+    ret = qemuMonitorGetStatus(priv->mon, &running, &reason);
     qemuDomainObjExitMonitorWithDriver(driver, vm);
 
     if (ret < 0 || !virDomainObjIsActive(vm))
@@ -2339,9 +2340,10 @@ qemuProcessUpdateState(struct qemud_driver *driver, 
virDomainObjPtr vm)
         virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                              VIR_DOMAIN_RUNNING_UNPAUSED);
     } else if (state == VIR_DOMAIN_RUNNING && !running) {
-        VIR_DEBUG("Domain %s was paused while its monitor was disconnected;"
-                  " changing state to paused", vm->def->name);
-        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_UNKNOWN);
+        VIR_DEBUG("Domain %s was paused (%s) while its monitor was"
+                  " disconnected; changing state to paused",
+                  vm->def->name, virDomainPausedReasonTypeToString(reason));
+        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, reason);
     } else if (state == VIR_DOMAIN_SHUTOFF && running) {
         VIR_DEBUG("Domain %s finished booting; changing state to running",
                   vm->def->name);
@@ -3470,6 +3472,7 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
     char *timestamp;
     qemuDomainObjPrivatePtr priv = vm->privateData;
     bool running = true;
+    virDomainPausedReason reason;
     virSecurityLabelPtr seclabel = NULL;
 
     VIR_DEBUG("Beginning VM attach process");
@@ -3599,7 +3602,7 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
         qemuDomainObjExitMonitorWithDriver(driver, vm);
         goto cleanup;
     }
-    if (qemuMonitorGetStatus(priv->mon, &running) < 0) {
+    if (qemuMonitorGetStatus(priv->mon, &running, &reason) < 0) {
         qemuDomainObjExitMonitorWithDriver(driver, vm);
         goto cleanup;
     }
@@ -3616,7 +3619,7 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
         virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                              VIR_DOMAIN_RUNNING_UNPAUSED);
     else
-        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_UNKNOWN);
+        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, reason);
 
     VIR_DEBUG("Writing domain status to disk");
     if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
-- 
1.7.6.1

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to