]> xenbits.xensource.com Git - libvirt.git/commitdiff
Allow destroying QEMU VM even if a job is active
authorDaniel P. Berrange <berrange@redhat.com>
Thu, 21 Apr 2011 15:19:06 +0000 (11:19 -0400)
committerDaniel P. Berrange <berrange@redhat.com>
Wed, 11 May 2011 08:35:15 +0000 (09:35 +0100)
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
src/qemu/qemu_process.c
src/qemu/qemu_process.h

index b8d9c9236f5898089429ab0ecb234d53c720b088..4f288d3ab20c7c9db2b26cdc726a3567ba8e37c6 100644 (file)
@@ -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;
 
index bd7c9323cb5a6b5c233f94caa81473fdc60a9b15..de728a2a08cef2e1305ace409d0412558144cdd6 100644 (file)
@@ -2363,6 +2363,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 != -ESRCH) {
+                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)
@@ -2430,13 +2470,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);
 
@@ -2448,7 +2481,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)) {
index f1ab599eeb4e496008ed9f539897c9c73b234ba1..d8afab0f189d25557f875d8d6cb2a30cb6fba7f2 100644 (file)
@@ -49,4 +49,6 @@ void qemuProcessStop(struct qemud_driver *driver,
                      virDomainObjPtr vm,
                      int migrated);
 
+void qemuProcessKill(virDomainObjPtr vm);
+
 #endif /* __QEMU_PROCESS_H__ */