snapshot: better events when starting paused

There are two classes of management apps that track events - one
that only cares about on/off (and only needs to track EVENT_STARTED
and EVENT_STOPPED), and one that cares about paused/running (also
tracks EVENT_SUSPENDED/EVENT_RESUMED).  To keep both classes happy,
any transition that can go from inactive to paused must emit two
back-to-back events - one for started and one for suspended (since
later resuming of the domain will only send RESUMED, but the first
class isn't tracking that).

This also fixes a bug where virDomainCreateWithFlags with the
VIR_DOMAIN_START_PAUSED flag failed to start paused when restoring
from a managed save image.

* include/libvirt/libvirt.h.in (VIR_DOMAIN_EVENT_SUSPENDED_RESTORED)
(VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT)
(VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT): New sub-events.
* src/qemu/qemu_driver.c (qemuDomainRevertToSnapshot): Use them.
(qemuDomainSaveImageStartVM): Likewise, and add parameter.
(qemudDomainCreate, qemuDomainObjStart): Send suspended event when
starting paused.
(qemuDomainObjRestore): Add parameter.
(qemuDomainObjStart, qemuDomainRestoreFlags): Update callers.
* examples/domain-events/events-c/event-test.c
(eventDetailToString): Map new detail strings.
This commit is contained in:
Eric Blake 2011-08-05 16:05:50 -06:00
parent 4813b3f094
commit c1ff5dc63d
3 changed files with 90 additions and 19 deletions

View File

@ -87,19 +87,45 @@ static const char *eventDetailToString(int event, int detail) {
case VIR_DOMAIN_EVENT_STARTED_RESTORED: case VIR_DOMAIN_EVENT_STARTED_RESTORED:
ret = "Restored"; ret = "Restored";
break; break;
case VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT:
ret = "Snapshot";
break;
} }
break; break;
case VIR_DOMAIN_EVENT_SUSPENDED: case VIR_DOMAIN_EVENT_SUSPENDED:
if (detail == VIR_DOMAIN_EVENT_SUSPENDED_PAUSED) switch (detail) {
case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED:
ret = "Paused"; ret = "Paused";
else if (detail == VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED) break;
case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED:
ret = "Migrated"; ret = "Migrated";
break;
case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR:
ret = "I/O Error";
break;
case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG:
ret = "Watchdog";
break;
case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED:
ret = "Restored";
break;
case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT:
ret = "Snapshot";
break;
}
break; break;
case VIR_DOMAIN_EVENT_RESUMED: case VIR_DOMAIN_EVENT_RESUMED:
if (detail == VIR_DOMAIN_EVENT_RESUMED_UNPAUSED) switch (detail) {
case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED:
ret = "Unpaused"; ret = "Unpaused";
else if (detail == VIR_DOMAIN_EVENT_RESUMED_MIGRATED) break;
case VIR_DOMAIN_EVENT_RESUMED_MIGRATED:
ret = "Migrated"; ret = "Migrated";
break;
case VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT:
ret = "Snapshot";
break;
}
break; break;
case VIR_DOMAIN_EVENT_STOPPED: case VIR_DOMAIN_EVENT_STOPPED:
switch (detail) { switch (detail) {
@ -121,6 +147,9 @@ static const char *eventDetailToString(int event, int detail) {
case VIR_DOMAIN_EVENT_STOPPED_FAILED: case VIR_DOMAIN_EVENT_STOPPED_FAILED:
ret = "Failed"; ret = "Failed";
break; break;
case VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT:
ret = "Snapshot";
break;
} }
break; break;
} }

View File

