[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH RFC 4/4] Wire up qemu agent for suspend



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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]