[libvirt] [PATCH] qemu: Finish domain shutdown on reconnect

Jiri Denemark jdenemar at redhat.com
Tue Sep 27 13:04:02 UTC 2011


If a domain started with -no-shutdown shuts down while libvirtd is not
running, it will be seen as paused when libvirtd reconnects to it. Use
the paused reason to detect if a domain was stopped because of shutdown
and finish the process just as if a SHUTDOWN event is delivered from
qemu.
---
 src/qemu/qemu_process.c |   50 ++++++++++++++++++++++++++++++++--------------
 1 files changed, 35 insertions(+), 15 deletions(-)

diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 21e6fbf..106a47c 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -429,18 +429,15 @@ cleanup:
 }
 
 
-static int
-qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                          virDomainObjPtr vm)
+static void
+qemuProcessShutdownOrReboot(virDomainObjPtr vm)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
-    VIR_DEBUG("vm=%p", vm);
 
-    virDomainObjLock(vm);
     if (priv->gotShutdown) {
         VIR_DEBUG("Ignoring repeated SHUTDOWN event from domain %s",
                   vm->def->name);
-        goto cleanup;
+        return;
     }
 
     priv->gotShutdown = true;
@@ -454,16 +451,23 @@ qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                             vm) < 0) {
             VIR_ERROR(_("Failed to create reboot thread, killing domain"));
             qemuProcessKill(vm, true);
-            if (virDomainObjUnref(vm) == 0)
-                vm = NULL;
+            /* Safe to ignore value since ref count was incremented above */
+            ignore_value(virDomainObjUnref(vm));
         }
     } else {
         qemuProcessKill(vm, true);
     }
+}
 
-cleanup:
-    if (vm)
-        virDomainObjUnlock(vm);
+static int
+qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+                          virDomainObjPtr vm)
+{
+    VIR_DEBUG("vm=%p", vm);
+
+    virDomainObjLock(vm);
+    qemuProcessShutdownOrReboot(vm);
+    virDomainObjUnlock(vm);
     return 0;
 }
 
@@ -2572,6 +2576,8 @@ qemuProcessReconnect(void *opaque)
     qemuDomainObjPrivatePtr priv;
     virConnectPtr conn = data->conn;
     struct qemuDomainJobObj oldjob;
+    int state;
+    int reason;
 
     memcpy(&oldjob, &data->oldjob, sizeof(oldjob));
 
@@ -2603,7 +2609,8 @@ qemuProcessReconnect(void *opaque)
     if (qemuProcessUpdateState(driver, obj) < 0)
         goto error;
 
-    if (virDomainObjGetState(obj, NULL) == VIR_DOMAIN_SHUTOFF) {
+    state = virDomainObjGetState(obj, &reason);
+    if (state == VIR_DOMAIN_SHUTOFF) {
         VIR_DEBUG("Domain '%s' wasn't fully started yet, killing it",
                   obj->def->name);
         goto error;
@@ -2618,6 +2625,18 @@ qemuProcessReconnect(void *opaque)
                                    &priv->qemuCaps) < 0)
         goto error;
 
+    /* In case the domain was paused for shutdown while we were not running,
+     * we need to finish the shutdown process. And we need to do it after
+     * we have qemuCaps filled in.
+     */
+    if (state == VIR_DOMAIN_PAUSED
+        && reason == VIR_DOMAIN_PAUSED_SHUTTING_DOWN) {
+        VIR_DEBUG("Domain %s shut down while we were not running;"
+                  " finishing shutdown sequence", obj->def->name);
+        qemuProcessShutdownOrReboot(obj);
+        goto endjob;
+    }
+
     if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
         priv->persistentAddrs = 1;
 
@@ -2647,12 +2666,13 @@ qemuProcessReconnect(void *opaque)
     if (obj->def->id >= driver->nextvmid)
         driver->nextvmid = obj->def->id + 1;
 
-    if (virDomainObjUnref(obj) > 0)
-        virDomainObjUnlock(obj);
-
+endjob:
     if (qemuDomainObjEndJob(driver, obj) == 0)
         obj = NULL;
 
+    if (obj && virDomainObjUnref(obj) > 0)
+        virDomainObjUnlock(obj);
+
     qemuDriverUnlock(driver);
 
     virConnectClose(conn);
-- 
1.7.6.1




More information about the libvir-list mailing list