[libvirt] [PATCH v2 8/9] Implement domain state reason

Jiri Denemark jdenemar at redhat.com
Tue May 10 13:39:10 UTC 2011


Only in drivers which use virDomainObj, drivers that query hypervisor
for domain status need to be updated separately in case their hypervisor
supports this functionality.

The reason is also saved into domain state XML so if a domain is not
running (i.e., no state XML exists) the reason will be lost by libvirtd
restart. I think this is an acceptable limitation.
---
Notes:
    Version 2:
    - rebased
    - fixed || vs && typo

 src/conf/domain_conf.c     |  163 ++++++++++++++++++++++++++++++++++++++++++-
 src/conf/domain_conf.h     |   26 +++++++-
 src/libvirt_private.syms   |    4 +
 src/libxl/libxl_driver.c   |   53 ++++++++------
 src/lxc/lxc_driver.c       |   52 ++++++++-------
 src/openvz/openvz_conf.c   |   16 +++--
 src/openvz/openvz_driver.c |   29 ++++----
 src/qemu/qemu_driver.c     |   66 ++++++++++--------
 src/qemu/qemu_migration.c  |   24 ++++---
 src/qemu/qemu_process.c    |   61 ++++++++++-------
 src/qemu/qemu_process.h    |   12 +++-
 src/test/test_driver.c     |   80 ++++++++++++----------
 src/uml/uml_driver.c       |   30 ++++----
 src/vmware/vmware_conf.c   |    3 +-
 src/vmware/vmware_driver.c |   33 ++++-----
 15 files changed, 446 insertions(+), 206 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index d3efec6..bd7c64a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -376,6 +376,56 @@ VIR_ENUM_IMPL(virDomainState, VIR_DOMAIN_CRASHED+1,
               "shutoff",
               "crashed")
 
+#define VIR_DOMAIN_NOSTATE_LAST (VIR_DOMAIN_NOSTATE_UNKNOWN + 1)
+VIR_ENUM_IMPL(virDomainNostateReason, VIR_DOMAIN_NOSTATE_LAST,
+              "unknown")
+
+#define VIR_DOMAIN_RUNNING_LAST (VIR_DOMAIN_RUNNING_SAVE_CANCELED + 1)
+VIR_ENUM_IMPL(virDomainRunningReason, VIR_DOMAIN_RUNNING_LAST,
+              "unknown",
+              "booted",
+              "migrated",
+              "restored",
+              "from snapshot",
+              "unpaused",
+              "migration canceled",
+              "save canceled")
+
+#define VIR_DOMAIN_BLOCKED_LAST (VIR_DOMAIN_BLOCKED_UNKNOWN + 1)
+VIR_ENUM_IMPL(virDomainBlockedReason, VIR_DOMAIN_BLOCKED_LAST,
+              "unknown")
+
+#define VIR_DOMAIN_PAUSED_LAST (VIR_DOMAIN_PAUSED_FROM_SNAPSHOT + 1)
+VIR_ENUM_IMPL(virDomainPausedReason, VIR_DOMAIN_PAUSED_LAST,
+              "unknown",
+              "user",
+              "migration",
+              "save",
+              "dump",
+              "ioerror",
+              "watchdog",
+              "from snapshot")
+
+#define VIR_DOMAIN_SHUTDOWN_LAST (VIR_DOMAIN_SHUTDOWN_USER + 1)
+VIR_ENUM_IMPL(virDomainShutdownReason, VIR_DOMAIN_SHUTDOWN_LAST,
+              "unknown",
+              "user")
+
+#define VIR_DOMAIN_SHUTOFF_LAST (VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT + 1)
+VIR_ENUM_IMPL(virDomainShutoffReason, VIR_DOMAIN_SHUTOFF_LAST,
+              "unknown",
+              "shutdown",
+              "destroyed",
+              "crashed",
+              "migrated",
+              "saved",
+              "failed",
+              "from snapshot")
+
+#define VIR_DOMAIN_CRASHED_LAST (VIR_DOMAIN_CRASHED_UNKNOWN + 1)
+VIR_ENUM_IMPL(virDomainCrashedReason, VIR_DOMAIN_CRASHED_LAST,
+              "unknown")
+
 VIR_ENUM_IMPL(virDomainSeclabel, VIR_DOMAIN_SECLABEL_LAST,
               "dynamic",
               "static")
@@ -1080,7 +1130,8 @@ static virDomainObjPtr virDomainObjNew(virCapsPtr caps)
     }
 
     virDomainObjLock(domain);
-    domain->state = VIR_DOMAIN_SHUTOFF;
+    virDomainObjSetState(domain, VIR_DOMAIN_SHUTOFF,
+                                 VIR_DOMAIN_SHUTOFF_UNKNOWN);
     domain->refs = 1;
 
     virDomainSnapshotObjListInit(&domain->snapshots);
@@ -6273,6 +6324,8 @@ static virDomainObjPtr virDomainObjParseXML(virCapsPtr caps,
     virDomainObjPtr obj;
     xmlNodePtr *nodes = NULL;
     int i, n;
+    int state;
+    int reason = 0;
 
     if (!(obj = virDomainObjNew(caps)))
         return NULL;
@@ -6296,7 +6349,7 @@ static virDomainObjPtr virDomainObjParseXML(virCapsPtr caps,
                              "%s", _("missing domain state"));
         goto error;
     }
