mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
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:
parent
4813b3f094
commit
c1ff5dc63d
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user