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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list