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

Daniel P. Berrange berrange at redhat.com
Fri May 13 09:55:42 UTC 2011


On Tue, May 10, 2011 at 03:39:10PM +0200, Jiri Denemark wrote:
> 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:

ACK

Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list