This allows guests to enter S4 ACPI state aka hibernation by using guest agent. With no flag given, we keep consistent and enter only S3 state (sleep). --- src/qemu/qemu_driver.c | 57 +++++++++++++++++++++++++++++++++++++++++------ tools/virsh.c | 30 +++++++++++++++++++++--- 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ab69dca..fba9aeb 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1388,7 +1388,10 @@ cleanup: } -static int qemudDomainSuspend(virDomainPtr dom) { +static int +qemudDomainSuspendFlags(virDomainPtr dom, + unsigned int flags) +{ struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm; int ret = -1; @@ -1397,6 +1400,15 @@ static int qemudDomainSuspend(virDomainPtr dom) { virDomainPausedReason reason; int eventDetail; + virCheckFlags(VIR_DOMAIN_SUSPEND_SLEEP | + VIR_DOMAIN_SUSPEND_HIBERNATE, -1); + + if ((flags & VIR_DOMAIN_SUSPEND_SLEEP) && + (flags & VIR_DOMAIN_SUSPEND_HIBERNATE)) { + qemuReportError(VIR_ERR_INVALID_ARG, "%s", _("seriosly?")); + return -1; + } + qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -1431,16 +1443,39 @@ static int qemudDomainSuspend(virDomainPtr dom) { "%s", _("domain is not running")); goto endjob; } - if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) { - if (qemuProcessStopCPUs(driver, vm, reason, QEMU_ASYNC_JOB_NONE) < 0) { + + if (flags & VIR_DOMAIN_SUSPEND_SLEEP) { + if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) { + if (qemuProcessStopCPUs(driver, vm, reason, QEMU_ASYNC_JOB_NONE) < 0) { + goto endjob; + } + event = virDomainEventNewFromObj(vm, + VIR_DOMAIN_EVENT_SUSPENDED, + eventDetail); + } + if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) + goto endjob; + } else if (flags & VIR_DOMAIN_SUSPEND_HIBERNATE) { + if (priv->agentError) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("QEMU guest agent is not " + "available due to an error")); goto endjob; } - event = virDomainEventNewFromObj(vm, - VIR_DOMAIN_EVENT_SUSPENDED, - eventDetail); + if (!priv->agent) { + qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("QEMU guest agent is not configured")); + goto endjob; + } + + qemuDomainObjEnterAgent(driver, vm); + ret = qemuAgentSuspend(priv->agent, QEMU_AGENT_SUSPEND_HIBERNATE); + qemuDomainObjExitAgent(driver, vm); + + if (ret < 0) + goto endjob; } - if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) - goto endjob; + ret = 0; endjob: @@ -1457,6 +1492,11 @@ cleanup: return ret; } +static int +qemudDomainSuspend(virDomainPtr dom) +{ + return qemudDomainSuspendFlags(dom, 0); +} static int qemudDomainResume(virDomainPtr dom) { struct qemud_driver *driver = dom->conn->privateData; @@ -11760,6 +11800,7 @@ static virDriver qemuDriver = { .domainLookupByUUID = qemudDomainLookupByUUID, /* 0.2.0 */ .domainLookupByName = qemudDomainLookupByName, /* 0.2.0 */ .domainSuspend = qemudDomainSuspend, /* 0.2.0 */ + .domainSuspendFlags = qemudDomainSuspendFlags, /* 0.9.10 */ .domainResume = qemudDomainResume, /* 0.2.0 */ .domainShutdown = qemuDomainShutdown, /* 0.2.0 */ .domainShutdownFlags = qemuDomainShutdownFlags, /* 0.9.10 */ diff --git a/tools/virsh.c b/tools/virsh.c index 74655c2..99b2ca9 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2142,6 +2142,7 @@ static const vshCmdInfo info_suspend[] = { static const vshCmdOptDef opts_suspend[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"mode", VSH_OT_STRING, VSH_OFLAG_NONE, N_("state to enter: sleep|hibernate")}, {NULL, 0, 0, NULL} }; @@ -2150,7 +2151,9 @@ cmdSuspend(vshControl *ctl, const vshCmd *cmd) { virDomainPtr dom; const char *name; + const char *mode; bool ret = true; + unsigned int flags = 0; if (!vshConnectionUsability(ctl, ctl->conn)) return false; @@ -2158,12 +2161,31 @@ cmdSuspend(vshControl *ctl, const vshCmd *cmd) if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) return false; - if (virDomainSuspend(dom) == 0) { + if (vshCommandOptString(cmd, "mode", &mode) < 0) { + vshError(ctl, "%s", _("Invalid type")); + return false; + } + + if (mode) { + if (STREQ(mode, "sleep")) { + flags |= VIR_DOMAIN_SUSPEND_SLEEP; + } else if (STREQ(mode, "hibernate")) { + flags |= VIR_DOMAIN_SUSPEND_HIBERNATE; + } else { + vshError(ctl, _("Unknown mode %s value, expecting 'sleep' or 'hibernate'"), mode); + return false; + } + } + + if (flags) + ret = virDomainSuspendFlags(dom, flags) == 0; + else + ret = virDomainSuspend(dom) == 0; + + if (ret) vshPrint(ctl, _("Domain %s suspended\n"), name); - } else { + else vshError(ctl, _("Failed to suspend domain %s"), name); - ret = false; - } virDomainFree(dom); return ret; -- 1.7.3.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list