The commit that prevents disk corruption on domain shutdown (96fc4784177ecb70357518fa863442455e45ad0e) causes regression with QEMU 0.14.* and 0.15.* because of a regression bug in QEMU that was fixed only recently in QEMU git. With affected QEMU binaries, domains cannot be shutdown properly and stay in a paused state. This patch tries to avoid this by sending SIGKILL to 0.1[45].* QEMU processes. Though we wait a bit more between sending SIGTERM and SIGKILL to reduce the possibility of virtual disk corruption. --- src/qemu/qemu_capabilities.c | 7 +++++++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_process.c | 19 +++++++++++++------ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 36f47a9..823c500 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -136,6 +136,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "pci-ohci", "usb-redir", "usb-hub", + "no-shutdown-bug", ); struct qemu_feature_flags { @@ -1049,6 +1050,12 @@ qemuCapsComputeCmdFlags(const char *help, if (version >= 13000) qemuCapsSet(flags, QEMU_CAPS_PCI_MULTIFUNCTION); + + /* QEMU version 0.14.* and 0.15.* are known not to handle SIGTERM + * properly when started with -no-shutdown + */ + if (version >= 14000 && version <= 15999) + qemuCapsSet(flags, QEMU_CAPS_NO_SHUTDOWN_BUG); } /* We parse the output of 'qemu -help' to get the QEMU diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 96b7a3b..53d5ace 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -110,6 +110,7 @@ enum qemuCapsFlags { QEMU_CAPS_PCI_OHCI = 71, /* -device pci-ohci */ QEMU_CAPS_USB_REDIR = 72, /* -device usb-redir */ QEMU_CAPS_USB_HUB = 73, /* -device usb-hub */ + QEMU_CAPS_NO_SHUTDOWN_BUG = 74, /* -no-shutdown doesn't exit on SIGTERM */ QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 3baaa19..3311699 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -434,6 +434,7 @@ qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED, virDomainObjPtr vm) { qemuDomainObjPrivatePtr priv = vm->privateData; + bool gracefully = true; VIR_DEBUG("vm=%p", vm); virDomainObjLock(vm); @@ -443,6 +444,12 @@ qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED, goto cleanup; } + if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NO_SHUTDOWN_BUG)) { + VIR_DEBUG("Emulator is likely affected by -no-shutdown bug;" + " we will not avoid sending SIGKILL to it"); + gracefully = false; + } + priv->gotShutdown = true; if (priv->fakeReboot) { virDomainObjRef(vm); @@ -452,12 +459,12 @@ qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED, qemuProcessFakeReboot, vm) < 0) { VIR_ERROR(_("Failed to create reboot thread, killing domain")); - qemuProcessKill(vm, true); + qemuProcessKill(vm, gracefully); if (virDomainObjUnref(vm) == 0) vm = NULL; } } else { - qemuProcessKill(vm, true); + qemuProcessKill(vm, gracefully); } cleanup: @@ -3227,15 +3234,15 @@ void qemuProcessKill(virDomainObjPtr vm, bool gracefully) } /* This loop sends SIGTERM, then waits a few iterations - * (1.6 seconds) to see if it dies. If still alive then + * (3 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++) { + for (i = 0 ; i < 23 ; i++) { int signum; if (i == 0) signum = SIGTERM; - else if (i == 8) + else if (i == 15) signum = SIGKILL; else signum = 0; /* Just check for existence */ @@ -3249,7 +3256,7 @@ void qemuProcessKill(virDomainObjPtr vm, bool gracefully) break; } - if (i == 0 && gracefully) + if (gracefully) break; usleep(200 * 1000); -- 1.7.6.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list