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