@ -116,8 +116,7 @@ typedef enum {
VIR_DOMAIN_PAUSED_DUMP = 4, /* paused for offline core dump */ VIR_DOMAIN_PAUSED_DUMP = 4, /* paused for offline core dump */
VIR_DOMAIN_PAUSED_IOERROR = 5, /* paused due to a disk I/O error */ VIR_DOMAIN_PAUSED_IOERROR = 5, /* paused due to a disk I/O error */
VIR_DOMAIN_PAUSED_WATCHDOG = 6, /* paused due to a watchdog event */ VIR_DOMAIN_PAUSED_WATCHDOG = 6, /* paused due to a watchdog event */
VIR_DOMAIN_PAUSED_FROM_SNAPSHOT = 7, /* restored from a snapshot which was VIR_DOMAIN_PAUSED_FROM_SNAPSHOT = 7, /* paused after restoring from snapshot */
* taken while domain was paused */
} virDomainPausedReason; } virDomainPausedReason;
typedef enum { typedef enum {
@ -2031,6 +2030,8 @@ typedef enum {
VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED = 1, /* Suspended for offline migration */ VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED = 1, /* Suspended for offline migration */
VIR_DOMAIN_EVENT_SUSPENDED_IOERROR = 2, /* Suspended due to a disk I/O error */ VIR_DOMAIN_EVENT_SUSPENDED_IOERROR = 2, /* Suspended due to a disk I/O error */
VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG = 3, /* Suspended due to a watchdog firing */ VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG = 3, /* Suspended due to a watchdog firing */
VIR_DOMAIN_EVENT_SUSPENDED_RESTORED = 4, /* Restored from paused state file */
VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT = 5, /* Restored from paused snapshot */
} virDomainEventSuspendedDetailType; } virDomainEventSuspendedDetailType;
/** /**
@ -2041,6 +2042,7 @@ typedef enum {
typedef enum { typedef enum {
VIR_DOMAIN_EVENT_RESUMED_UNPAUSED = 0, /* Normal resume due to admin unpause */ VIR_DOMAIN_EVENT_RESUMED_UNPAUSED = 0, /* Normal resume due to admin unpause */
VIR_DOMAIN_EVENT_RESUMED_MIGRATED = 1, /* Resumed for completion of migration */ VIR_DOMAIN_EVENT_RESUMED_MIGRATED = 1, /* Resumed for completion of migration */
VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT = 2, /* Resumed from snapshot */
} virDomainEventResumedDetailType; } virDomainEventResumedDetailType;
/** /**

View File

@ -1269,6 +1269,7 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
virDomainObjPtr vm = NULL; virDomainObjPtr vm = NULL;
virDomainPtr dom = NULL; virDomainPtr dom = NULL;
virDomainEventPtr event = NULL; virDomainEventPtr event = NULL;
virDomainEventPtr event2 = NULL;
virCheckFlags(VIR_DOMAIN_START_PAUSED | virCheckFlags(VIR_DOMAIN_START_PAUSED |
VIR_DOMAIN_START_AUTODESTROY, NULL); VIR_DOMAIN_START_AUTODESTROY, NULL);
@ -1316,6 +1317,16 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
event = virDomainEventNewFromObj(vm, event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED, VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_BOOTED); VIR_DOMAIN_EVENT_STARTED_BOOTED);
if (event && (flags & VIR_DOMAIN_START_PAUSED)) {
/* There are two classes of event-watching clients - those
* that only care about on/off (and must see a started event
* no matter what, but don't care about suspend events), and
* those that also care about running/paused. To satisfy both
* client types, we have to send two events. */
event2 = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_SUSPENDED,
VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
}
virDomainAuditStart(vm, "booted", true); virDomainAuditStart(vm, "booted", true);
dom = virGetDomain(conn, vm->def->name, vm->def->uuid); dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
@ -1329,8 +1340,11 @@ cleanup:
virDomainDefFree(def); virDomainDefFree(def);
if (vm) if (vm)
virDomainObjUnlock(vm); virDomainObjUnlock(vm);
if (event) if (event) {
qemuDomainEventQueue(driver, event); qemuDomainEventQueue(driver, event);
if (event2)
qemuDomainEventQueue(driver, event2);
}
qemuDriverUnlock(driver); qemuDriverUnlock(driver);
return dom; return dom;
} }
@ -3934,7 +3948,8 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
virDomainObjPtr vm, virDomainObjPtr vm,
int *fd, int *fd,
const struct qemud_save_header *header, const struct qemud_save_header *header,
const char *path) const char *path,
bool start_paused)
{ {
int ret = -1; int ret = -1;
virDomainEventPtr event; virDomainEventPtr event;
@ -4005,8 +4020,8 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
qemuDomainEventQueue(driver, event); qemuDomainEventQueue(driver, event);
/* If it was running before, resume it now. */ /* If it was running before, resume it now unless caller requested pause. */
if (header->was_running) { if (header->was_running && !start_paused) {
if (qemuProcessStartCPUs(driver, vm, conn, if (qemuProcessStartCPUs(driver, vm, conn,
VIR_DOMAIN_RUNNING_RESTORED, VIR_DOMAIN_RUNNING_RESTORED,
QEMU_ASYNC_JOB_NONE) < 0) { QEMU_ASYNC_JOB_NONE) < 0) {
@ -4019,6 +4034,14 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
VIR_WARN("Failed to save status on vm %s", vm->def->name); VIR_WARN("Failed to save status on vm %s", vm->def->name);
goto out; goto out;
} }
} else {
int detail = (start_paused ? VIR_DOMAIN_EVENT_SUSPENDED_PAUSED :
VIR_DOMAIN_EVENT_SUSPENDED_RESTORED);
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_SUSPENDED,
detail);
if (event)
qemuDomainEventQueue(driver, event);
} }
ret = 0; ret = 0;
@ -4070,7 +4093,8 @@ qemuDomainRestoreFlags(virConnectPtr conn,
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0) if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup; goto cleanup;
ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path); ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
false);
if (virFileDirectFdClose(directFd) < 0) if (virFileDirectFdClose(directFd) < 0)
VIR_WARN("Failed to close %s", path); VIR_WARN("Failed to close %s", path);
@ -4197,6 +4221,7 @@ qemuDomainObjRestore(virConnectPtr conn,
struct qemud_driver *driver, struct qemud_driver *driver,
virDomainObjPtr vm, virDomainObjPtr vm,
const char *path, const char *path,
bool start_paused,
bool bypass_cache) bool bypass_cache)
{ {
virDomainDefPtr def = NULL; virDomainDefPtr def = NULL;
@ -4230,7 +4255,8 @@ qemuDomainObjRestore(virConnectPtr conn,
virDomainObjAssignDef(vm, def, true); virDomainObjAssignDef(vm, def, true);
def = NULL; def = NULL;
ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path); ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
start_paused);
if (virFileDirectFdClose(directFd) < 0) if (virFileDirectFdClose(directFd) < 0)
VIR_WARN("Failed to close %s", path); VIR_WARN("Failed to close %s", path);
@ -4518,7 +4544,7 @@ qemuDomainObjStart(virConnectPtr conn,
} }
} else { } else {
ret = qemuDomainObjRestore(conn, driver, vm, managed_save, ret = qemuDomainObjRestore(conn, driver, vm, managed_save,
bypass_cache); start_paused, bypass_cache);
if (ret == 0 && unlink(managed_save) < 0) if (ret == 0 && unlink(managed_save) < 0)
VIR_WARN("Failed to remove the managed state %s", managed_save); VIR_WARN("Failed to remove the managed state %s", managed_save);
@ -4537,8 +4563,16 @@ qemuDomainObjStart(virConnectPtr conn,
virDomainEventNewFromObj(vm, virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED, VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_BOOTED); VIR_DOMAIN_EVENT_STARTED_BOOTED);
if (event) if (event) {
qemuDomainEventQueue(driver, event); qemuDomainEventQueue(driver, event);
if (start_paused) {
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_SUSPENDED,
VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
if (event)
qemuDomainEventQueue(driver, event);
}
}
} }
cleanup: cleanup:
@ -8813,6 +8847,7 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
virDomainSnapshotObjPtr snap = NULL; virDomainSnapshotObjPtr snap = NULL;
char uuidstr[VIR_UUID_STRING_BUFLEN]; char uuidstr[VIR_UUID_STRING_BUFLEN];
virDomainEventPtr event = NULL; virDomainEventPtr event = NULL;
virDomainEventPtr event2 = NULL;
qemuDomainObjPrivatePtr priv; qemuDomainObjPrivatePtr priv;
int rc; int rc;
@ -8869,6 +8904,9 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
goto endjob; goto endjob;
} }
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
if (snap->def->state == VIR_DOMAIN_PAUSED) { if (snap->def->state == VIR_DOMAIN_PAUSED) {
/* qemu unconditionally starts the domain running again after /* qemu unconditionally starts the domain running again after
* loadvm, so let's pause it to keep consistency * loadvm, so let's pause it to keep consistency
@ -8879,14 +8917,13 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
QEMU_ASYNC_JOB_NONE); QEMU_ASYNC_JOB_NONE);
if (rc < 0) if (rc < 0)
goto endjob; goto endjob;
event2 = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_SUSPENDED,
VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
} else { } else {
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
VIR_DOMAIN_RUNNING_FROM_SNAPSHOT); VIR_DOMAIN_RUNNING_FROM_SNAPSHOT);
} }
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
} else { } else {
/* qemu is a little funny with running guests and the restoration /* qemu is a little funny with running guests and the restoration
* of snapshots. If the snapshot was taken online, * of snapshots. If the snapshot was taken online,
@ -8929,8 +8966,11 @@ cleanup:
} else if (snap) { } else if (snap) {
snap->def->current = false; snap->def->current = false;
} }
if (event) if (event) {
qemuDomainEventQueue(driver, event); qemuDomainEventQueue(driver, event);
if (event2)
qemuDomainEventQueue(driver, event2);
}
if (vm) if (vm)
virDomainObjUnlock(vm); virDomainObjUnlock(vm);
qemuDriverUnlock(driver); qemuDriverUnlock(driver);