]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu_agent: Wait for events instead of agent response
authorMichal Privoznik <mprivozn@redhat.com>
Fri, 15 Jun 2012 16:00:13 +0000 (18:00 +0200)
committerCole Robinson <crobinso@redhat.com>
Sun, 12 Aug 2012 22:35:01 +0000 (18:35 -0400)
With latest changes to qemu-ga success on some commands is not reported
anymore, e.g. guest-shutdown or guest-suspend-*. However, errors are
still being reported. Therefore, we need to find different source of
indication if operation was successful. Events.
(cherry picked from commit d97a234c62d272eb140c836cb93d750a4dec3354)

src/qemu/qemu_agent.c
src/qemu/qemu_agent.h
src/qemu/qemu_process.c

index bc4ceff08d1108767d49d9eec57a0696cdb6cddb..553d98284a6377b1812c0b000dac0b377d1296c2 100644 (file)
@@ -107,6 +107,11 @@ struct _qemuAgent {
     /* If anything went wrong, this will be fed back
      * the next monitor msg */
     virError lastError;
+
+    /* Some guest agent commands don't return anything
+     * but fire up an event on qemu monitor instead.
+     * Take that as indication of successful completion */
+    qemuAgentEvent await_event;
 };
 
 #if DEBUG_RAW_IO
@@ -825,6 +830,13 @@ void qemuAgentClose(qemuAgentPtr mon)
         VIR_FORCE_CLOSE(mon->fd);
     }
 
+    /* If there is somebody waiting for a message
+     * wake him up. No message will arrive anyway. */
+    if (mon->msg && !mon->msg->finished) {
+        mon->msg->finished = 1;
+        virCondSignal(&mon->notify);
+    }
+
     if (qemuAgentUnref(mon) > 0)
         qemuAgentUnlock(mon);
 }
@@ -981,6 +993,7 @@ qemuAgentCommand(qemuAgentPtr mon,
     int ret = -1;
     qemuAgentMessage msg;
     char *cmdstr = NULL;
+    int await_event = mon->await_event;
 
     *reply = NULL;
 
@@ -1009,10 +1022,16 @@ qemuAgentCommand(qemuAgentPtr mon,
               ret, msg.rxObject);
 
     if (ret == 0) {
+        /* If we haven't obtained any reply but we wait for an
+         * event, then don't report this as error */
         if (!msg.rxObject) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                            _("Missing monitor reply object"));
-            ret = -1;
+            if (await_event) {
+                VIR_DEBUG("Woken up by event %d", await_event);
+            } else {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                _("Missing monitor reply object"));
+                ret = -1;
+            }
         } else {
             *reply = msg.rxObject;
         }
@@ -1237,6 +1256,24 @@ error:
     return NULL;
 }
 
+void qemuAgentNotifyEvent(qemuAgentPtr mon,
+                          qemuAgentEvent event)
+{
+    VIR_DEBUG("mon=%p event=%d", mon, event);
+    if (mon->await_event == event) {
+        VIR_DEBUG("Waking up a tragedian");
+        mon->await_event = QEMU_AGENT_EVENT_NONE;
+        /* somebody waiting for this event, wake him up. */
+        if (mon->msg && !mon->msg->finished) {
+            mon->msg->finished = 1;
+            virCondSignal(&mon->notify);
+        }
+    } else {
+        /* shouldn't happen but one never knows */
+        VIR_WARN("Received unexpected event %d", event);
+    }
+}
+
 VIR_ENUM_DECL(qemuAgentShutdownMode);
 
 VIR_ENUM_IMPL(qemuAgentShutdownMode,
@@ -1256,9 +1293,10 @@ int qemuAgentShutdown(qemuAgentPtr mon,
     if (!cmd)
         return -1;
 
+    mon->await_event = QEMU_AGENT_EVENT_SHUTDOWN;
     ret = qemuAgentCommand(mon, cmd, &reply);
 
-    if (ret == 0)
+    if (reply && ret == 0)
         ret = qemuAgentCheckError(cmd, reply);
 
     virJSONValueFree(cmd);
@@ -1361,9 +1399,10 @@ qemuAgentSuspend(qemuAgentPtr mon,
     if (!cmd)
         return -1;
 
+    mon->await_event = QEMU_AGENT_EVENT_SUSPEND;
     ret = qemuAgentCommand(mon, cmd, &reply);
 
-    if (ret == 0)
+    if (reply && ret == 0)
         ret = qemuAgentCheckError(cmd, reply);
 
     virJSONValueFree(cmd);
index 98c23b0e21cfbab420441498019407677d4220e4..0816d909017abe811e57721808ca3f4d64d1e66b 100644 (file)
@@ -55,6 +55,15 @@ int qemuAgentUnref(qemuAgentPtr mon) ATTRIBUTE_RETURN_CHECK;
 
 void qemuAgentClose(qemuAgentPtr mon);
 
+typedef enum {
+    QEMU_AGENT_EVENT_NONE = 0,
+    QEMU_AGENT_EVENT_SHUTDOWN,
+    QEMU_AGENT_EVENT_SUSPEND
+} qemuAgentEvent;
+
+void qemuAgentNotifyEvent(qemuAgentPtr mon,
+                          qemuAgentEvent event);
+
 typedef enum {
     QEMU_AGENT_SHUTDOWN_POWERDOWN,
     QEMU_AGENT_SHUTDOWN_REBOOT,
index bc12215e83d97ca3bc7d10310694a2e0f1312e7c..9a8667665c49fae0aa3e6cbe618d7028f9a12dbc 100644 (file)
@@ -663,6 +663,9 @@ qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                  vm->def->name);
     }
 
+    if (priv->agent)
+        qemuAgentNotifyEvent(priv->agent, QEMU_AGENT_EVENT_SHUTDOWN);
+
     qemuProcessShutdownOrReboot(driver, vm);
 
 unlock:
@@ -1116,6 +1119,7 @@ qemuProcessHandlePMSuspend(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     event = virDomainEventPMSuspendNewFromObj(vm);
 
     if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
+        qemuDomainObjPrivatePtr priv = vm->privateData;
         VIR_DEBUG("Transitioned guest %s to pmsuspended state due to "
                   "QMP suspend event", vm->def->name);
 
@@ -1126,6 +1130,9 @@ qemuProcessHandlePMSuspend(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
             VIR_WARN("Unable to save status on vm %s after suspend event",
                      vm->def->name);
         }
+
+        if (priv->agent)
+            qemuAgentNotifyEvent(priv->agent, QEMU_AGENT_EVENT_SUSPEND);
     }
 
     virDomainObjUnlock(vm);