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

Michal Privoznik mprivozn at redhat.com
Thu Jan 26 14:06:16 UTC 2012


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




More information about the libvir-list mailing list