-    if ((obj->state = virDomainStateTypeFromString(tmp)) < 0) {
+    if ((state = virDomainStateTypeFromString(tmp)) < 0) {
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                              _("invalid domain state '%s'"), tmp);
         VIR_FREE(tmp);
@@ -6304,6 +6357,18 @@ static virDomainObjPtr virDomainObjParseXML(virCapsPtr caps,
     }
     VIR_FREE(tmp);
 
+    if ((tmp = virXPathString("string(./@reason)", ctxt))) {
+        if ((reason = virDomainStateReasonFromString(state, tmp)) < 0) {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                 _("invalid domain state reason '%s'"), tmp);
+            VIR_FREE(tmp);
+            goto error;
+        }
+        VIR_FREE(tmp);
+    }
+
+    virDomainObjSetState(obj, state, reason);
+
     if ((virXPathLong("string(./@pid)", ctxt, &val)) < 0) {
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                              "%s", _("invalid pid"));
@@ -8498,10 +8563,14 @@ static char *virDomainObjFormat(virCapsPtr caps,
 {
     char *config_xml = NULL;
     virBuffer buf = VIR_BUFFER_INITIALIZER;
+    int state;
+    int reason;
     int i;
 
-    virBufferAsprintf(&buf, "<domstatus state='%s' pid='%d'>\n",
-                      virDomainStateTypeToString(obj->state),
+    state = virDomainObjGetState(obj, &reason);
+    virBufferAsprintf(&buf, "<domstatus state='%s' reason='%s' pid='%d'>\n",
+                      virDomainStateTypeToString(state),
+                      virDomainStateReasonToString(state, reason),
                       obj->pid);
 
     for (i = 0 ; i < VIR_DOMAIN_TAINT_LAST ; i++) {
@@ -9604,3 +9673,89 @@ virDomainObjCopyPersistentDef(virCapsPtr caps, virDomainObjPtr dom)
     VIR_FREE(xml);
     return ret;
 }
+
+
+virDomainState
+virDomainObjGetState(virDomainObjPtr dom, int *reason)
+{
+    if (reason)
+        *reason = dom->state.reason;
+
+    return dom->state.state;
+}
+
+
+void
+virDomainObjSetState(virDomainObjPtr dom, virDomainState state, int reason)
+{
+    int last = -1;
+
+    switch (state) {
+    case VIR_DOMAIN_NOSTATE:    last = VIR_DOMAIN_NOSTATE_LAST;     break;
+    case VIR_DOMAIN_RUNNING:    last = VIR_DOMAIN_RUNNING_LAST;     break;
+    case VIR_DOMAIN_BLOCKED:    last = VIR_DOMAIN_BLOCKED_LAST;     break;
+    case VIR_DOMAIN_PAUSED:     last = VIR_DOMAIN_PAUSED_LAST;      break;
+    case VIR_DOMAIN_SHUTDOWN:   last = VIR_DOMAIN_SHUTDOWN_LAST;    break;
+    case VIR_DOMAIN_SHUTOFF:    last = VIR_DOMAIN_SHUTOFF_LAST;     break;
+    case VIR_DOMAIN_CRASHED:    last = VIR_DOMAIN_CRASHED_LAST;     break;
+    }
+
+    if (last < 0) {
+        VIR_ERROR(_("invalid domain state: %d"), state);
+        return;
+    }
+
+    dom->state.state = state;
+    if (reason > 0 && reason < last)
+        dom->state.reason = reason;
+    else
+        dom->state.reason = 0;
+}
+
+
+const char *
+virDomainStateReasonToString(virDomainState state, int reason)
+{
+    switch (state) {
+    case VIR_DOMAIN_NOSTATE:
+        return virDomainNostateReasonTypeToString(reason);
+    case VIR_DOMAIN_RUNNING:
+        return virDomainRunningReasonTypeToString(reason);
+    case VIR_DOMAIN_BLOCKED:
+        return virDomainBlockedReasonTypeToString(reason);
+    case VIR_DOMAIN_PAUSED:
+        return virDomainPausedReasonTypeToString(reason);
+    case VIR_DOMAIN_SHUTDOWN:
+        return virDomainShutdownReasonTypeToString(reason);
+    case VIR_DOMAIN_SHUTOFF:
+        return virDomainShutoffReasonTypeToString(reason);
+    case VIR_DOMAIN_CRASHED:
+        return virDomainCrashedReasonTypeToString(reason);
+    }
+
+    return NULL;
+}
+
+
+int
+virDomainStateReasonFromString(virDomainState state, const char *reason)
+{
+    switch (state) {
+    case VIR_DOMAIN_NOSTATE:
+        return virDomainNostateReasonTypeFromString(reason);
+    case VIR_DOMAIN_RUNNING:
+        return virDomainRunningReasonTypeFromString(reason);
+    case VIR_DOMAIN_BLOCKED:
+        return virDomainBlockedReasonTypeFromString(reason);
+    case VIR_DOMAIN_PAUSED:
+        return virDomainPausedReasonTypeFromString(reason);
+    case VIR_DOMAIN_SHUTDOWN:
+        return virDomainShutdownReasonTypeFromString(reason);
+    case VIR_DOMAIN_SHUTOFF:
+        return virDomainShutoffReasonTypeFromString(reason);
+    case VIR_DOMAIN_CRASHED:
+        return virDomainCrashedReasonTypeFromString(reason);
+    }
+
+    return -1;
+}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index a0f820c..fe42f21 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1193,6 +1193,12 @@ enum virDomainTaintFlags {
 };
 
 /* Guest VM runtime state */
+typedef struct _virDomainStateReason virDomainStateReason;
+struct _virDomainStateReason {
+    int state;
+    int reason;
+};
+
 typedef struct _virDomainObj virDomainObj;
 typedef virDomainObj *virDomainObjPtr;
 struct _virDomainObj {
@@ -1200,7 +1206,7 @@ struct _virDomainObj {
     int refs;
 
     int pid;
-    int state;
+    virDomainStateReason state;
 
     unsigned int autostart : 1;
     unsigned int persistent : 1;
@@ -1440,6 +1446,13 @@ int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
                                 virDomainDiskDefPathIterator iter,
                                 void *opaque);
 
+void
+virDomainObjSetState(virDomainObjPtr obj, virDomainState state, int reason)
+        ATTRIBUTE_NONNULL(1);
+virDomainState
+virDomainObjGetState(virDomainObjPtr obj, int *reason)
+        ATTRIBUTE_NONNULL(1);
+
 typedef const char* (*virLifecycleToStringFunc)(int type);
 typedef int (*virLifecycleFromStringFunc)(const char *type);
 
@@ -1494,6 +1507,17 @@ VIR_ENUM_DECL(virDomainGraphicsSpiceZlibCompression)
 VIR_ENUM_DECL(virDomainGraphicsSpicePlaybackCompression)
 /* from libvirt.h */
 VIR_ENUM_DECL(virDomainState)
+VIR_ENUM_DECL(virDomainNostateReason)
+VIR_ENUM_DECL(virDomainRunningReason)
+VIR_ENUM_DECL(virDomainBlockedReason)
+VIR_ENUM_DECL(virDomainPausedReason)
+VIR_ENUM_DECL(virDomainShutdownReason)
+VIR_ENUM_DECL(virDomainShutoffReason)
+VIR_ENUM_DECL(virDomainCrashedReason)
+
+const char *virDomainStateReasonToString(virDomainState state, int reason);
+int virDomainStateReasonFromString(virDomainState state, const char *reason);
+
 VIR_ENUM_DECL(virDomainSeclabel)
 VIR_ENUM_DECL(virDomainClockOffset)
 
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index e2e706d..1209315 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -292,6 +292,7 @@ virDomainNetTypeToString;
 virDomainObjAssignDef;
 virDomainObjCopyPersistentDef;
 virDomainObjGetPersistentDef;
+virDomainObjGetState;
 virDomainObjIsDuplicate;
 virDomainObjListDeinit;
 virDomainObjListGetActiveIDs;
@@ -301,6 +302,7 @@ virDomainObjListNumOfDomains;
 virDomainObjLock;
 virDomainObjRef;
 virDomainObjSetDefTransient;
+virDomainObjSetState;
 virDomainObjTaint;
 virDomainObjUnlock;
 virDomainObjUnref;
@@ -324,6 +326,8 @@ virDomainSnapshotObjListRemove;
 virDomainSoundDefFree;
 virDomainSoundModelTypeFromString;
 virDomainSoundModelTypeToString;
+virDomainStateReasonFromString;
+virDomainStateReasonToString;
 virDomainStateTypeFromString;
 virDomainStateTypeToString;
 virDomainTaintTypeFromString;
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 1fcf723..6962711 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -245,7 +245,9 @@ libxlDoNodeGetInfo(libxlDriverPrivatePtr driver, virNodeInfoPtr info)
  * virDomainObjPtr should be locked on invocation
  */
 static void
-libxlVmCleanup(libxlDriverPrivatePtr driver, virDomainObjPtr vm)
+libxlVmCleanup(libxlDriverPrivatePtr driver,
+               virDomainObjPtr vm,
+               virDomainShutoffReason reason)
 {
     libxlDomainObjPrivatePtr priv = vm->privateData;
     int vnc_port;
@@ -265,7 +267,7 @@ libxlVmCleanup(libxlDriverPrivatePtr driver, virDomainObjPtr vm)
 
     if (vm->persistent) {
         vm->def->id = -1;
-        vm->state = VIR_DOMAIN_SHUTOFF;
+        virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
     }
 
     if ((vm->def->ngraphics == 1) &&
@@ -302,7 +304,10 @@ libxlVmCleanup(libxlDriverPrivatePtr driver, virDomainObjPtr vm)
  * virDomainObjPtr should be locked on invocation
  */
 static int
-libxlVmReap(libxlDriverPrivatePtr driver, virDomainObjPtr vm, int force)
+libxlVmReap(libxlDriverPrivatePtr driver,
+            virDomainObjPtr vm,
+            int force,
+            virDomainShutoffReason reason)
 {
     libxlDomainObjPrivatePtr priv = vm->privateData;
 
@@ -312,7 +317,7 @@ libxlVmReap(libxlDriverPrivatePtr driver, virDomainObjPtr vm, int force)
         return -1;
     }
 
-    libxlVmCleanup(driver, vm);
+    libxlVmCleanup(driver, vm, reason);
     return 0;
 }
 
@@ -353,6 +358,8 @@ static void libxlEventHandler(int watch,
         goto cleanup;
 
     if (event.type == LIBXL_EVENT_DOMAIN_DEATH) {
+        virDomainShutoffReason reason;
+
         /* libxl_event_get_domain_death_info returns 1 if death
          * event was for this domid */
         if (libxl_event_get_domain_death_info(&priv->ctx,
@@ -366,18 +373,22 @@ static void libxlEventHandler(int watch,
         switch (info.shutdown_reason) {
             case SHUTDOWN_poweroff:
             case SHUTDOWN_crash:
-                if (info.shutdown_reason == SHUTDOWN_crash)
+                if (info.shutdown_reason == SHUTDOWN_crash) {
                     dom_event = virDomainEventNewFromObj(vm,
                                               VIR_DOMAIN_EVENT_STOPPED,
                                               VIR_DOMAIN_EVENT_STOPPED_CRASHED);
-                libxlVmReap(driver, vm, 0);
+                    reason = VIR_DOMAIN_SHUTOFF_CRASHED;
+                } else {
+                    reason = VIR_DOMAIN_SHUTOFF_SHUTDOWN;
+                }
+                libxlVmReap(driver, vm, 0, reason);
                 if (!vm->persistent) {
                     virDomainRemoveInactive(&driver->domains, vm);
                     vm = NULL;
                 }
                 break;
             case SHUTDOWN_reboot:
-                libxlVmReap(driver, vm, 0);
+                libxlVmReap(driver, vm, 0, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
                 libxlVmStart(driver, vm, 0);
                 break;
             default:
@@ -596,9 +607,9 @@ libxlVmStart(libxlDriverPrivatePtr driver,
 
     if (!start_paused) {
         libxl_domain_unpause(&priv->ctx, domid);
-        vm->state = VIR_DOMAIN_RUNNING;
+        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
     } else {
-        vm->state = VIR_DOMAIN_PAUSED;
+        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
     }
 
 
@@ -617,7 +628,7 @@ error:
     if (domid > 0) {
         libxl_domain_destroy(&priv->ctx, domid, 0);
         def->id = -1;
-        vm->state = VIR_DOMAIN_SHUTOFF;
+        virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED);
     }
     libxl_domain_config_destroy(&d_config);
     VIR_FREE(dom_xml);
@@ -662,7 +673,7 @@ libxlReconnectDomain(void *payload,
 
     /* Update domid in case it changed (e.g. reboot) while we were gone? */
     vm->def->id = d_info.domid;
-    vm->state = VIR_DOMAIN_RUNNING;
+    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNKNOWN);
 
     /* Recreate domain death et. al. events */
     libxlCreateDomEvents(vm);
@@ -670,7 +681,7 @@ libxlReconnectDomain(void *payload,
     return;
 
 out:
-    libxlVmCleanup(driver, vm);
+    libxlVmCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_UNKNOWN);
     if (!vm->persistent)
         virDomainRemoveInactive(&driver->domains, vm);
     else
@@ -1213,7 +1224,7 @@ libxlDomainSuspend(virDomainPtr dom)
 
     priv = vm->privateData;
 
-    if (vm->state != VIR_DOMAIN_PAUSED) {
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
         if (libxl_domain_pause(&priv->ctx, dom->id) != 0) {
             libxlError(VIR_ERR_INTERNAL_ERROR,
                        _("Failed to suspend domain '%d' with libxenlight"),
@@ -1221,7 +1232,7 @@ libxlDomainSuspend(virDomainPtr dom)
             goto cleanup;
         }
 
-        vm->state = VIR_DOMAIN_PAUSED;
+        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
 
         event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
                                          VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
@@ -1272,7 +1283,7 @@ libxlDomainResume(virDomainPtr dom)
 
     priv = vm->privateData;
 
-    if (vm->state == VIR_DOMAIN_PAUSED) {
+    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
         if (libxl_domain_unpause(&priv->ctx, dom->id) != 0) {
             libxlError(VIR_ERR_INTERNAL_ERROR,
                        _("Failed to resume domain '%d' with libxenlight"),
@@ -1280,7 +1291,8 @@ libxlDomainResume(virDomainPtr dom)
             goto cleanup;
         }
 
-        vm->state = VIR_DOMAIN_RUNNING;
+        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
+                             VIR_DOMAIN_RUNNING_UNPAUSED);
 
         event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_RESUMED,
                                          VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
@@ -1413,7 +1425,7 @@ libxlDomainDestroy(virDomainPtr dom)
     event = virDomainEventNewFromObj(vm,VIR_DOMAIN_EVENT_STOPPED,
                                      VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
 
-    if (libxlVmReap(driver, vm, 1) != 0) {
+    if (libxlVmReap(driver, vm, 1, VIR_DOMAIN_SHUTOFF_DESTROYED) != 0) {
         libxlError(VIR_ERR_INTERNAL_ERROR,
                    _("Failed to destroy domain '%d'"), dom->id);
         goto cleanup;
@@ -1596,7 +1608,7 @@ libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
         info->memory = d_info.current_memkb;
     }
 
-    info->state = vm->state;
+    info->state = virDomainObjGetState(vm, NULL);
     info->maxMem = vm->def->mem.max_balloon;
     info->nrVirtCpu = vm->def->vcpus;
     ret = 0;
@@ -1629,10 +1641,7 @@ libxlDomainGetState(virDomainPtr dom,
         goto cleanup;
     }
 
-    *state = vm->state;
-    if (reason)
-        *reason = 0;
-
+    *state = virDomainObjGetState(vm, reason);
     ret = 0;
 
   cleanup:
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 2d57eb2..aab0c7f 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -522,7 +522,7 @@ static int lxcDomainGetInfo(virDomainPtr dom,
         goto cleanup;
     }
 
-    info->state = vm->state;
+    info->state = virDomainObjGetState(vm, NULL);
 
     if (!virDomainObjIsActive(vm) || driver->cgroup == NULL) {
         info->cpuTime = 0;
@@ -588,10 +588,7 @@ lxcDomainGetState(virDomainPtr dom,
         goto cleanup;
     }
 
-    *state = vm->state;
-    if (reason)
-        *reason = 0;
-
+    *state = virDomainObjGetState(vm, reason);
     ret = 0;
 
 cleanup:
@@ -984,15 +981,16 @@ cleanup:
 
 /**
  * lxcVmCleanup:
- * @conn: pointer to connection
  * @driver: pointer to driver structure
  * @vm: pointer to VM to clean up
+ * @reason: reason for switching the VM to shutoff state
  *
  * Cleanout resources associated with the now dead VM
  *
  */
 static void lxcVmCleanup(lxc_driver_t *driver,
-                        virDomainObjPtr  vm)
+                         virDomainObjPtr vm,
+                         virDomainShutoffReason reason)
 {
     virCgroupPtr cgroup;
     int i;
@@ -1014,7 +1012,7 @@ static void lxcVmCleanup(lxc_driver_t *driver,
     virFileDeletePid(driver->stateDir, vm->def->name);
     virDomainDeleteConfig(driver->stateDir, NULL, vm);
 
-    vm->state = VIR_DOMAIN_SHUTOFF;
+    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
     vm->pid = -1;
     vm->def->id = -1;
     priv->monitor = -1;
@@ -1198,7 +1196,8 @@ error:
 
 
 static int lxcVmTerminate(lxc_driver_t *driver,
-                          virDomainObjPtr vm)
+                          virDomainObjPtr vm,
+                          virDomainShutoffReason reason)
 {
     virCgroupPtr group = NULL;
     int rc;
@@ -1225,7 +1224,7 @@ static int lxcVmTerminate(lxc_driver_t *driver,
         rc = -1;
         goto cleanup;
     }
-    lxcVmCleanup(driver, vm);
+    lxcVmCleanup(driver, vm, reason);
 
     rc = 0;
 
@@ -1255,7 +1254,7 @@ static void lxcMonitorEvent(int watch,
         goto cleanup;
     }
 
-    if (lxcVmTerminate(driver, vm) < 0) {
+    if (lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0) {
         virEventRemoveHandle(watch);
     } else {
         event = virDomainEventNewFromObj(vm,
@@ -1481,6 +1480,7 @@ cleanup:
  * @conn: pointer to connection
  * @driver: pointer to driver structure
  * @vm: pointer to virtual machine structure
+ * @reason: reason for switching vm to running state
  *
  * Starts a vm
  *
@@ -1488,7 +1488,8 @@ cleanup:
  */
 static int lxcVmStart(virConnectPtr conn,
                       lxc_driver_t * driver,
-                      virDomainObjPtr  vm)
+                      virDomainObjPtr vm,
+                      virDomainRunningReason reason)
 {
     int rc = -1, r;
     unsigned int i;
@@ -1588,14 +1589,14 @@ static int lxcVmStart(virConnectPtr conn,
     }
 
     vm->def->id = vm->pid;
-    vm->state = VIR_DOMAIN_RUNNING;
+    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
 
     if ((priv->monitorWatch = virEventAddHandle(
              priv->monitor,
              VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
              lxcMonitorEvent,
              vm, NULL)) < 0) {
-        lxcVmTerminate(driver, vm);
+        lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
         goto cleanup;
     }
 
@@ -1668,7 +1669,7 @@ static int lxcDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
         goto cleanup;
     }
 
-    ret = lxcVmStart(dom->conn, driver, vm);
+    ret = lxcVmStart(dom->conn, driver, vm, VIR_DOMAIN_RUNNING_BOOTED);
 
     if (ret == 0)
         event = virDomainEventNewFromObj(vm,
@@ -1739,7 +1740,7 @@ lxcDomainCreateAndStart(virConnectPtr conn,
         goto cleanup;
     def = NULL;
 
-    if (lxcVmStart(conn, driver, vm) < 0) {
+    if (lxcVmStart(conn, driver, vm, VIR_DOMAIN_RUNNING_BOOTED) < 0) {
         virDomainRemoveInactive(&driver->domains, vm);
         vm = NULL;
         goto cleanup;
@@ -1930,7 +1931,7 @@ static int lxcDomainDestroy(virDomainPtr dom)
         goto cleanup;
     }
 
-    ret = lxcVmTerminate(driver, vm);
+    ret = lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
     event = virDomainEventNewFromObj(vm,
                                      VIR_DOMAIN_EVENT_STOPPED,
                                      VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
@@ -1978,7 +1979,8 @@ lxcAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaqu
     virDomainObjLock(vm);
     if (vm->autostart &&
         !virDomainObjIsActive(vm)) {
-        int ret = lxcVmStart(data->conn, data->driver, vm);
+        int ret = lxcVmStart(data->conn, data->driver, vm,
+                             VIR_DOMAIN_RUNNING_BOOTED);
         if (ret < 0) {
             virErrorPtr err = virGetLastError();
             VIR_ERROR(_("Failed to autostart VM '%s': %s"),
@@ -2052,14 +2054,15 @@ lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
 
     if (vm->pid != 0) {
         vm->def->id = vm->pid;
-        vm->state = VIR_DOMAIN_RUNNING;
+        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
+                             VIR_DOMAIN_RUNNING_UNKNOWN);
 
         if ((priv->monitorWatch = virEventAddHandle(
                  priv->monitor,
                  VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
                  lxcMonitorEvent,
                  vm, NULL)) < 0) {
-            lxcVmTerminate(driver, vm);
+            lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
             goto cleanup;
         }
     } else {
@@ -2673,13 +2676,13 @@ static int lxcDomainSuspend(virDomainPtr dom)
         goto cleanup;
     }
 
-    if (vm->state != VIR_DOMAIN_PAUSED) {
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
         if (lxcFreezeContainer(driver, vm) < 0) {
             lxcError(VIR_ERR_OPERATION_FAILED,
                      "%s", _("Suspend operation failed"));
             goto cleanup;
         }
-        vm->state = VIR_DOMAIN_PAUSED;
+        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
 
         event = virDomainEventNewFromObj(vm,
                                          VIR_DOMAIN_EVENT_SUSPENDED,
@@ -2738,13 +2741,14 @@ static int lxcDomainResume(virDomainPtr dom)
         goto cleanup;
     }
 
-    if (vm->state == VIR_DOMAIN_PAUSED) {
+    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
         if (lxcUnfreezeContainer(driver, vm) < 0) {
             lxcError(VIR_ERR_OPERATION_FAILED,
                      "%s", _("Resume operation failed"));
             goto cleanup;
         }
-        vm->state = VIR_DOMAIN_RUNNING;
+        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
+                             VIR_DOMAIN_RUNNING_UNPAUSED);
 
         event = virDomainEventNewFromObj(vm,
                                          VIR_DOMAIN_EVENT_RESUMED,
diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c
index 88cd4c8..8c6261f 100644
--- a/src/openvz/openvz_conf.c
+++ b/src/openvz/openvz_conf.c
@@ -484,14 +484,20 @@ int openvzLoadDomains(struct openvz_driver *driver) {
         if (VIR_ALLOC(dom->def) < 0)
             goto no_memory;
 
-        if (STREQ(status, "stopped"))
-            dom->state = VIR_DOMAIN_SHUTOFF;
-        else
-            dom->state = VIR_DOMAIN_RUNNING;
+        if (STREQ(status, "stopped")) {
+            virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF,
+                                 VIR_DOMAIN_SHUTOFF_UNKNOWN);
+        } else {
+            virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
+                                 VIR_DOMAIN_RUNNING_UNKNOWN);
+        }
 
         dom->refs = 1;
         dom->pid = veid;
-        dom->def->id = dom->state == VIR_DOMAIN_SHUTOFF ? -1 : veid;
+        if (virDomainObjGetState(dom, NULL) == VIR_DOMAIN_SHUTOFF)
+            dom->def->id = -1;
+        else
+            dom->def->id = veid;
         /* XXX OpenVZ doesn't appear to have concept of a transient domain */
         dom->persistent = 1;
 
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index 3ab72e8..4ecaea7 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -353,7 +353,7 @@ static int openvzDomainGetInfo(virDomainPtr dom,
         goto cleanup;
     }
 
-    info->state = vm->state;
+    info->state = virDomainObjGetState(vm, NULL);
 
     if (!virDomainObjIsActive(vm)) {
         info->cpuTime = 0;
@@ -399,10 +399,7 @@ openvzDomainGetState(virDomainPtr dom,
         goto cleanup;
     }
 
-    *state = vm->state;
-    if (reason)
-        *reason = 0;
-
+    *state = virDomainObjGetState(vm, reason);
     ret = 0;
 
 cleanup:
@@ -525,12 +522,12 @@ static int openvzDomainSuspend(virDomainPtr dom) {
         goto cleanup;
     }
 
-    if (vm->state != VIR_DOMAIN_PAUSED) {
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
         openvzSetProgramSentinal(prog, vm->def->name);
         if (virRun(prog, NULL) < 0) {
             goto cleanup;
         }
-        vm->state = VIR_DOMAIN_PAUSED;
+        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
     }
 
     ret = 0;
@@ -563,12 +560,12 @@ static int openvzDomainResume(virDomainPtr dom) {
       goto cleanup;
   }
 
-  if (vm->state == VIR_DOMAIN_PAUSED) {
+  if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
       openvzSetProgramSentinal(prog, vm->def->name);
       if (virRun(prog, NULL) < 0) {
           goto cleanup;
       }
-      vm->state = VIR_DOMAIN_RUNNING;
+      virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNPAUSED);
   }
 
   ret = 0;
@@ -596,7 +593,7 @@ static int openvzDomainShutdown(virDomainPtr dom) {
     }
 
     openvzSetProgramSentinal(prog, vm->def->name);
-    if (vm->state != VIR_DOMAIN_RUNNING) {
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
         openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                     _("domain is not in running state"));
         goto cleanup;
@@ -606,7 +603,7 @@ static int openvzDomainShutdown(virDomainPtr dom) {
         goto cleanup;
 
     vm->def->id = -1;
-    vm->state = VIR_DOMAIN_SHUTOFF;
+    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
     dom->id = -1;
     ret = 0;
 
@@ -634,7 +631,7 @@ static int openvzDomainReboot(virDomainPtr dom,
     }
 
     openvzSetProgramSentinal(prog, vm->def->name);
-    if (vm->state != VIR_DOMAIN_RUNNING) {
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
         openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                     _("domain is not in running state"));
         goto cleanup;
@@ -644,6 +641,8 @@ static int openvzDomainReboot(virDomainPtr dom,
         goto cleanup;
     ret = 0;
 
+    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
+
 cleanup:
     if (vm)
         virDomainObjUnlock(vm);
@@ -1022,7 +1021,7 @@ openvzDomainCreateXML(virConnectPtr conn, const char *xml,
 
     vm->pid = strtoI(vm->def->name);
     vm->def->id = vm->pid;
-    vm->state = VIR_DOMAIN_RUNNING;
+    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
 
     if (vm->def->maxvcpus > 0) {
         if (openvzDomainSetVcpusInternal(vm, vm->def->maxvcpus) < 0) {
@@ -1064,7 +1063,7 @@ openvzDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
         goto cleanup;
     }
 
-    if (vm->state != VIR_DOMAIN_SHUTOFF) {
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_SHUTOFF) {
         openvzError(VIR_ERR_OPERATION_DENIED, "%s",
                     _("domain is not in shutoff state"));
         goto cleanup;
@@ -1078,7 +1077,7 @@ openvzDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
     vm->pid = strtoI(vm->def->name);
     vm->def->id = vm->pid;
     dom->id = vm->pid;
-    vm->state = VIR_DOMAIN_RUNNING;
+    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
     ret = 0;
 
 cleanup:
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a1617bc..1c5f439 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1325,7 +1325,7 @@ static int qemudDomainSuspend(virDomainPtr dom) {
     priv = vm->privateData;
 
     if (priv->jobActive == QEMU_JOB_MIGRATION_OUT) {
-        if (vm->state != VIR_DOMAIN_PAUSED) {
+        if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
             VIR_DEBUG("Requesting domain pause on %s",
                       vm->def->name);
             priv->jobSignals |= QEMU_JOB_SIGNAL_SUSPEND;
@@ -1341,8 +1341,8 @@ static int qemudDomainSuspend(virDomainPtr dom) {
                             "%s", _("domain is not running"));
             goto endjob;
         }
-        if (vm->state != VIR_DOMAIN_PAUSED) {
-            if (qemuProcessStopCPUs(driver, vm) < 0) {
+        if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
+            if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_USER) < 0) {
                 goto endjob;
             }
             event = virDomainEventNewFromObj(vm,
@@ -1394,8 +1394,9 @@ static int qemudDomainResume(virDomainPtr dom) {
                         "%s", _("domain is not running"));
         goto endjob;
     }
-    if (vm->state == VIR_DOMAIN_PAUSED) {
-        if (qemuProcessStartCPUs(driver, vm, dom->conn) < 0) {
+    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
+        if (qemuProcessStartCPUs(driver, vm, dom->conn,
+                                 VIR_DOMAIN_RUNNING_UNPAUSED) < 0) {
             if (virGetLastError() == NULL)
                 qemuReportError(VIR_ERR_OPERATION_FAILED,
                                 "%s", _("resume operation failed"));
@@ -1491,7 +1492,7 @@ static int qemudDomainDestroy(virDomainPtr dom) {
         goto endjob;
     }
 
-    qemuProcessStop(driver, vm, 0);
+    qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_DESTROYED);
     event = virDomainEventNewFromObj(vm,
                                      VIR_DOMAIN_EVENT_STOPPED,
                                      VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
@@ -1725,7 +1726,7 @@ static int qemudDomainGetInfo(virDomainPtr dom,
         goto cleanup;
     }
 
-    info->state = vm->state;
+    info->state = virDomainObjGetState(vm, NULL);
 
     if (!virDomainObjIsActive(vm)) {
         info->cpuTime = 0;
@@ -1807,10 +1808,7 @@ qemuDomainGetState(virDomainPtr dom,
         goto cleanup;
     }
 
-    *state = vm->state;
-    if (reason)
-        *reason = 0;
-
+    *state = virDomainObjGetState(vm, reason);
     ret = 0;
 
 cleanup:
@@ -1936,9 +1934,9 @@ static int qemudDomainSaveFlag(struct qemud_driver *driver, virDomainPtr dom,
     priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;
 
     /* Pause */
-    if (vm->state == VIR_DOMAIN_RUNNING) {
+    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
         header.was_running = 1;
-        if (qemuProcessStopCPUs(driver, vm) < 0)
+        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE) < 0)
             goto endjob;
 
         if (!virDomainObjIsActive(vm)) {
@@ -2085,7 +2083,7 @@ static int qemudDomainSaveFlag(struct qemud_driver *driver, virDomainPtr dom,
     ret = 0;
 
     /* Shut it down */
-    qemuProcessStop(driver, vm, 0);
+    qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_SAVED);
     qemuAuditDomainStop(vm, "saved");
     event = virDomainEventNewFromObj(vm,
                                      VIR_DOMAIN_EVENT_STOPPED,
@@ -2101,7 +2099,8 @@ endjob:
     if (vm) {
         if (ret != 0) {
             if (header.was_running && virDomainObjIsActive(vm)) {
-                rc = qemuProcessStartCPUs(driver, vm, dom->conn);
+                rc = qemuProcessStartCPUs(driver, vm, dom->conn,
+                                          VIR_DOMAIN_RUNNING_SAVE_CANCELED);
                 if (rc < 0)
                     VIR_WARN0("Unable to resume guest CPUs after save failure");
             }
@@ -2413,11 +2412,12 @@ static int qemudDomainCoreDump(virDomainPtr dom,
 
     /* Migrate will always stop the VM, so the resume condition is
        independent of whether the stop command is issued.  */
-    resume = (vm->state == VIR_DOMAIN_RUNNING);
+    resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
 
     /* Pause domain for non-live dump */
-    if (!(flags & VIR_DUMP_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
-        if (qemuProcessStopCPUs(driver, vm) < 0)
+    if (!(flags & VIR_DUMP_LIVE) &&
+        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
+        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_DUMP) < 0)
             goto endjob;
         paused = 1;
 
@@ -2436,7 +2436,7 @@ static int qemudDomainCoreDump(virDomainPtr dom,
 
 endjob:
     if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
-        qemuProcessStop(driver, vm, 0);
+        qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_CRASHED);
         qemuAuditDomainStop(vm, "crashed");
         event = virDomainEventNewFromObj(vm,
                                          VIR_DOMAIN_EVENT_STOPPED,
@@ -2447,7 +2447,8 @@ endjob:
        will support synchronous operations so we always get here after
        the migration is complete.  */
     else if (resume && paused && virDomainObjIsActive(vm)) {
-        if (qemuProcessStartCPUs(driver, vm, dom->conn) < 0) {
+        if (qemuProcessStartCPUs(driver, vm, dom->conn,
+                                 VIR_DOMAIN_RUNNING_UNPAUSED) < 0) {
             if (virGetLastError() == NULL)
                 qemuReportError(VIR_ERR_OPERATION_FAILED,
                                 "%s", _("resuming after dump failed"));
@@ -2513,7 +2514,8 @@ static void processWatchdogEvent(void *data, void *opaque)
                 qemuReportError(VIR_ERR_OPERATION_FAILED,
                                 "%s", _("Dump failed"));
 
-            ret = qemuProcessStartCPUs(driver, wdEvent->vm, NULL);
+            ret = qemuProcessStartCPUs(driver, wdEvent->vm, NULL,
+                                       VIR_DOMAIN_RUNNING_UNPAUSED);
 
             if (ret < 0)
                 qemuReportError(VIR_ERR_OPERATION_FAILED,
@@ -3211,7 +3213,8 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
 
     /* If it was running before, resume it now. */
     if (header->was_running) {
-        if (qemuProcessStartCPUs(driver, vm, conn) < 0) {
+        if (qemuProcessStartCPUs(driver, vm, conn,
+                                 VIR_DOMAIN_RUNNING_RESTORED) < 0) {
             if (virGetLastError() == NULL)
                 qemuReportError(VIR_ERR_OPERATION_FAILED,
                                 "%s", _("failed to resume domain"));
@@ -6345,12 +6348,12 @@ qemuDomainSnapshotCreateActive(virConnectPtr conn,
     if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
         return -1;
 
-    if (vm->state == VIR_DOMAIN_RUNNING) {
+    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
         /* savevm monitor command pauses the domain emitting an event which
          * confuses libvirt since it's not notified when qemu resumes the
          * domain. Thus we stop and start CPUs ourselves.
          */
-        if (qemuProcessStopCPUs(driver, vm) < 0)
+        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE) < 0)
             goto cleanup;
 
         resume = true;
@@ -6367,7 +6370,8 @@ qemuDomainSnapshotCreateActive(virConnectPtr conn,
 
 cleanup:
     if (resume && virDomainObjIsActive(vm) &&
-        qemuProcessStartCPUs(driver, vm, conn) < 0 &&
+        qemuProcessStartCPUs(driver, vm, conn,
+                             VIR_DOMAIN_RUNNING_UNPAUSED) < 0 &&
         virGetLastError() == NULL) {
         qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                         _("resuming after snapshot failed"));
@@ -6417,7 +6421,7 @@ static virDomainSnapshotPtr qemuDomainSnapshotCreateXML(virDomainPtr domain,
     if (!(snap = virDomainSnapshotAssignDef(&vm->snapshots, def)))
         goto cleanup;
 
-    snap->def->state = vm->state;
+    snap->def->state = virDomainObjGetState(vm, NULL);
 
     /* actually do the snapshot */
     if (!virDomainObjIsActive(vm)) {
@@ -6717,9 +6721,13 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
             /* qemu unconditionally starts the domain running again after
              * loadvm, so let's pause it to keep consistency
              */
-            rc = qemuProcessStopCPUs(driver, vm);
+            rc = qemuProcessStopCPUs(driver, vm,
+                                     VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
             if (rc < 0)
                 goto endjob;
+        } else {
+            virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
+                                 VIR_DOMAIN_RUNNING_FROM_SNAPSHOT);
         }
 
         event = virDomainEventNewFromObj(vm,
@@ -6738,7 +6746,7 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
          */
 
         if (virDomainObjIsActive(vm)) {
-            qemuProcessStop(driver, vm, 0);
+            qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
             qemuAuditDomainStop(vm, "from-snapshot");
             event = virDomainEventNewFromObj(vm,
                                              VIR_DOMAIN_EVENT_STOPPED,
@@ -6755,8 +6763,6 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
             goto endjob;
     }
 
-    vm->state = snap->def->state;
-
     ret = 0;
 
 endjob:
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 6738a53..b45beb7 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -65,7 +65,7 @@ qemuMigrationSetOffline(struct qemud_driver *driver,
 {
     int ret;
 
-    ret = qemuProcessStopCPUs(driver, vm);
+    ret = qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_MIGRATION);
     if (ret == 0) {
         virDomainEventPtr event;
 
@@ -325,7 +325,7 @@ qemuMigrationPrepareTunnel(struct qemud_driver *driver,
 
     if (virFDStreamOpen(st, dataFD[1]) < 0) {
         qemuAuditDomainStart(vm, "migrated", false);
-        qemuProcessStop(driver, vm, 0);
+        qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_FAILED);
         if (!vm->persistent) {
             if (qemuDomainObjEndJob(vm) > 0)
                 virDomainRemoveInactive(&driver->domains, vm);
@@ -1047,8 +1047,9 @@ int qemuMigrationPerform(struct qemud_driver *driver,
     memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
     priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;
 
-    resume = vm->state == VIR_DOMAIN_RUNNING;
-    if (!(flags & VIR_MIGRATE_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
+    resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
+    if (!(flags & VIR_MIGRATE_LIVE) &&
+        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
         if (qemuMigrationSetOffline(driver, vm) < 0)
             goto endjob;
     }
@@ -1063,7 +1064,7 @@ int qemuMigrationPerform(struct qemud_driver *driver,
     }
 
     /* Clean up the source domain. */
-    qemuProcessStop(driver, vm, 1);
+    qemuProcessStop(driver, vm, 1, VIR_DOMAIN_SHUTOFF_MIGRATED);
     qemuAuditDomainStop(vm, "migrated");
     resume = 0;
 
@@ -1079,9 +1080,10 @@ int qemuMigrationPerform(struct qemud_driver *driver,
     ret = 0;
 
 endjob:
-    if (resume && vm->state == VIR_DOMAIN_PAUSED) {
+    if (resume && virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
         /* we got here through some sort of failure; start the domain again */
-        if (qemuProcessStartCPUs(driver, vm, conn) < 0) {
+        if (qemuProcessStartCPUs(driver, vm, conn,
+                                 VIR_DOMAIN_RUNNING_MIGRATION_CANCELED) < 0) {
             /* Hm, we already know we are in error here.  We don't want to
              * overwrite the previous error, though, so we just throw something
              * to the logs and hope for the best
@@ -1220,7 +1222,8 @@ qemuMigrationFinish(struct qemud_driver *driver,
              * >= 0.10.6 to work properly.  This isn't strictly necessary on
              * older qemu's, but it also doesn't hurt anything there
              */
-            if (qemuProcessStartCPUs(driver, vm, dconn) < 0) {
+            if (qemuProcessStartCPUs(driver, vm, dconn,
+                                     VIR_DOMAIN_RUNNING_MIGRATED) < 0) {
                 if (virGetLastError() == NULL)
                     qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                     "%s", _("resume operation failed"));
@@ -1231,7 +1234,8 @@ qemuMigrationFinish(struct qemud_driver *driver,
         event = virDomainEventNewFromObj(vm,
                                          VIR_DOMAIN_EVENT_RESUMED,
                                          VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
-        if (vm->state == VIR_DOMAIN_PAUSED) {
+        if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
+            virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
             qemuDomainEventQueue(driver, event);
             event = virDomainEventNewFromObj(vm,
                                              VIR_DOMAIN_EVENT_SUSPENDED,
@@ -1242,7 +1246,7 @@ qemuMigrationFinish(struct qemud_driver *driver,
             goto endjob;
         }
     } else {
-        qemuProcessStop(driver, vm, 1);
+        qemuProcessStop(driver, vm, 1, VIR_DOMAIN_SHUTOFF_FAILED);
         qemuAuditDomainStop(vm, "failed");
         event = virDomainEventNewFromObj(vm,
                                          VIR_DOMAIN_EVENT_STOPPED,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index bd7c932..f74122e 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -132,7 +132,10 @@ qemuProcessHandleMonitorEOF(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                                      VIR_DOMAIN_EVENT_STOPPED_FAILED :
                                      VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
 
-    qemuProcessStop(driver, vm, 0);
+    qemuProcessStop(driver, vm, 0,
+                    hasError ?
+                    VIR_DOMAIN_SHUTOFF_CRASHED :
+                    VIR_DOMAIN_SHUTOFF_SHUTDOWN);
     qemuAuditDomainStop(vm, hasError ? "failed" : "shutdown");
 
     if (!vm->persistent)
@@ -340,11 +343,11 @@ qemuProcessHandleStop(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     virDomainEventPtr event = NULL;
 
     virDomainObjLock(vm);
-    if (vm->state == VIR_DOMAIN_RUNNING) {
+    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
         VIR_DEBUG("Transitioned guest %s to paused state due to unknown event",
                   vm->def->name);
 
-        vm->state = VIR_DOMAIN_PAUSED;
+        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_UNKNOWN);
         event = virDomainEventNewFromObj(vm,
                                          VIR_DOMAIN_EVENT_SUSPENDED,
                                          VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
@@ -409,10 +412,10 @@ qemuProcessHandleWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     watchdogEvent = virDomainEventWatchdogNewFromObj(vm, action);
 
     if (action == VIR_DOMAIN_EVENT_WATCHDOG_PAUSE &&
-        vm->state == VIR_DOMAIN_RUNNING) {
+        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
         VIR_DEBUG("Transitioned guest %s to paused state due to watchdog", vm->def->name);
 
-        vm->state = VIR_DOMAIN_PAUSED;
+        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_WATCHDOG);
         lifecycleEvent = virDomainEventNewFromObj(vm,
                                                   VIR_DOMAIN_EVENT_SUSPENDED,
                                                   VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG);
@@ -488,10 +491,10 @@ qemuProcessHandleIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     ioErrorEvent2 = virDomainEventIOErrorReasonNewFromObj(vm, srcPath, devAlias, action, reason);
 
     if (action == VIR_DOMAIN_EVENT_IO_ERROR_PAUSE &&
-        vm->state == VIR_DOMAIN_RUNNING) {
+        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
         VIR_DEBUG("Transitioned guest %s to paused state due to IO error", vm->def->name);
 
-        vm->state = VIR_DOMAIN_PAUSED;
+        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_IOERROR);
         lifecycleEvent = virDomainEventNewFromObj(vm,
                                                   VIR_DOMAIN_EVENT_SUSPENDED,
                                                   VIR_DOMAIN_EVENT_SUSPENDED_IOERROR);
@@ -1816,7 +1819,7 @@ qemuProcessPrepareMonitorChr(struct qemud_driver *driver,
 
 int
 qemuProcessStartCPUs(struct qemud_driver *driver, virDomainObjPtr vm,
-                     virConnectPtr conn)
+                     virConnectPtr conn, virDomainRunningReason reason)
 {
     int ret;
     qemuDomainObjPrivatePtr priv = vm->privateData;
@@ -1824,27 +1827,32 @@ qemuProcessStartCPUs(struct qemud_driver *driver, virDomainObjPtr vm,
     qemuDomainObjEnterMonitorWithDriver(driver, vm);
     ret = qemuMonitorStartCPUs(priv->mon, conn);
     qemuDomainObjExitMonitorWithDriver(driver, vm);
-    if (ret == 0) {
-        vm->state = VIR_DOMAIN_RUNNING;
-    }
+
+    if (ret == 0)
+        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
 
     return ret;
 }
 
 
-int qemuProcessStopCPUs(struct qemud_driver *driver, virDomainObjPtr vm)
+int qemuProcessStopCPUs(struct qemud_driver *driver, virDomainObjPtr vm,
+                        virDomainPausedReason reason)
 {
     int ret;
-    int oldState = vm->state;
+    int oldState;
+    int oldReason;
     qemuDomainObjPrivatePtr priv = vm->privateData;
 
-    vm->state = VIR_DOMAIN_PAUSED;
+    oldState = virDomainObjGetState(vm, &oldReason);
+    virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, reason);
+
     qemuDomainObjEnterMonitorWithDriver(driver, vm);
     ret = qemuMonitorStopCPUs(priv->mon);
     qemuDomainObjExitMonitorWithDriver(driver, vm);
-    if (ret < 0) {
-        vm->state = oldState;
-    }
+
+    if (ret < 0)
+        virDomainObjSetState(vm, oldState, oldReason);
+
     return ret;
 }
 
@@ -1950,7 +1958,7 @@ error:
         /* We can't get the monitor back, so must kill the VM
          * to remove danger of it ending up running twice if
          * user tries to start it again later */
-        qemuProcessStop(driver, obj, 0);
+        qemuProcessStop(driver, obj, 0, VIR_DOMAIN_SHUTOFF_FAILED);
         if (!obj->persistent)
             virDomainRemoveInactive(&driver->domains, obj);
         else
@@ -2289,7 +2297,6 @@ int qemuProcessStart(virConnectPtr conn,
 
     if (migrateFrom)
         start_paused = true;
-    vm->state = start_paused ? VIR_DOMAIN_PAUSED : VIR_DOMAIN_RUNNING;
 
     if (ret == -1) /* The VM failed to start; tear filters before taps */
         virDomainConfVMNWFilterTeardown(vm);
@@ -2333,15 +2340,20 @@ int qemuProcessStart(virConnectPtr conn,
     if (!start_paused) {
         VIR_DEBUG0("Starting domain CPUs");
         /* Allow the CPUS to start executing */
-        if (qemuProcessStartCPUs(driver, vm, conn) < 0) {
+        if (qemuProcessStartCPUs(driver, vm, conn,
+                                 VIR_DOMAIN_RUNNING_BOOTED) < 0) {
             if (virGetLastError() == NULL)
                 qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("resume operation failed"));
             goto cleanup;
         }
+    } else {
+        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
+                             migrateFrom ?
+                             VIR_DOMAIN_PAUSED_MIGRATION :
+                             VIR_DOMAIN_PAUSED_USER);
     }
 
-
     VIR_DEBUG0("Writing domain status to disk");
     if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
         goto cleanup;
@@ -2357,7 +2369,7 @@ cleanup:
      * pretend we never started it */
     virCommandFree(cmd);
     VIR_FORCE_CLOSE(logfile);
-    qemuProcessStop(driver, vm, 0);
+    qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_FAILED);
 
     return -1;
 }
@@ -2365,7 +2377,8 @@ cleanup:
 
 void qemuProcessStop(struct qemud_driver *driver,
                      virDomainObjPtr vm,
-                     int migrated)
+                     int migrated,
+                     virDomainShutoffReason reason)
 {
     int ret;
     int retries = 0;
@@ -2523,7 +2536,7 @@ retry:
     vm->taint = 0;
     vm->pid = -1;
     vm->def->id = -1;
-    vm->state = VIR_DOMAIN_SHUTOFF;
+    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
     VIR_FREE(priv->vcpupids);
     priv->nvcpupids = 0;
     qemuCapsFree(priv->qemuCaps);
diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h
index f1ab599..40b386d 100644
--- a/src/qemu/qemu_process.h
+++ b/src/qemu/qemu_process.h
@@ -28,8 +28,13 @@ int qemuProcessPrepareMonitorChr(struct qemud_driver *driver,
                                  virDomainChrSourceDefPtr monConfig,
                                  const char *vm);
 
-int qemuProcessStartCPUs(struct qemud_driver *driver, virDomainObjPtr vm, virConnectPtr conn);
-int qemuProcessStopCPUs(struct qemud_driver *driver, virDomainObjPtr vm);
+int qemuProcessStartCPUs(struct qemud_driver *driver,
+                         virDomainObjPtr vm,
+                         virConnectPtr conn,
+                         virDomainRunningReason reason);
+int qemuProcessStopCPUs(struct qemud_driver *driver,
+                        virDomainObjPtr vm,
+                        virDomainPausedReason reason);
 
 void qemuProcessAutostartAll(struct qemud_driver *driver);
 void qemuProcessReconnectAll(virConnectPtr conn, struct qemud_driver *driver);
@@ -47,6 +52,7 @@ int qemuProcessStart(virConnectPtr conn,
 
 void qemuProcessStop(struct qemud_driver *driver,
                      virDomainObjPtr vm,
-                     int migrated);
+                     int migrated,
+                     virDomainShutoffReason reason);
 
 #endif /* __QEMU_PROCESS_H__ */
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 4ec2852..ca79309 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -459,7 +459,8 @@ cleanup:
 
 static void
 testDomainShutdownState(virDomainPtr domain,
-                        virDomainObjPtr privdom)
+                        virDomainObjPtr privdom,
+                        virDomainShutoffReason reason)
 {
     if (privdom->newDef) {
         virDomainDefFree(privdom->def);
@@ -467,7 +468,7 @@ testDomainShutdownState(virDomainPtr domain,
         privdom->newDef = NULL;
     }
 
-    privdom->state = VIR_DOMAIN_SHUTOFF;
+    virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF, reason);
     privdom->def->id = -1;
     if (domain)
         domain->id = -1;
@@ -476,7 +477,8 @@ testDomainShutdownState(virDomainPtr domain,
 /* Set up domain runtime state */
 static int
 testDomainStartState(virConnectPtr conn,
-                     virDomainObjPtr dom)
+                     virDomainObjPtr dom,
+                     virDomainRunningReason reason)
 {
     testConnPtr privconn = conn->privateData;
     int ret = -1;
@@ -484,7 +486,7 @@ testDomainStartState(virConnectPtr conn,
     if (testDomainUpdateVCPUs(conn, dom, dom->def->vcpus, 1) < 0)
         goto cleanup;
 
-    dom->state = VIR_DOMAIN_RUNNING;
+    virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, reason);
     dom->def->id = privconn->nextDomID++;
 
     if (virDomainObjSetDefTransient(privconn->caps, dom, false) < 0) {
@@ -494,7 +496,7 @@ testDomainStartState(virConnectPtr conn,
     ret = 0;
 cleanup:
     if (ret < 0)
-        testDomainShutdownState(NULL, dom);
+        testDomainShutdownState(NULL, dom, VIR_DOMAIN_SHUTOFF_FAILED);
     return ret;
 }
 
@@ -565,7 +567,7 @@ static int testOpenDefault(virConnectPtr conn) {
     domdef = NULL;
 
     domobj->persistent = 1;
-    if (testDomainStartState(conn, domobj) < 0) {
+    if (testDomainStartState(conn, domobj, VIR_DOMAIN_RUNNING_BOOTED) < 0) {
         virDomainObjUnlock(domobj);
         goto error;
     }
@@ -925,7 +927,7 @@ static int testOpenFromFile(virConnectPtr conn,
         }
 
         dom->persistent = 1;
-        if (testDomainStartState(conn, dom) < 0) {
+        if (testDomainStartState(conn, dom, VIR_DOMAIN_RUNNING_BOOTED) < 0) {
             virDomainObjUnlock(dom);
             goto error;
         }
@@ -1327,7 +1329,7 @@ testDomainCreateXML(virConnectPtr conn, const char *xml,
         goto cleanup;
     def = NULL;
 
-    if (testDomainStartState(conn, dom) < 0)
+    if (testDomainStartState(conn, dom, VIR_DOMAIN_RUNNING_BOOTED) < 0)
         goto cleanup;
 
     event = virDomainEventNewFromObj(dom,
@@ -1457,7 +1459,7 @@ static int testDestroyDomain (virDomainPtr domain)
         goto cleanup;
     }
 
-    testDomainShutdownState(domain, privdom);
+    testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_DESTROYED);
     event = virDomainEventNewFromObj(privdom,
                                      VIR_DOMAIN_EVENT_STOPPED,
                                      VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
@@ -1495,13 +1497,14 @@ static int testResumeDomain (virDomainPtr domain)
         goto cleanup;
     }
 
-    if (privdom->state != VIR_DOMAIN_PAUSED) {
+    if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_PAUSED) {
         testError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not paused"),
                   domain->name);
         goto cleanup;
     }
 
-    privdom->state = VIR_DOMAIN_RUNNING;
+    virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
+                         VIR_DOMAIN_RUNNING_UNPAUSED);
     event = virDomainEventNewFromObj(privdom,
                                      VIR_DOMAIN_EVENT_RESUMED,
                                      VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
@@ -1523,6 +1526,7 @@ static int testPauseDomain (virDomainPtr domain)
     testConnPtr privconn = domain->conn->privateData;
     virDomainObjPtr privdom;
     virDomainEventPtr event = NULL;
+    int state;
     int ret = -1;
 
     testDriverLock(privconn);
@@ -1535,14 +1539,14 @@ static int testPauseDomain (virDomainPtr domain)
         goto cleanup;
     }
 
-    if (privdom->state == VIR_DOMAIN_SHUTOFF ||
-        privdom->state == VIR_DOMAIN_PAUSED) {
+    state = virDomainObjGetState(privdom, NULL);
+    if (state == VIR_DOMAIN_SHUTOFF || state == VIR_DOMAIN_PAUSED) {
         testError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not running"),
                   domain->name);
         goto cleanup;
     }
 
-    privdom->state = VIR_DOMAIN_PAUSED;
+    virDomainObjSetState(privdom, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
     event = virDomainEventNewFromObj(privdom,
                                      VIR_DOMAIN_EVENT_SUSPENDED,
                                      VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
@@ -1576,13 +1580,13 @@ static int testShutdownDomain (virDomainPtr domain)
         goto cleanup;
     }
 
-    if (privdom->state == VIR_DOMAIN_SHUTOFF) {
+    if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
         testError(VIR_ERR_INTERNAL_ERROR,
                   _("domain '%s' not running"), domain->name);
         goto cleanup;
     }
 
-    testDomainShutdownState(domain, privdom);
+    testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
     event = virDomainEventNewFromObj(privdom,
                                      VIR_DOMAIN_EVENT_STOPPED,
                                      VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
@@ -1621,31 +1625,38 @@ static int testRebootDomain (virDomainPtr domain,
         goto cleanup;
     }
 
-    privdom->state = VIR_DOMAIN_SHUTDOWN;
+    virDomainObjSetState(privdom, VIR_DOMAIN_SHUTDOWN,
+                         VIR_DOMAIN_SHUTDOWN_USER);
+
     switch (privdom->def->onReboot) {
     case VIR_DOMAIN_LIFECYCLE_DESTROY:
-        privdom->state = VIR_DOMAIN_SHUTOFF;
+        virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
+                             VIR_DOMAIN_SHUTOFF_SHUTDOWN);
         break;
 
     case VIR_DOMAIN_LIFECYCLE_RESTART:
-        privdom->state = VIR_DOMAIN_RUNNING;
+        virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
+                             VIR_DOMAIN_RUNNING_BOOTED);
         break;
 
     case VIR_DOMAIN_LIFECYCLE_PRESERVE:
-        privdom->state = VIR_DOMAIN_SHUTOFF;
+        virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
+                             VIR_DOMAIN_SHUTOFF_SHUTDOWN);
         break;
 
     case VIR_DOMAIN_LIFECYCLE_RESTART_RENAME:
-        privdom->state = VIR_DOMAIN_RUNNING;
+        virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
+                             VIR_DOMAIN_RUNNING_BOOTED);
         break;
 
     default:
-        privdom->state = VIR_DOMAIN_SHUTOFF;
+        virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
+                             VIR_DOMAIN_SHUTOFF_SHUTDOWN);
         break;
     }
 
-    if (privdom->state == VIR_DOMAIN_SHUTOFF) {
-        testDomainShutdownState(domain, privdom);
+    if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
+        testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
         event = virDomainEventNewFromObj(privdom,
                                          VIR_DOMAIN_EVENT_STOPPED,
                                          VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
@@ -1691,7 +1702,7 @@ static int testGetDomainInfo (virDomainPtr domain,
         goto cleanup;
     }
 
-    info->state = privdom->state;
+    info->state = virDomainObjGetState(privdom, NULL);
     info->memory = privdom->def->mem.cur_balloon;
     info->maxMem = privdom->def->mem.max_balloon;
     info->nrVirtCpu = privdom->def->vcpus;
@@ -1726,10 +1737,7 @@ testDomainGetState(virDomainPtr domain,
         goto cleanup;
     }
 
-    *state = privdom->state;
-    if (reason)
-        *reason = 0;
-
+    *state = virDomainObjGetState(privdom, reason);
     ret = 0;
 
 cleanup:
@@ -1804,7 +1812,7 @@ static int testDomainSave(virDomainPtr domain,
     }
     fd = -1;
 
-    testDomainShutdownState(domain, privdom);
+    testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SAVED);
     event = virDomainEventNewFromObj(privdom,
                                      VIR_DOMAIN_EVENT_STOPPED,
                                      VIR_DOMAIN_EVENT_STOPPED_SAVED);
@@ -1902,7 +1910,7 @@ static int testDomainRestore(virConnectPtr conn,
         goto cleanup;
     def = NULL;
 
-    if (testDomainStartState(conn, dom) < 0)
+    if (testDomainStartState(conn, dom, VIR_DOMAIN_RUNNING_RESTORED) < 0)
         goto cleanup;
 
     event = virDomainEventNewFromObj(dom,
@@ -1961,7 +1969,7 @@ static int testDomainCoreDump(virDomainPtr domain,
     }
 
     if (flags & VIR_DUMP_CRASH) {
-        testDomainShutdownState(domain, privdom);
+        testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_CRASHED);
         event = virDomainEventNewFromObj(privdom,
                                          VIR_DOMAIN_EVENT_STOPPED,
                                          VIR_DOMAIN_EVENT_STOPPED_CRASHED);
@@ -2514,13 +2522,14 @@ static int testDomainCreateWithFlags(virDomainPtr domain, unsigned int flags) {
         goto cleanup;
     }
 
-    if (privdom->state != VIR_DOMAIN_SHUTOFF) {
+    if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_SHUTOFF) {
         testError(VIR_ERR_INTERNAL_ERROR,
                   _("Domain '%s' is already running"), domain->name);
         goto cleanup;
     }
 
-    if (testDomainStartState(domain->conn, privdom) < 0)
+    if (testDomainStartState(domain->conn, privdom,
+                             VIR_DOMAIN_RUNNING_BOOTED) < 0)
         goto cleanup;
     domain->id = privdom->def->id;
 
@@ -2557,13 +2566,12 @@ static int testDomainUndefine(virDomainPtr domain) {
         goto cleanup;
     }
 
-    if (privdom->state != VIR_DOMAIN_SHUTOFF) {
+    if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_SHUTOFF) {
         testError(VIR_ERR_INTERNAL_ERROR,
                   _("Domain '%s' is still running"), domain->name);
         goto cleanup;
     }
 
-    privdom->state = VIR_DOMAIN_SHUTOFF;
     event = virDomainEventNewFromObj(privdom,
                                      VIR_DOMAIN_EVENT_UNDEFINED,
                                      VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index e6fe019..eebf4af 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -133,7 +133,8 @@ static int umlStartVMDaemon(virConnectPtr conn,
 
 static void umlShutdownVMDaemon(virConnectPtr conn,
                                 struct uml_driver *driver,
-                                virDomainObjPtr vm);
+                                virDomainObjPtr vm,
+                                virDomainShutoffReason reason);
 
 
 static int umlMonitorCommand(const struct uml_driver *driver,
@@ -305,7 +306,7 @@ reread:
                 continue;
             }
 
-            umlShutdownVMDaemon(NULL, driver, dom);
+            umlShutdownVMDaemon(NULL, driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
         } else if (e->mask & (IN_CREATE | IN_MODIFY)) {
             VIR_DEBUG("Got inotify domain startup '%s'", name);
             if (virDomainObjIsActive(dom)) {
@@ -319,14 +320,17 @@ reread:
             }
 
             dom->def->id = driver->nextvmid++;
-            dom->state = VIR_DOMAIN_RUNNING;
+            virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
+                                 VIR_DOMAIN_RUNNING_BOOTED);
 
             if (umlOpenMonitor(driver, dom) < 0) {
                 VIR_WARN0("Could not open monitor for new domain");
-                umlShutdownVMDaemon(NULL, driver, dom);
+                umlShutdownVMDaemon(NULL, driver, dom,
+                                    VIR_DOMAIN_SHUTOFF_FAILED);
             } else if (umlIdentifyChrPTY(driver, dom) < 0) {
                 VIR_WARN0("Could not identify charater devices for new domain");
-                umlShutdownVMDaemon(NULL, driver, dom);
+                umlShutdownVMDaemon(NULL, driver, dom,
+                                    VIR_DOMAIN_SHUTOFF_FAILED);
             }
         }
         virDomainObjUnlock(dom);
@@ -515,7 +519,7 @@ umlShutdownOneVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
 
     virDomainObjLock(dom);
     if (virDomainObjIsActive(dom))
-        umlShutdownVMDaemon(NULL, driver, dom);
+        umlShutdownVMDaemon(NULL, driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
     virDomainObjUnlock(dom);
 }
 
@@ -907,7 +911,8 @@ cleanup:
 
 static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
                                 struct uml_driver *driver ATTRIBUTE_UNUSED,
-                                virDomainObjPtr vm)
+                                virDomainObjPtr vm,
+                                virDomainShutoffReason reason)
 {
     int ret;
     umlDomainObjPrivatePtr priv = vm->privateData;
@@ -926,7 +931,7 @@ static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
 
     vm->pid = -1;
     vm->def->id = -1;
-    vm->state = VIR_DOMAIN_SHUTOFF;
+    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
 
     virDomainConfVMNWFilterTeardown(vm);
     umlCleanupTapDevices(conn, vm);
@@ -1345,7 +1350,7 @@ static int umlDomainDestroy(virDomainPtr dom) {
         goto cleanup;
     }
 
-    umlShutdownVMDaemon(dom->conn, driver, vm);
+    umlShutdownVMDaemon(dom->conn, driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
     if (!vm->persistent) {
         virDomainRemoveInactive(&driver->domains,
                                 vm);
@@ -1498,7 +1503,7 @@ static int umlDomainGetInfo(virDomainPtr dom,
         goto cleanup;
     }
 
-    info->state = vm->state;
+    info->state = virDomainObjGetState(vm, NULL);
 
     if (!virDomainObjIsActive(vm)) {
         info->cpuTime = 0;
@@ -1544,10 +1549,7 @@ umlDomainGetState(virDomainPtr dom,
         goto cleanup;
     }
 
-    *state = vm->state;
-    if (reason)
-        *reason = 0;
-
+    *state = virDomainObjGetState(vm, reason);
     ret = 0;
 
 cleanup:
diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c
index 6339248..4ec33ae 100644
--- a/src/vmware/vmware_conf.c
+++ b/src/vmware/vmware_conf.c
@@ -185,7 +185,8 @@ vmwareLoadDomains(struct vmware_driver *driver)
         if ((vm->def->id = vmwareExtractPid(vmxPath)) < 0)
             goto cleanup;
         /* vmrun list only reports running vms */
-        vm->state = VIR_DOMAIN_RUNNING;
+        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
+                             VIR_DOMAIN_RUNNING_UNKNOWN);
         vm->persistent = 1;
 
         virDomainObjUnlock(vm);
diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c
index 743e136..bd3771d 100644
--- a/src/vmware/vmware_driver.c
+++ b/src/vmware/vmware_driver.c
@@ -178,7 +178,9 @@ vmwareGetVersion(virConnectPtr conn, unsigned long *version)
 }
 
 static int
-vmwareStopVM(struct vmware_driver *driver, virDomainObjPtr vm)
+vmwareStopVM(struct vmware_driver *driver,
+             virDomainObjPtr vm,
+             virDomainShutoffReason reason)
 {
     const char *cmd[] = {
         VMRUN, "-T", PROGRAM_SENTINAL, "stop",
@@ -193,7 +195,7 @@ vmwareStopVM(struct vmware_driver *driver, virDomainObjPtr vm)
     }
 
     vm->def->id = -1;
-    vm->state = VIR_DOMAIN_SHUTOFF;
+    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
 
     return 0;
 }
@@ -207,7 +209,7 @@ vmwareStartVM(struct vmware_driver *driver, virDomainObjPtr vm)
     };
     const char *vmxPath = ((vmwareDomainPtr) vm->privateData)->vmxPath;
 
-    if (vm->state != VIR_DOMAIN_SHUTOFF) {
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_SHUTOFF) {
         vmwareError(VIR_ERR_OPERATION_INVALID, "%s",
                     _("domain is not in shutoff state"));
         return -1;
@@ -225,11 +227,11 @@ vmwareStartVM(struct vmware_driver *driver, virDomainObjPtr vm)
     }
 
     if ((vm->def->id = vmwareExtractPid(vmxPath)) < 0) {
-        vmwareStopVM(driver, vm);
+        vmwareStopVM(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
         return -1;
     }
 
-    vm->state = VIR_DOMAIN_RUNNING;
+    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
 
     return 0;
 }
@@ -322,13 +324,13 @@ vmwareDomainShutdown(virDomainPtr dom)
         goto cleanup;
     }
 
-    if (vm->state != VIR_DOMAIN_RUNNING) {
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
         vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
                     _("domain is not in running state"));
         goto cleanup;
     }
 
-    if (vmwareStopVM(driver, vm) < 0)
+    if (vmwareStopVM(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0)
         goto cleanup;
 
     if (!vm->persistent) {
@@ -375,7 +377,7 @@ vmwareDomainSuspend(virDomainPtr dom)
 
     vmwareSetSentinal(cmd, vmw_types[driver->type]);
     vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);
-    if (vm->state != VIR_DOMAIN_RUNNING) {
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
         vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
                     _("domain is not in running state"));
         goto cleanup;
@@ -384,7 +386,7 @@ vmwareDomainSuspend(virDomainPtr dom)
     if (virRun(cmd, NULL) < 0)
         goto cleanup;
 
-    vm->state = VIR_DOMAIN_PAUSED;
+    virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
     ret = 0;
 
   cleanup:
@@ -424,7 +426,7 @@ vmwareDomainResume(virDomainPtr dom)
 
     vmwareSetSentinal(cmd, vmw_types[driver->type]);
     vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);
-    if (vm->state != VIR_DOMAIN_PAUSED) {
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
         vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
                     _("domain is not in suspend state"));
         goto cleanup;
@@ -433,7 +435,7 @@ vmwareDomainResume(virDomainPtr dom)
     if (virRun(cmd, NULL) < 0)
         goto cleanup;
 
-    vm->state = VIR_DOMAIN_RUNNING;
+    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNPAUSED);
     ret = 0;
 
   cleanup:
@@ -470,7 +472,7 @@ vmwareDomainReboot(virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED)
     vmwareSetSentinal(cmd, vmxPath);
 
 
-    if (vm->state != VIR_DOMAIN_RUNNING) {
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
         vmwareError(VIR_ERR_INTERNAL_ERROR, "%s",
                     _("domain is not in running state"));
         goto cleanup;
@@ -883,7 +885,7 @@ vmwareDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
         goto cleanup;
     }
 
-    info->state = vm->state;
+    info->state = virDomainObjGetState(vm, NULL);
     info->cpuTime = 0;
     info->maxMem = vm->def->mem.max_balloon;
     info->memory = vm->def->mem.cur_balloon;
@@ -918,10 +920,7 @@ vmwareDomainGetState(virDomainPtr dom,
         goto cleanup;
     }
 
-    *state = vm->state;
-    if (reason)
-        *reason = 0;
-
+    *state = virDomainObjGetState(vm, reason);
     ret = 0;
 
   cleanup:
-- 
1.7.5.rc3




More information about the libvir-list mailing list