]> xenbits.xensource.com Git - libvirt.git/commitdiff
snapshot: better events when starting paused
authorEric Blake <eblake@redhat.com>
Fri, 5 Aug 2011 22:05:50 +0000 (16:05 -0600)
committerEric Blake <eblake@redhat.com>
Fri, 2 Sep 2011 16:00:06 +0000 (10:00 -0600)
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.

examples/domain-events/events-c/event-test.c
include/libvirt/libvirt.h.in
src/qemu/qemu_driver.c

index 4766a0df3de1a840f293b8a2f2d912ac5dae6e75..6a3ed26ab4d5ab82eb67b99eb286cb6eae2ae688 100644 (file)
@@ -87,19 +87,45 @@ static const char *eventDetailToString(int event, int detail) {
             case VIR_DOMAIN_EVENT_STARTED_RESTORED:
                 ret = "Restored";
                 break;
+            case VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT:
+                ret = "Snapshot";
+                break;
             }
             break;
         case VIR_DOMAIN_EVENT_SUSPENDED:
-            if (detail == VIR_DOMAIN_EVENT_SUSPENDED_PAUSED)
+            switch (detail) {
+            case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED:
                 ret = "Paused";
-            else if (detail == VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED)
+                break;
+            case VIR_DOMAIN_EVENT_SUSPENDED_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;
         case VIR_DOMAIN_EVENT_RESUMED:
-            if (detail == VIR_DOMAIN_EVENT_RESUMED_UNPAUSED)
+            switch (detail) {
+            case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED:
                 ret = "Unpaused";
-            else if (detail == VIR_DOMAIN_EVENT_RESUMED_MIGRATED)
+                break;
+            case VIR_DOMAIN_EVENT_RESUMED_MIGRATED:
                 ret = "Migrated";
+                break;
+            case VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT:
+                ret = "Snapshot";
+                break;
+            }
             break;
         case VIR_DOMAIN_EVENT_STOPPED:
             switch (detail) {
@@ -121,6 +147,9 @@ static const char *eventDetailToString(int event, int detail) {
             case VIR_DOMAIN_EVENT_STOPPED_FAILED:
                 ret = "Failed";
                 break;
+            case VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT:
+                ret = "Snapshot";
+                break;
             }
             break;
     }
index 38b2763013bbbf1c5f8990a11906f407987df333..4ef6ab26dce5f330773da6af7fc284be41d880c7 100644 (file)
@@ -116,8 +116,7 @@ typedef enum {
     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 {
@@ -2031,6 +2030,8 @@ 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;
 
 /**
@@ -2041,6 +2042,7 @@ typedef enum {
 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;
 
 /**
index 2e0e766489b7ea6c9093e8499ec529239d8db598..4637c2d715d0269d09e9354b1eea1ad290d74f8b 100644 (file)
@@ -1269,6 +1269,7 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
     virDomainObjPtr vm = NULL;
     virDomainPtr dom = NULL;
     virDomainEventPtr event = NULL;
+    virDomainEventPtr event2 = NULL;
 
     virCheckFlags(VIR_DOMAIN_START_PAUSED |
                   VIR_DOMAIN_START_AUTODESTROY, NULL);
@@ -1316,6 +1317,16 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
     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);
@@ -1329,8 +1340,11 @@ cleanup:
     virDomainDefFree(def);
     if (vm)
         virDomainObjUnlock(vm);
-    if (event)
+    if (event) {
         qemuDomainEventQueue(driver, event);
+        if (event2)
+            qemuDomainEventQueue(driver, event2);
+    }
     qemuDriverUnlock(driver);
     return dom;
 }
@@ -3934,7 +3948,8 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
                            virDomainObjPtr vm,
                            int *fd,
                            const struct qemud_save_header *header,
-                           const char *path)
+                           const char *path,
+                           bool start_paused)
 {
     int ret = -1;
     virDomainEventPtr event;
@@ -4005,8 +4020,8 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
         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) {
@@ -4019,6 +4034,14 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
             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;
@@ -4070,7 +4093,8 @@ qemuDomainRestoreFlags(virConnectPtr conn,
     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);
 
@@ -4197,6 +4221,7 @@ qemuDomainObjRestore(virConnectPtr conn,
                      struct qemud_driver *driver,
                      virDomainObjPtr vm,
                      const char *path,
+                     bool start_paused,
                      bool bypass_cache)
 {
     virDomainDefPtr def = NULL;
@@ -4230,7 +4255,8 @@ qemuDomainObjRestore(virConnectPtr conn,
     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);
 
@@ -4518,7 +4544,7 @@ qemuDomainObjStart(virConnectPtr conn,
             }
         } 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);
@@ -4537,8 +4563,16 @@ qemuDomainObjStart(virConnectPtr conn,
             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:
@@ -8813,6 +8847,7 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
     virDomainSnapshotObjPtr snap = NULL;
     char uuidstr[VIR_UUID_STRING_BUFLEN];
     virDomainEventPtr event = NULL;
+    virDomainEventPtr event2 = NULL;
     qemuDomainObjPrivatePtr priv;
     int rc;
 
@@ -8869,6 +8904,9 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
                 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
@@ -8879,14 +8917,13 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
                                      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,
@@ -8929,8 +8966,11 @@ cleanup:
     } 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);