From e8603e5f73646b4c6ce894fc5369ad8b2a6a557e Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Fri, 15 Jun 2012 18:00:13 +0200 Subject: [PATCH] qemu_agent: Wait for events instead of agent response 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 | 49 ++++++++++++++++++++++++++++++++++++----- src/qemu/qemu_agent.h | 9 ++++++++ src/qemu/qemu_process.c | 7 ++++++ 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index bc4ceff08d..553d98284a 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -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); diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h index 98c23b0e21..0816d90901 100644 --- a/src/qemu/qemu_agent.h +++ b/src/qemu/qemu_agent.h @@ -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, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index bc12215e83..9a8667665c 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -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);