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)
This commit is contained in:
Michal Privoznik 2012-06-15 18:00:13 +02:00 committed by Cole Robinson
parent 4cb2da8cd4
commit e8603e5f73
3 changed files with 60 additions and 5 deletions

View File

@ -107,6 +107,11 @@ struct _qemuAgent {
/* If anything went wrong, this will be fed back /* If anything went wrong, this will be fed back
* the next monitor msg */ * the next monitor msg */
virError lastError; 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 #if DEBUG_RAW_IO
@ -825,6 +830,13 @@ void qemuAgentClose(qemuAgentPtr mon)
VIR_FORCE_CLOSE(mon->fd); 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) if (qemuAgentUnref(mon) > 0)
qemuAgentUnlock(mon); qemuAgentUnlock(mon);
} }
@ -981,6 +993,7 @@ qemuAgentCommand(qemuAgentPtr mon,
int ret = -1; int ret = -1;
qemuAgentMessage msg; qemuAgentMessage msg;
char *cmdstr = NULL; char *cmdstr = NULL;
int await_event = mon->await_event;
*reply = NULL; *reply = NULL;
@ -1009,10 +1022,16 @@ qemuAgentCommand(qemuAgentPtr mon,
ret, msg.rxObject); ret, msg.rxObject);
if (ret == 0) { 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) { if (!msg.rxObject) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", if (await_event) {
_("Missing monitor reply object")); VIR_DEBUG("Woken up by event %d", await_event);
ret = -1; } else {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Missing monitor reply object"));
ret = -1;
}
} else { } else {
*reply = msg.rxObject; *reply = msg.rxObject;
} }
@ -1237,6 +1256,24 @@ error:
return NULL; 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_DECL(qemuAgentShutdownMode);
VIR_ENUM_IMPL(qemuAgentShutdownMode, VIR_ENUM_IMPL(qemuAgentShutdownMode,
@ -1256,9 +1293,10 @@ int qemuAgentShutdown(qemuAgentPtr mon,
if (!cmd) if (!cmd)
return -1; return -1;
mon->await_event = QEMU_AGENT_EVENT_SHUTDOWN;
ret = qemuAgentCommand(mon, cmd, &reply); ret = qemuAgentCommand(mon, cmd, &reply);
if (ret == 0) if (reply && ret == 0)
ret = qemuAgentCheckError(cmd, reply); ret = qemuAgentCheckError(cmd, reply);
virJSONValueFree(cmd); virJSONValueFree(cmd);
@ -1361,9 +1399,10 @@ qemuAgentSuspend(qemuAgentPtr mon,
if (!cmd) if (!cmd)
return -1; return -1;
mon->await_event = QEMU_AGENT_EVENT_SUSPEND;
ret = qemuAgentCommand(mon, cmd, &reply); ret = qemuAgentCommand(mon, cmd, &reply);
if (ret == 0) if (reply && ret == 0)
ret = qemuAgentCheckError(cmd, reply); ret = qemuAgentCheckError(cmd, reply);
virJSONValueFree(cmd); virJSONValueFree(cmd);

View File

@ -55,6 +55,15 @@ int qemuAgentUnref(qemuAgentPtr mon) ATTRIBUTE_RETURN_CHECK;
void qemuAgentClose(qemuAgentPtr mon); 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 { typedef enum {
QEMU_AGENT_SHUTDOWN_POWERDOWN, QEMU_AGENT_SHUTDOWN_POWERDOWN,
QEMU_AGENT_SHUTDOWN_REBOOT, QEMU_AGENT_SHUTDOWN_REBOOT,

View File

@ -663,6 +663,9 @@ qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
vm->def->name); vm->def->name);
} }
if (priv->agent)
qemuAgentNotifyEvent(priv->agent, QEMU_AGENT_EVENT_SHUTDOWN);
qemuProcessShutdownOrReboot(driver, vm); qemuProcessShutdownOrReboot(driver, vm);
unlock: unlock:
@ -1116,6 +1119,7 @@ qemuProcessHandlePMSuspend(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
event = virDomainEventPMSuspendNewFromObj(vm); event = virDomainEventPMSuspendNewFromObj(vm);
if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) { if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
qemuDomainObjPrivatePtr priv = vm->privateData;
VIR_DEBUG("Transitioned guest %s to pmsuspended state due to " VIR_DEBUG("Transitioned guest %s to pmsuspended state due to "
"QMP suspend event", vm->def->name); "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", VIR_WARN("Unable to save status on vm %s after suspend event",
vm->def->name); vm->def->name);
} }
if (priv->agent)
qemuAgentNotifyEvent(priv->agent, QEMU_AGENT_EVENT_SUSPEND);
} }
virDomainObjUnlock(vm); virDomainObjUnlock(vm);