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_WATCHDOG = 6, /* paused due to a watchdog event */
- VIR_DOMAIN_PAUSED_FROM_SNAPSHOT = 7, /* restored from a snapshot which was
- * taken while domain was paused */
+ VIR_DOMAIN_PAUSED_FROM_SNAPSHOT = 7, /* paused after restoring from snapshot */
} virDomainPausedReason;
typedef enum {
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_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;
/**
typedef enum {
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_FROM_SNAPSHOT = 2, /* Resumed from snapshot */
} virDomainEventResumedDetailType;
/**
virDomainObjPtr vm = NULL;
virDomainPtr dom = NULL;
virDomainEventPtr event = NULL;
+ virDomainEventPtr event2 = NULL;
virCheckFlags(VIR_DOMAIN_START_PAUSED |
VIR_DOMAIN_START_AUTODESTROY, NULL);
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
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);
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
virDomainDefFree(def);
if (vm)
virDomainObjUnlock(vm);
- if (event)
+ if (event) {
qemuDomainEventQueue(driver, event);
+ if (event2)
+ qemuDomainEventQueue(driver, event2);
+ }
qemuDriverUnlock(driver);
return dom;
}
virDomainObjPtr vm,
int *fd,
const struct qemud_save_header *header,
- const char *path)
+ const char *path,
+ bool start_paused)
{
int ret = -1;
virDomainEventPtr event;
qemuDomainEventQueue(driver, event);
- /* If it was running before, resume it now. */
- if (header->was_running) {
+ /* If it was running before, resume it now unless caller requested pause. */
+ if (header->was_running && !start_paused) {
if (qemuProcessStartCPUs(driver, vm, conn,
VIR_DOMAIN_RUNNING_RESTORED,
QEMU_ASYNC_JOB_NONE) < 0) {
VIR_WARN("Failed to save status on vm %s", vm->def->name);
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;
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup;
- ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path);
+ ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
+ false);
if (virFileDirectFdClose(directFd) < 0)
VIR_WARN("Failed to close %s", path);
struct qemud_driver *driver,
virDomainObjPtr vm,
const char *path,
+ bool start_paused,
bool bypass_cache)
{
virDomainDefPtr def = NULL;
virDomainObjAssignDef(vm, def, true);
def = NULL;
- ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path);
+ ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
+ start_paused);
if (virFileDirectFdClose(directFd) < 0)
VIR_WARN("Failed to close %s", path);
}
} else {
ret = qemuDomainObjRestore(conn, driver, vm, managed_save,
- bypass_cache);
+ start_paused, bypass_cache);
if (ret == 0 && unlink(managed_save) < 0)
VIR_WARN("Failed to remove the managed state %s", managed_save);
virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_BOOTED);
- if (event)
+ if (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:
virDomainSnapshotObjPtr snap = NULL;
char uuidstr[VIR_UUID_STRING_BUFLEN];
virDomainEventPtr event = NULL;
+ virDomainEventPtr event2 = NULL;
qemuDomainObjPrivatePtr priv;
int rc;
goto endjob;
}
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
if (snap->def->state == VIR_DOMAIN_PAUSED) {
/* qemu unconditionally starts the domain running again after
* loadvm, so let's pause it to keep consistency
QEMU_ASYNC_JOB_NONE);
if (rc < 0)
goto endjob;
+ event2 = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
} else {
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
VIR_DOMAIN_RUNNING_FROM_SNAPSHOT);
}
-
- event = virDomainEventNewFromObj(vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
} else {
/* qemu is a little funny with running guests and the restoration
* of snapshots. If the snapshot was taken online,
} else if (snap) {
snap->def->current = false;
}
- if (event)
+ if (event) {
qemuDomainEventQueue(driver, event);
+ if (event2)
+ qemuDomainEventQueue(driver, event2);
+ }
if (vm)
virDomainObjUnlock(vm);
qemuDriverUnlock(driver);