diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 87e762bb51..c12e657859 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6509,23 +6509,17 @@ qemuBuildPMCommandLine(virCommandPtr cmd, const virDomainDef *def, qemuDomainObjPrivatePtr priv) { - bool allowReboot = true; virQEMUCapsPtr qemuCaps = priv->qemuCaps; /* Only add -no-reboot option if each event destroys domain */ - if (def->onReboot == VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY && - def->onPoweroff == VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY && - (def->onCrash == VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY || - def->onCrash == VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY)) { - allowReboot = false; + if (priv->allowReboot == VIR_TRISTATE_BOOL_NO) virCommandAddArg(cmd, "-no-reboot"); - } /* If JSON monitor is enabled, we can receive an event * when QEMU stops. If we use no-shutdown, then we can * watch for this event and do a soft/warm reboot. */ - if (priv->monJSON && allowReboot && + if (priv->monJSON && priv->allowReboot == VIR_TRISTATE_BOOL_YES && virQEMUCapsGet(qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) { virCommandAddArg(cmd, "-no-shutdown"); } diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 05e8b96aa4..26f65e2d9b 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1767,6 +1767,7 @@ qemuDomainObjPrivateDataClear(qemuDomainObjPrivatePtr priv) priv->namespaces = NULL; priv->reconnectBlockjobs = VIR_TRISTATE_BOOL_ABSENT; + priv->allowReboot = VIR_TRISTATE_BOOL_ABSENT; } @@ -1876,6 +1877,16 @@ qemuDomainObjPrivateXMLFormatBlockjobs(virBufferPtr buf, } +static void +qemuDomainObjPrivateXMLFormatAllowReboot(virBufferPtr buf, + virTristateBool allowReboot) +{ + virBufferAsprintf(buf, "\n", + virTristateBoolTypeToString(allowReboot)); + +} + + static int qemuDomainObjPrivateXMLFormat(virBufferPtr buf, virDomainObjPtr vm) @@ -1998,6 +2009,8 @@ qemuDomainObjPrivateXMLFormat(virBufferPtr buf, if (priv->chardevStdioLogd) virBufferAddLit(buf, "\n"); + qemuDomainObjPrivateXMLFormatAllowReboot(buf, priv->allowReboot); + if (qemuDomainObjPrivateXMLFormatBlockjobs(buf, vm) < 0) return -1; @@ -2108,6 +2121,31 @@ qemuDomainObjPrivateXMLParseBlockjobs(qemuDomainObjPrivatePtr priv, } +static int +qemuDomainObjPrivateXMLParseAllowReboot(xmlXPathContextPtr ctxt, + virTristateBool *allowReboot) +{ + int ret = -1; + int val; + char *valStr; + + if ((valStr = virXPathString("string(./allowReboot/@value)", ctxt))) { + if ((val = virTristateBoolTypeFromString(valStr)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid allowReboot value '%s'"), valStr); + goto cleanup; + } + *allowReboot = val; + } + + ret = 0; + + cleanup: + VIR_FREE(valStr); + return ret; +} + + static int qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, virDomainObjPtr vm, @@ -2323,6 +2361,8 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, priv->chardevStdioLogd = virXPathBoolean("boolean(./chardevStdioLogd)", ctxt) == 1; + qemuDomainObjPrivateXMLParseAllowReboot(ctxt, &priv->allowReboot); + if (qemuDomainObjPrivateXMLParseBlockjobs(priv, ctxt) < 0) goto error; diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index a29dd76037..afe979d2ed 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -261,6 +261,7 @@ struct _qemuDomainObjPrivate { char *lockState; bool fakeReboot; + virTristateBool allowReboot; int jobs_queued; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 7f833e940b..66e81bbe51 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5309,6 +5309,26 @@ qemuProcessPrepareDomainStorage(virConnectPtr conn, } +static void +qemuProcessPrepareAllowReboot(virDomainObjPtr vm) +{ + virDomainDefPtr def = vm->def; + qemuDomainObjPrivatePtr priv = vm->privateData; + + if (priv->allowReboot != VIR_TRISTATE_BOOL_ABSENT) + return; + + if (def->onReboot == VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY && + def->onPoweroff == VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY && + (def->onCrash == VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY || + def->onCrash == VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY)) { + priv->allowReboot = VIR_TRISTATE_BOOL_NO; + } else { + priv->allowReboot = VIR_TRISTATE_BOOL_YES; + } +} + + /** * qemuProcessPrepareDomain: * @conn: connection object (for looking up storage volumes) @@ -5365,6 +5385,8 @@ qemuProcessPrepareDomain(virConnectPtr conn, priv->chardevStdioLogd = true; } + qemuProcessPrepareAllowReboot(vm); + /* * Normally PCI addresses are assigned in the virDomainCreate * or virDomainDefine methods. We might still need to assign @@ -6618,6 +6640,10 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED, priv->gotShutdown = false; + /* Attaching to running QEMU so we need to detect whether it was started + * with -no-reboot. */ + qemuProcessPrepareAllowReboot(vm); + /* * Normally PCI addresses are assigned in the virDomainCreate * or virDomainDefine methods. We might still need to assign @@ -6994,6 +7020,10 @@ qemuProcessReconnect(void *opaque) if (qemuDomainMasterKeyReadFile(priv) < 0) goto error; + /* If we are connecting to a guest started by old libvirt there is no + * allowReboot in status XML and we need to initialize it. */ + qemuProcessPrepareAllowReboot(obj); + VIR_DEBUG("Reconnect monitor to %p '%s'", obj, obj->def->name); /* XXX check PID liveliness & EXE path */ diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 14f5b58fe9..2185532a6c 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -109,7 +109,8 @@ static const char testStatusXMLPrefixBodyStatic[] = "\n" "\n" "\n" -"\n"; +"\n" +"\n"; static const char testStatusXMLSuffix[] = "\n";