[libvirt] [PATCH v2] Allow destroying QEMU VM even if a job is active

Daniel P. Berrange berrange at redhat.com
Mon May 9 16:58:42 UTC 2011


Introduce a virProcessKill function that can be safely called
even when the job mutex is held. This allows virDomainDestroy
to kill any VM even if it is asleep in a monitor job. The PID
will die and the thread asleep on the monitor will then wake
up releasing the job mutex.

* src/qemu/qemu_driver.c: Kill process before using qemuProcessStop
  to ensure job is released
* src/qemu/qemu_process.c: Add virProcessKill for killing off
  QEMU processes
---
 src/qemu/qemu_driver.c  |    7 ++++++
 src/qemu/qemu_process.c |   49 +++++++++++++++++++++++++++++++++++++++-------
 src/qemu/qemu_process.h |    2 +
 3 files changed, 50 insertions(+), 8 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b3f9e00..e12dfd8 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1482,6 +1482,13 @@ static int qemudDomainDestroy(virDomainPtr dom) {
         goto cleanup;
     }
 
+    /* Although qemuProcessStop does this already, there may
+     * be an outstanding job active. We want to make sure we
+     * can kill the process even if a job is active. Killing
+     * it now means the job will be released
+     */
+    qemuProcessKill(vm);
+
     if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
         goto cleanup;
 
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 4c2bb84..285d1e8 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -2369,6 +2369,46 @@ cleanup:
 }
 
 
+void qemuProcessKill(virDomainObjPtr vm)
+{
+    int i;
+    int rc;
+    VIR_DEBUG("vm=%s pid=%d", vm->def->name, vm->pid);
+
+    if (!virDomainObjIsActive(vm)) {
+        VIR_DEBUG("VM '%s' not active", vm->def->name);
+        return;
+    }
+
+    /* This loop sends SIGTERM, then waits a few iterations
+     * (1.6 seconds) to see if it dies. If still alive then
+     * it does SIGKILL, and waits a few more iterations (1.6
+     * seconds more) to confirm that it has really gone.
+     */
+    for (i = 0 ; i < 15 ; i++) {
+        int signum;
+        if (i == 0)
+            signum = SIGTERM;
+        else if (i == 8)
+            signum = SIGKILL;
+        else
+            signum = 0; /* Just check for existence */
+
+        rc = virKillProcess(vm->pid, signum);
+        if (rc < 0) {
+            if (rc != -ERSCH) {
+                char ebuf[1024];
+                VIR_WARN("Failed to kill process %d %s",
+                         vm->pid, virStrerror(errno, ebuf, sizeof ebuf));
+            }
+            break;
+        }
+
+        usleep(200 * 1000);
+    }
+}
+
+
 void qemuProcessStop(struct qemud_driver *driver,
                      virDomainObjPtr vm,
                      int migrated)
@@ -2436,13 +2476,6 @@ void qemuProcessStop(struct qemud_driver *driver,
         }
     }
 
-    /* This will safely handle a non-running guest with pid=0 or pid=-1*/
-    if (virKillProcess(vm->pid, 0) == 0 &&
-        virKillProcess(vm->pid, SIGTERM) < 0)
-        virReportSystemError(errno,
-                             _("Failed to send SIGTERM to %s (%d)"),
-                             vm->def->name, vm->pid);
-
     if (priv->mon)
         qemuMonitorClose(priv->mon);
 
@@ -2454,7 +2487,7 @@ void qemuProcessStop(struct qemud_driver *driver,
     }
 
     /* shut it off for sure */
-    virKillProcess(vm->pid, SIGKILL);
+    qemuProcessKill(vm);
 
     /* now that we know it's stopped call the hook if present */
     if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h
index f1ab599..d8afab0 100644
--- a/src/qemu/qemu_process.h
+++ b/src/qemu/qemu_process.h
@@ -49,4 +49,6 @@ void qemuProcessStop(struct qemud_driver *driver,
                      virDomainObjPtr vm,
                      int migrated);
 
+void qemuProcessKill(virDomainObjPtr vm);
+
 #endif /* __QEMU_PROCESS_H__ */
-- 
1.7.4.4




More information about the libvir-list mailing list