[libvirt] [PATCH 0/8] Introduce virDomainGetState API

This new API solves several problems: - calling virDomainGetInfo for just getting domain status is an overkill since it may result in sending requests to guest OS - since virDomainGetInfo can hang when guest OS is not responding and it is used by virsh list, listing domains can hang - virDomainGetState provides additional info about what action led to domain's current state, which can be used instead of listening to domain events I'm undecided whether this API should support flags parameter or not. On one hand the API seems simple and focused enough not to allow any fine-tuning but on the other hand we've already had too many issues with APIs that didn't support flags. Another thing is that it would be nice to somehow report that a domain is running but libvirt is currently waiting for reply from hypervisor and is not able to do anything else with the domain until it gets the reply. In case of qemu driver, this translates to the driver being stuck in comunication with qemu monitor. I'm not sure if we should somehow integrate this into virDomainGetState API. Probably not. Jiri Denemark (8): virDomainGetState public API Internal driver API for virDomainGetState virDomainGetState public API implementation Wire protocol format and dispatcher for virDomainGetState virsh: Prefer virDomainGetState over virDomainGetInfo remote: Implement virDomainGetState Implement basic virDomainGetState in all drivers Implement domain state reason daemon/remote.c | 33 ++++++ daemon/remote_dispatch_prototypes.h | 8 ++ daemon/remote_dispatch_table.h | 5 + include/libvirt/libvirt.h.in | 55 ++++++++++ python/generator.py | 1 + python/libvirt-override-api.xml | 5 + python/libvirt-override.c | 26 +++++ src/conf/domain_conf.c | 163 ++++++++++++++++++++++++++++- src/conf/domain_conf.h | 26 +++++- src/driver.h | 5 + src/esx/esx_driver.c | 53 ++++++++++ src/libvirt.c | 47 +++++++++ src/libvirt_private.syms | 4 + src/libvirt_public.syms | 5 + src/libxl/libxl_driver.c | 75 ++++++++++--- src/lxc/lxc_driver.c | 76 ++++++++++---- src/openvz/openvz_conf.c | 16 ++- src/openvz/openvz_driver.c | 52 ++++++++-- src/phyp/phyp_driver.c | 11 ++ src/qemu/qemu_driver.c | 90 ++++++++++++----- src/qemu/qemu_migration.c | 24 +++-- src/qemu/qemu_process.c | 61 +++++++----- src/qemu/qemu_process.h | 12 ++- src/remote/remote_driver.c | 30 ++++++ src/remote/remote_protocol.c | 20 ++++ src/remote/remote_protocol.h | 16 +++ src/remote/remote_protocol.x | 12 ++- src/remote_protocol-structs | 7 ++ src/test/test_driver.c | 102 +++++++++++++------ src/uml/uml_driver.c | 53 ++++++++-- src/vbox/vbox_tmpl.c | 55 ++++++++++ src/vmware/vmware_conf.c | 3 +- src/vmware/vmware_driver.c | 55 ++++++++--- src/xen/xen_driver.c | 17 +++ src/xen/xen_driver.h | 1 + src/xen/xen_hypervisor.c | 33 ++++++ src/xen/xen_hypervisor.h | 4 + src/xen/xen_inotify.c | 1 + src/xen/xend_internal.c | 96 +++++++++++++----- src/xen/xend_internal.h | 1 + src/xen/xm_internal.c | 18 +++ src/xen/xm_internal.h | 1 + src/xen/xs_internal.c | 31 ++++++ src/xen/xs_internal.h | 3 + src/xenapi/xenapi_driver.c | 44 ++++++++ tools/virsh.c | 195 +++++++++++++++++++++++++++++------ 46 files changed, 1415 insertions(+), 236 deletions(-) -- 1.7.5.rc3

This API is supposed to replace virDomainGetInfo when the only purpose of calling it is getting current domain status. --- include/libvirt/libvirt.h.in | 55 +++++++++++++++++++++++++++++++++++++++ python/generator.py | 1 + python/libvirt-override-api.xml | 5 +++ python/libvirt-override.c | 26 ++++++++++++++++++ src/libvirt_public.syms | 5 +++ 5 files changed, 92 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 5783303..0e64140 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -89,6 +89,58 @@ typedef enum { VIR_DOMAIN_CRASHED = 6 /* the domain is crashed */ } virDomainState; +typedef enum { + VIR_DOMAIN_NOSTATE_UNKNOWN = 0, +} virDomainNostateReason; + +typedef enum { + VIR_DOMAIN_RUNNING_UNKNOWN = 0, + VIR_DOMAIN_RUNNING_BOOTED = 1, /* normal startup from boot */ + VIR_DOMAIN_RUNNING_MIGRATED = 2, /* migrated from another host */ + VIR_DOMAIN_RUNNING_RESTORED = 3, /* restored from a state file */ + VIR_DOMAIN_RUNNING_FROM_SNAPSHOT = 4, /* restored from snapshot */ + VIR_DOMAIN_RUNNING_UNPAUSED = 5, /* returned from paused state */ + VIR_DOMAIN_RUNNING_MIGRATION_CANCELED = 6, /* returned from migration */ + VIR_DOMAIN_RUNNING_SAVE_CANCELED = 7, /* returned from failed save process */ +} virDomainRunningReason; + +typedef enum { + VIR_DOMAIN_BLOCKED_UNKNOWN = 0, /* the reason is unknown */ +} virDomainBlockedReason; + +typedef enum { + VIR_DOMAIN_PAUSED_UNKNOWN = 0, /* the reason is unknown */ + VIR_DOMAIN_PAUSED_USER = 1, /* paused on user request */ + VIR_DOMAIN_PAUSED_MIGRATION = 2, /* paused for offline migration */ + VIR_DOMAIN_PAUSED_SAVE = 3, /* paused for save */ + VIR_DOMAIN_PAUSED_DUMP = 4, /* paused for offline core dump */ + VIR_DOMAIN_PAUSED_IOERROR = 5, /* paused due to a disk I/O error */ + VIR_DOMAIN_PAUSED_WATCHDOG = 6, /* paused due to a watchdog event */ + VIR_DOMAIN_PAUSED_FROM_SNAPSHOT = 7, /* restored from a snapshot which was + * taken while domain was paused */ +} virDomainPausedReason; + +typedef enum { + VIR_DOMAIN_SHUTDOWN_UNKNOWN = 0, /* the reason is unknown */ + VIR_DOMAIN_SHUTDOWN_USER = 1, /* shutting down on user request */ +} virDomainShutdownReason; + +typedef enum { + VIR_DOMAIN_SHUTOFF_UNKNOWN = 0, /* the reason is unknown */ + VIR_DOMAIN_SHUTOFF_SHUTDOWN = 1, /* normal shutdown */ + VIR_DOMAIN_SHUTOFF_DESTROYED = 2, /* forced poweroff */ + VIR_DOMAIN_SHUTOFF_CRASHED = 3, /* domain crashed */ + VIR_DOMAIN_SHUTOFF_MIGRATED = 4, /* migrated to another host */ + VIR_DOMAIN_SHUTOFF_SAVED = 5, /* saved to a file */ + VIR_DOMAIN_SHUTOFF_FAILED = 6, /* domain failed to start */ + VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT = 7, /* restored from a snapshot which was + * taken while domain was shutoff */ +} virDomainShutoffReason; + +typedef enum { + VIR_DOMAIN_CRASHED_UNKNOWN = 0, /* crashed for unknown reason */ +} virDomainCrashedReason; + /** * virDomainInfoPtr: * @@ -674,6 +726,9 @@ int virDomainCoreDump (virDomainPtr domain, */ int virDomainGetInfo (virDomainPtr domain, virDomainInfoPtr info); +int virDomainGetState (virDomainPtr domain, + int *state, + int *reason); /* * Return scheduler type in effect 'sedf', 'credit', 'linux' diff --git a/python/generator.py b/python/generator.py index 4fa4f65..b395caf 100755 --- a/python/generator.py +++ b/python/generator.py @@ -293,6 +293,7 @@ skip_impl = ( 'virConnGetLastError', 'virGetLastError', 'virDomainGetInfo', + 'virDomainGetState', 'virDomainGetBlockInfo', 'virDomainGetJobInfo', 'virNodeGetInfo', diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index 54deeb5..3a77845 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -48,6 +48,11 @@ <return type='int *' info='the list of information or None in case of error'/> <arg name='domain' type='virDomainPtr' info='a domain object'/> </function> + <function name='virDomainGetState' file='python'> + <info>Extract domain state.</info> + <return type='int *' info='the list containing state and reason or None in case of error'/> + <arg name='domain' type='virDomainPtr' info='a domain object'/> + </function> <function name='virDomainGetBlockInfo' file='python'> <info>Extract information about a domain block device size</info> <return type='int *' info='the list of information or None in case of error'/> diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 4a9b432..795a522 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -1068,6 +1068,31 @@ libvirt_virDomainGetInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { } static PyObject * +libvirt_virDomainGetState(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) +{ + PyObject *py_retval; + int c_retval; + virDomainPtr domain; + PyObject *pyobj_domain; + int state; + int reason; + + if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetInfo", &pyobj_domain)) + return(NULL); + domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainGetState(domain, &state, &reason); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + py_retval = PyList_New(2); + PyList_SetItem(py_retval, 0, libvirt_intWrap(state)); + PyList_SetItem(py_retval, 1, libvirt_intWrap(reason)); + return(py_retval); +} + +static PyObject * libvirt_virDomainGetBlockInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; int c_retval; @@ -3527,6 +3552,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virConnectDomainEventRegisterAny", libvirt_virConnectDomainEventRegisterAny, METH_VARARGS, NULL}, {(char *) "virConnectDomainEventDeregisterAny", libvirt_virConnectDomainEventDeregisterAny, METH_VARARGS, NULL}, {(char *) "virDomainGetInfo", libvirt_virDomainGetInfo, METH_VARARGS, NULL}, + {(char *) "virDomainGetState", libvirt_virDomainGetState, METH_VARARGS, NULL}, {(char *) "virDomainGetBlockInfo", libvirt_virDomainGetBlockInfo, METH_VARARGS, NULL}, {(char *) "virNodeGetInfo", libvirt_virNodeGetInfo, METH_VARARGS, NULL}, {(char *) "virDomainGetUUID", libvirt_virDomainGetUUID, METH_VARARGS, NULL}, diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index b4aed41..6011487 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -436,4 +436,9 @@ LIBVIRT_0.9.0 { virStorageVolUpload; } LIBVIRT_0.8.8; +LIBVIRT_0.9.1 { + global: + virDomainGetState; +} LIBVIRT_0.9.0; + # .... define new API here using predicted next version number .... -- 1.7.5.rc3

On 05/04/2011 08:45 AM, Jiri Denemark wrote:
This API is supposed to replace virDomainGetInfo when the only purpose of calling it is getting current domain status. @@ -674,6 +726,9 @@ int virDomainCoreDump (virDomainPtr domain, */ int virDomainGetInfo (virDomainPtr domain, virDomainInfoPtr info); +int virDomainGetState (virDomainPtr domain, + int *state, + int *reason);
Definitely add the unsigned int flags argument. I'm not sure yet whether we want to pass a struct instead of two int* arguments; if nothing else, a flag could let us treat the argument as a union of different structs, and return a different struct of information according to which flag was requested.
+++ b/src/libvirt_public.syms @@ -436,4 +436,9 @@ LIBVIRT_0.9.0 { virStorageVolUpload; } LIBVIRT_0.8.8;
+LIBVIRT_0.9.1 {
0.9.2
+ global: + virDomainGetState; +} LIBVIRT_0.9.0; + # .... define new API here using predicted next version number ....
-- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Wed, May 04, 2011 at 10:45:33 -0600, Eric Blake wrote:
On 05/04/2011 08:45 AM, Jiri Denemark wrote:
This API is supposed to replace virDomainGetInfo when the only purpose of calling it is getting current domain status. @@ -674,6 +726,9 @@ int virDomainCoreDump (virDomainPtr domain, */ int virDomainGetInfo (virDomainPtr domain, virDomainInfoPtr info); +int virDomainGetState (virDomainPtr domain, + int *state, + int *reason);
Definitely add the unsigned int flags argument. I'm not sure yet whether we want to pass a struct instead of two int* arguments; if nothing else, a flag could let us treat the argument as a union of different structs, and return a different struct of information according to which flag was requested.
Hmm, this sounds like a bad design to me. If we need to return different struct, we should create a new API for that.
+++ b/src/libvirt_public.syms @@ -436,4 +436,9 @@ LIBVIRT_0.9.0 { virStorageVolUpload; } LIBVIRT_0.8.8;
+LIBVIRT_0.9.1 {
0.9.2
Ah, sure. Jirka

--- src/driver.h | 5 +++++ src/esx/esx_driver.c | 1 + src/libxl/libxl_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 1 + src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/vmware/vmware_driver.c | 1 + src/xen/xen_driver.c | 1 + src/xen/xen_driver.h | 1 + src/xen/xen_hypervisor.c | 1 + src/xen/xen_inotify.c | 1 + src/xen/xend_internal.c | 1 + src/xen/xm_internal.c | 1 + src/xen/xs_internal.c | 1 + src/xenapi/xenapi_driver.c | 1 + 20 files changed, 24 insertions(+), 0 deletions(-) diff --git a/src/driver.h b/src/driver.h index a8b79e6..d9898d4 100644 --- a/src/driver.h +++ b/src/driver.h @@ -166,6 +166,10 @@ typedef int (*virDrvDomainGetInfo) (virDomainPtr domain, virDomainInfoPtr info); typedef int + (*virDrvDomainGetState) (virDomainPtr domain, + int *state, + int *reason); +typedef int (*virDrvDomainSave) (virDomainPtr domain, const char *to); typedef int @@ -563,6 +567,7 @@ struct _virDriver { virDrvDomainSetBlkioParameters domainSetBlkioParameters; virDrvDomainGetBlkioParameters domainGetBlkioParameters; virDrvDomainGetInfo domainGetInfo; + virDrvDomainGetState domainGetState; virDrvDomainSave domainSave; virDrvDomainRestore domainRestore; virDrvDomainCoreDump domainCoreDump; diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 1f8f90b..543ebe6 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -4596,6 +4596,7 @@ static virDriver esxDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ esxDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 247d78e..db6f99c 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -2672,6 +2672,7 @@ static virDriver libxlDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ libxlDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index e905302..bc96ed4 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2830,6 +2830,7 @@ static virDriver lxcDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ lxcDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 4af28e9..268e752 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1591,6 +1591,7 @@ static virDriver openvzDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ openvzDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index ebd4a8a..fb365ba 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -3752,6 +3752,7 @@ static virDriver phypDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ phypDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 7132837..549cb2f 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7140,6 +7140,7 @@ static virDriver qemuDriver = { qemuDomainSetBlkioParameters, /* domainSetBlkioParameters */ qemuDomainGetBlkioParameters, /* domainGetBlkioParameters */ qemudDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ qemudDomainSave, /* domainSave */ qemuDomainRestore, /* domainRestore */ qemudDomainCoreDump, /* domainCoreDump */ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index e30780c..9796bb5 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -11222,6 +11222,7 @@ static virDriver remote_driver = { remoteDomainSetBlkioParameters, /* domainSetBlkioParameters */ remoteDomainGetBlkioParameters, /* domainGetBlkioParameters */ remoteDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ remoteDomainSave, /* domainSave */ remoteDomainRestore, /* domainRestore */ remoteDomainCoreDump, /* domainCoreDump */ diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 0978214..6f4ae75 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5371,6 +5371,7 @@ static virDriver testDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ testGetDomainInfo, /* domainGetInfo */ + NULL, /* domainGetState */ testDomainSave, /* domainSave */ testDomainRestore, /* domainRestore */ testDomainCoreDump, /* domainCoreDump */ diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 33849a0..6852a16 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2177,6 +2177,7 @@ static virDriver umlDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ umlDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 8241d34..d4a8924 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -8566,6 +8566,7 @@ virDriver NAME(Driver) = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ vboxDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ vboxDomainSave, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index bbfb1a4..c6c92c6 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -931,6 +931,7 @@ static virDriver vmwareDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ vmwareDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index dd94fbc..1646828 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -2132,6 +2132,7 @@ static virDriver xenUnifiedDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ xenUnifiedDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ xenUnifiedDomainSave, /* domainSave */ xenUnifiedDomainRestore, /* domainRestore */ xenUnifiedDomainCoreDump, /* domainCoreDump */ diff --git a/src/xen/xen_driver.h b/src/xen/xen_driver.h index 58b8561..6619494 100644 --- a/src/xen/xen_driver.h +++ b/src/xen/xen_driver.h @@ -90,6 +90,7 @@ struct xenUnifiedDriver { virDrvDomainSetMaxMemory domainSetMaxMemory; virDrvDomainSetMemory domainSetMemory; virDrvDomainGetInfo domainGetInfo; + virDrvDomainGetState domainGetState; virDrvDomainSave domainSave; virDrvDomainRestore domainRestore; virDrvDomainCoreDump domainCoreDump; diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index 9a5b41d..f5218bc 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -821,6 +821,7 @@ struct xenUnifiedDriver xenHypervisorDriver = { xenHypervisorSetMaxMemory, /* domainSetMaxMemory */ NULL, /* domainSetMemory */ xenHypervisorGetDomainInfo, /* domainGetInfo */ + NULL, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index 9dde72c..a2661a4 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -69,6 +69,7 @@ struct xenUnifiedDriver xenInotifyDriver = { NULL, /* domainSetMaxMemory */ NULL, /* domainSetMemory */ NULL, /* domainGetInfo */ + NULL, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index b608a43..1fbb8e6 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -3861,6 +3861,7 @@ struct xenUnifiedDriver xenDaemonDriver = { xenDaemonDomainSetMaxMemory, /* domainSetMaxMemory */ xenDaemonDomainSetMemory, /* domainMaxMemory */ xenDaemonDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ xenDaemonDomainSave, /* domainSave */ xenDaemonDomainRestore, /* domainRestore */ xenDaemonDomainCoreDump, /* domainCoreDump */ diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index f9f52b5..06334a4 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -100,6 +100,7 @@ struct xenUnifiedDriver xenXMDriver = { xenXMDomainSetMaxMemory, /* domainSetMaxMemory */ xenXMDomainSetMemory, /* domainMaxMemory */ xenXMDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/xen/xs_internal.c b/src/xen/xs_internal.c index c318f6c..127161c 100644 --- a/src/xen/xs_internal.c +++ b/src/xen/xs_internal.c @@ -62,6 +62,7 @@ struct xenUnifiedDriver xenStoreDriver = { NULL, /* domainSetMaxMemory */ xenStoreDomainSetMemory, /* domainSetMemory */ xenStoreGetDomainInfo, /* domainGetInfo */ + NULL, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 3fbdcc6..83417df 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -1813,6 +1813,7 @@ static virDriver xenapiDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ xenapiDomainGetInfo, /* domainGetInfo */ + NULL, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ -- 1.7.5.rc3

On 05/04/2011 08:45 AM, Jiri Denemark wrote:
--- src/driver.h | 5 +++++ src/esx/esx_driver.c | 1 + src/libxl/libxl_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 1 + src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/vmware/vmware_driver.c | 1 + src/xen/xen_driver.c | 1 + src/xen/xen_driver.h | 1 + src/xen/xen_hypervisor.c | 1 + src/xen/xen_inotify.c | 1 + src/xen/xend_internal.c | 1 + src/xen/xm_internal.c | 1 +
Hmm, I don't think we should be modifying the _xenUnifiedDriver internal callback struct in xen_driver.h, nor all the internal xen users. Rather, adding the new member to xen_driver.c should be enough to cover the code, since the stated goal in xen_driver.h is to eventually get rid of the internal callback struct and make xen_driver directly call into the appropriate helpers as necessary.
typedef int + (*virDrvDomainGetState) (virDomainPtr domain, + int *state, + int *reason);
This will obviously change according to whatever API we settle on in patch 1. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

--- src/libvirt.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 47 insertions(+), 0 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index e74e977..5cd20ce 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3173,6 +3173,53 @@ error: } /** + * virDomainGetState: + * @domain: a domain object + * @state: returned state of the domain (one of virDomainState) + * @reason: returned reason which led to @state (one of virDomain*Reason + * corresponding to the current state); it is allowed to be NULL + * + * Extract domain state. Each state can be accompanied with a reason (if known) + * which led to the state. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainGetState(virDomainPtr domain, int *state, int *reason) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "state=%p, reason=%p", state, reason); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + if (!state) { + virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + conn = domain->conn; + if (conn->driver->domainGetState) { + int ret; + ret = conn->driver->domainGetState(domain, state, reason); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + +/** * virDomainGetXMLDesc: * @domain: a domain object * @flags: an OR'ed set of virDomainXMLFlags -- 1.7.5.rc3

On 05/04/2011 08:45 AM, Jiri Denemark wrote:
--- src/libvirt.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 47 insertions(+), 0 deletions(-)
diff --git a/src/libvirt.c b/src/libvirt.c index e74e977..5cd20ce 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3173,6 +3173,53 @@ error: }
/** + * virDomainGetState: + * @domain: a domain object + * @state: returned state of the domain (one of virDomainState) + * @reason: returned reason which led to @state (one of virDomain*Reason + * corresponding to the current state); it is allowed to be NULL + * + * Extract domain state. Each state can be accompanied with a reason (if known) + * which led to the state. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainGetState(virDomainPtr domain, int *state, int *reason)
Obvious fallout from signature changes in patch 1. But the documentation looks good for what we have so far. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

--- daemon/remote.c | 33 +++++++++++++++++++++++++++++++++ daemon/remote_dispatch_prototypes.h | 8 ++++++++ daemon/remote_dispatch_table.h | 5 +++++ src/remote/remote_protocol.c | 20 ++++++++++++++++++++ src/remote/remote_protocol.h | 16 ++++++++++++++++ src/remote/remote_protocol.x | 12 +++++++++++- src/remote_protocol-structs | 7 +++++++ 7 files changed, 100 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index eedbc77..0136318 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -8738,6 +8738,39 @@ cleanup: return rv; } +static int +remoteDispatchDomainGetState(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *rerr, + remote_domain_get_state_args *args, + remote_domain_get_state_ret *ret) +{ + virDomainPtr dom = NULL; + int rv = -1; + + if (!conn) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (!(dom = get_nonnull_domain(conn, args->dom))) + goto cleanup; + + if (virDomainGetState(dom, &ret->state, &ret->reason) < 0) + goto cleanup; + + rv = 0; + +cleanup: + if (rv < 0) + remoteDispatchError(rerr); + if (dom) + virDomainFree(dom); + return rv; +} + /*----- Helpers. -----*/ diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h index cf2f38c..73d810d 100644 --- a/daemon/remote_dispatch_prototypes.h +++ b/daemon/remote_dispatch_prototypes.h @@ -306,6 +306,14 @@ static int remoteDispatchDomainGetSecurityLabel( remote_error *rerr, remote_domain_get_security_label_args *args, remote_domain_get_security_label_ret *ret); +static int remoteDispatchDomainGetState( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *rerr, + remote_domain_get_state_args *args, + remote_domain_get_state_ret *ret); static int remoteDispatchDomainGetVcpus( struct qemud_server *server, struct qemud_client *client, diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index b39f7c2..07ffd5e 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -1052,3 +1052,8 @@ .args_filter = (xdrproc_t) xdr_remote_storage_vol_download_args, .ret_filter = (xdrproc_t) xdr_void, }, +{ /* DomainGetState => 210 */ + .fn = (dispatch_fn) remoteDispatchDomainGetState, + .args_filter = (xdrproc_t) xdr_remote_domain_get_state_args, + .ret_filter = (xdrproc_t) xdr_remote_domain_get_state_ret, +}, diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 5604371..eb68c79 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -3902,6 +3902,26 @@ xdr_remote_storage_vol_download_args (XDR *xdrs, remote_storage_vol_download_arg } bool_t +xdr_remote_domain_get_state_args (XDR *xdrs, remote_domain_get_state_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_domain_get_state_ret (XDR *xdrs, remote_domain_get_state_ret *objp) +{ + + if (!xdr_int (xdrs, &objp->state)) + return FALSE; + if (!xdr_int (xdrs, &objp->reason)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_procedure (XDR *xdrs, remote_procedure *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index d9bf151..fc68ca5 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -2200,6 +2200,17 @@ struct remote_storage_vol_download_args { u_int flags; }; typedef struct remote_storage_vol_download_args remote_storage_vol_download_args; + +struct remote_domain_get_state_args { + remote_nonnull_domain dom; +}; +typedef struct remote_domain_get_state_args remote_domain_get_state_args; + +struct remote_domain_get_state_ret { + int state; + int reason; +}; +typedef struct remote_domain_get_state_ret remote_domain_get_state_ret; #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1 @@ -2413,6 +2424,7 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, + REMOTE_PROC_DOMAIN_GET_STATE = 210, }; typedef enum remote_procedure remote_procedure; @@ -2796,6 +2808,8 @@ extern bool_t xdr_remote_domain_snapshot_delete_args (XDR *, remote_domain_snap extern bool_t xdr_remote_domain_open_console_args (XDR *, remote_domain_open_console_args*); extern bool_t xdr_remote_storage_vol_upload_args (XDR *, remote_storage_vol_upload_args*); extern bool_t xdr_remote_storage_vol_download_args (XDR *, remote_storage_vol_download_args*); +extern bool_t xdr_remote_domain_get_state_args (XDR *, remote_domain_get_state_args*); +extern bool_t xdr_remote_domain_get_state_ret (XDR *, remote_domain_get_state_ret*); extern bool_t xdr_remote_procedure (XDR *, remote_procedure*); extern bool_t xdr_remote_message_type (XDR *, remote_message_type*); extern bool_t xdr_remote_message_status (XDR *, remote_message_status*); @@ -3153,6 +3167,8 @@ extern bool_t xdr_remote_domain_snapshot_delete_args (); extern bool_t xdr_remote_domain_open_console_args (); extern bool_t xdr_remote_storage_vol_upload_args (); extern bool_t xdr_remote_storage_vol_download_args (); +extern bool_t xdr_remote_domain_get_state_args (); +extern bool_t xdr_remote_domain_get_state_ret (); extern bool_t xdr_remote_procedure (); extern bool_t xdr_remote_message_type (); extern bool_t xdr_remote_message_status (); diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 675eccd..2f65bfd 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1940,6 +1940,15 @@ struct remote_storage_vol_download_args { unsigned int flags; }; +struct remote_domain_get_state_args { + remote_nonnull_domain dom; +}; + +struct remote_domain_get_state_ret { + int state; + int reason; +}; + /*----- Protocol. -----*/ @@ -2176,7 +2185,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_BLKIO_PARAMETERS = 206, REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, - REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209 + REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, + REMOTE_PROC_DOMAIN_GET_STATE = 210 /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 944553c..84859c6 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1427,6 +1427,13 @@ struct remote_storage_vol_download_args { uint64_t length; u_int flags; }; +struct remote_domain_get_state_args { + remote_nonnull_domain dom; +}; +struct remote_domain_get_state_ret { + int state; + int reason; +}; struct remote_message_header { u_int prog; u_int vers; -- 1.7.5.rc3

On 05/04/2011 08:45 AM, Jiri Denemark wrote:
--- daemon/remote.c | 33 +++++++++++++++++++++++++++++++++ daemon/remote_dispatch_prototypes.h | 8 ++++++++ daemon/remote_dispatch_table.h | 5 +++++ src/remote/remote_protocol.c | 20 ++++++++++++++++++++ src/remote/remote_protocol.h | 16 ++++++++++++++++ src/remote/remote_protocol.x | 12 +++++++++++- src/remote_protocol-structs | 7 +++++++ 7 files changed, 100 insertions(+), 1 deletions(-)
I saw no problems with this patch, but it may be affected if we change the API in patch one. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

--- tools/virsh.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 162 insertions(+), 33 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 5d8b025..6dae9fa 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -223,6 +223,8 @@ typedef struct __vshControl { int log_fd; /* log file descriptor */ char *historydir; /* readline history directory name */ char *historyfile; /* readline history file name */ + bool noGetState; /* virDomainGetState is not supported in + * current connection */ } __vshControl; typedef struct vshCmdGrp { @@ -334,7 +336,9 @@ static void vshDebug(vshControl *ctl, int level, const char *format, ...) /* XXX: add batch support */ #define vshPrint(_ctl, ...) vshPrintExtra(NULL, __VA_ARGS__) +static int vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason); static const char *vshDomainStateToString(int state); +static const char *vshDomainStateReasonToString(int state, int reason); static const char *vshDomainVcpuStateToString(int state); static bool vshConnectionUsability(vshControl *ctl, virConnectPtr conn); @@ -571,6 +575,7 @@ vshReconnect(vshControl *ctl) { else vshError(ctl, "%s", _("Reconnected to the hypervisor")); disconnected = 0; + ctl->noGetState = false; } /* --------------- @@ -717,6 +722,7 @@ cmdConnect(vshControl *ctl, const vshCmd *cmd) } ctl->name = vshStrdup(ctl, name); + ctl->noGetState = false; ctl->readonly = ro; ctl->conn = virConnectOpenAuth(ctl->name, virConnectAuthPtrDefault, @@ -750,14 +756,14 @@ static bool cmdRunConsole(vshControl *ctl, virDomainPtr dom, const char *name) { bool ret = false; - virDomainInfo dominfo; + int state; - if (virDomainGetInfo(dom, &dominfo) < 0) { + if ((state = vshDomainState(ctl, dom, NULL)) < 0) { vshError(ctl, "%s", _("Unable to get domain status")); goto cleanup; } - if (dominfo.state == VIR_DOMAIN_SHUTOFF) { + if (state == VIR_DOMAIN_SHUTOFF) { vshError(ctl, "%s", _("The domain is not running")); goto cleanup; } @@ -872,29 +878,20 @@ cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) vshPrintExtra(ctl, "----------------------------------\n"); for (i = 0; i < maxid; i++) { - virDomainInfo info; virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]); - const char *state; /* this kind of work with domains is not atomic operation */ if (!dom) continue; - if (virDomainGetInfo(dom, &info) < 0) - state = _("no state"); - else - state = _(vshDomainStateToString(info.state)); - vshPrint(ctl, "%3d %-20s %s\n", virDomainGetID(dom), virDomainGetName(dom), - state); + vshDomainStateToString(vshDomainState(ctl, dom, NULL))); virDomainFree(dom); } for (i = 0; i < maxname; i++) { - virDomainInfo info; virDomainPtr dom = virDomainLookupByName(ctl->conn, names[i]); - const char *state; /* this kind of work with domains is not atomic operation */ if (!dom) { @@ -902,12 +899,10 @@ cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) continue; } - if (virDomainGetInfo(dom, &info) < 0) - state = _("no state"); - else - state = _(vshDomainStateToString(info.state)); - - vshPrint(ctl, "%3s %-20s %s\n", "-", names[i], state); + vshPrint(ctl, "%3s %-20s %s\n", + "-", + names[i], + vshDomainStateToString(vshDomainState(ctl, dom, NULL))); virDomainFree(dom); VIR_FREE(names[i]); @@ -928,15 +923,17 @@ static const vshCmdInfo info_domstate[] = { static const vshCmdOptDef opts_domstate[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"reason", VSH_OT_BOOL, 0, N_("also print reason for the state")}, {NULL, 0, 0, NULL} }; static bool cmdDomstate(vshControl *ctl, const vshCmd *cmd) { - virDomainInfo info; virDomainPtr dom; bool ret = true; + int showReason = vshCommandOptBool(cmd, "reason"); + int state, reason; if (!vshConnectionUsability(ctl, ctl->conn)) return false; @@ -944,12 +941,21 @@ cmdDomstate(vshControl *ctl, const vshCmd *cmd) if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) return false; - if (virDomainGetInfo(dom, &info) == 0) - vshPrint(ctl, "%s\n", - _(vshDomainStateToString(info.state))); - else + if ((state = vshDomainState(ctl, dom, &reason)) < 0) { ret = false; + goto cleanup; + } + + if (showReason) { + vshPrint(ctl, "%s (%s)\n", + _(vshDomainStateToString(state)), + vshDomainStateReasonToString(state, reason)); + } else { + vshPrint(ctl, "%s\n", + _(vshDomainStateToString(state))); + } +cleanup: virDomainFree(dom); return ret; } @@ -3023,7 +3029,6 @@ static bool cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd) { virDomainPtr dom; - virDomainInfo info; int kilobytes = 0; bool ret = true; int config = vshCommandOptBool(cmd, "config"); @@ -3063,12 +3068,6 @@ cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd) return false; } - if (virDomainGetInfo(dom, &info) != 0) { - virDomainFree(dom); - vshError(ctl, "%s", _("Unable to verify current MemorySize")); - return false; - } - if (flags == -1) { if (virDomainSetMaxMemory(dom, kilobytes) != 0) { vshError(ctl, "%s", _("Unable to change MaxMemorySize")); @@ -12024,10 +12023,38 @@ vshCommandStringParse(vshControl *ctl, char *cmdstr) * Misc utils * --------------- */ +static int +vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason) +{ + virDomainInfo info; + + if (reason) + *reason = -1; + + if (!ctl->noGetState) { + int state; + if (virDomainGetState(dom, &state, reason) < 0) { + virErrorPtr err = virGetLastError(); + if (err && err->code == VIR_ERR_NO_SUPPORT) + ctl->noGetState = true; + else + return -1; + } else { + return state; + } + } + + /* fall back to virDomainGetInfo if virDomainGetState is not supported */ + if (virDomainGetInfo(dom, &info) < 0) + return -1; + else + return info.state; +} + static const char * vshDomainStateToString(int state) { - switch (state) { + switch ((virDomainState) state) { case VIR_DOMAIN_RUNNING: return N_("running"); case VIR_DOMAIN_BLOCKED: @@ -12040,13 +12067,114 @@ vshDomainStateToString(int state) return N_("shut off"); case VIR_DOMAIN_CRASHED: return N_("crashed"); - default: + case VIR_DOMAIN_NOSTATE: ;/*FALLTHROUGH*/ } return N_("no state"); /* = dom0 state */ } static const char * +vshDomainStateReasonToString(int state, int reason) +{ + switch ((virDomainState) state) { + case VIR_DOMAIN_NOSTATE: + switch ((virDomainNostateReason) reason) { + case VIR_DOMAIN_NOSTATE_UNKNOWN: + ; + } + break; + + case VIR_DOMAIN_RUNNING: + switch ((virDomainRunningReason) reason) { + case VIR_DOMAIN_RUNNING_BOOTED: + return N_("booted"); + case VIR_DOMAIN_RUNNING_MIGRATED: + return N_("migrated"); + case VIR_DOMAIN_RUNNING_RESTORED: + return N_("restored"); + case VIR_DOMAIN_RUNNING_FROM_SNAPSHOT: + return N_("from snapshot"); + case VIR_DOMAIN_RUNNING_UNPAUSED: + return N_("unpaused"); + case VIR_DOMAIN_RUNNING_MIGRATION_CANCELED: + return N_("migration canceled"); + case VIR_DOMAIN_RUNNING_SAVE_CANCELED: + return N_("save canceled"); + case VIR_DOMAIN_RUNNING_UNKNOWN: + ; + } + break; + + case VIR_DOMAIN_BLOCKED: + switch ((virDomainBlockedReason) reason) { + case VIR_DOMAIN_BLOCKED_UNKNOWN: + ; + } + break; + + case VIR_DOMAIN_PAUSED: + switch ((virDomainPausedReason) reason) { + case VIR_DOMAIN_PAUSED_USER: + return N_("user"); + case VIR_DOMAIN_PAUSED_MIGRATION: + return N_("migrating"); + case VIR_DOMAIN_PAUSED_SAVE: + return N_("saving"); + case VIR_DOMAIN_PAUSED_DUMP: + return N_("dumping"); + case VIR_DOMAIN_PAUSED_IOERROR: + return N_("I/O error"); + case VIR_DOMAIN_PAUSED_WATCHDOG: + return N_("watchdog"); + case VIR_DOMAIN_PAUSED_FROM_SNAPSHOT: + return N_("from snapshot"); + case VIR_DOMAIN_PAUSED_UNKNOWN: + ; + } + break; + + case VIR_DOMAIN_SHUTDOWN: + switch ((virDomainShutdownReason) reason) { + case VIR_DOMAIN_SHUTDOWN_USER: + return N_("user"); + case VIR_DOMAIN_SHUTDOWN_UNKNOWN: + ; + } + break; + + case VIR_DOMAIN_SHUTOFF: + switch ((virDomainShutoffReason) reason) { + case VIR_DOMAIN_SHUTOFF_SHUTDOWN: + return N_("shutdown"); + case VIR_DOMAIN_SHUTOFF_DESTROYED: + return N_("destroyed"); + case VIR_DOMAIN_SHUTOFF_CRASHED: + return N_("crashed"); + case VIR_DOMAIN_SHUTOFF_MIGRATED: + return N_("migrated"); + case VIR_DOMAIN_SHUTOFF_SAVED: + return N_("saved"); + case VIR_DOMAIN_SHUTOFF_FAILED: + return N_("failed"); + case VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT: + return N_("from snapshot"); + case VIR_DOMAIN_SHUTOFF_UNKNOWN: + ; + } + break; + + case VIR_DOMAIN_CRASHED: + switch ((virDomainCrashedReason) reason) { + case VIR_DOMAIN_CRASHED_UNKNOWN: + ; + } + break; + } + + return N_("unknown"); +} + +static const char * vshDomainVcpuStateToString(int state) { switch (state) { @@ -12144,6 +12272,7 @@ vshError(vshControl *ctl, const char *format, ...) VIR_FREE(str); } + /* * Initialize connection. */ -- 1.7.5.rc3

On 05/04/2011 08:45 AM, Jiri Denemark wrote:
--- tools/virsh.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 162 insertions(+), 33 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c index 5d8b025..6dae9fa 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -223,6 +223,8 @@ typedef struct __vshControl { int log_fd; /* log file descriptor */ char *historydir; /* readline history directory name */ char *historyfile; /* readline history file name */ + bool noGetState; /* virDomainGetState is not supported in + * current connection */
Nice - remembering the failure once, so you don't have to repeat it. However, I don't like double negatives; could we instead have: bool useGetInfo /* must use virDomainGetInfo, since virDomainGetState failed */
@@ -571,6 +575,7 @@ vshReconnect(vshControl *ctl) { else vshError(ctl, "%s", _("Reconnected to the hypervisor")); disconnected = 0; + ctl->noGetState = false;
then a default state of ctl->useGetInfo = false still makes sense,
@@ -3063,12 +3068,6 @@ cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd) return false; }
- if (virDomainGetInfo(dom, &info) != 0) { - virDomainFree(dom); - vshError(ctl, "%s", _("Unable to verify current MemorySize")); - return false; - } -
This seems like one case where we still want to keep the virDomainGetInfo and actually query the guest.
+static int +vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason) +{ + virDomainInfo info; + + if (reason) + *reason = -1; + + if (!ctl->noGetState) {
Here, if you follow my rename, you avoid the double negative ("!" and "no"), and instead have: if (!ctl->useGetInfo) But overall, the patch looks nice. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Wed, May 04, 2011 at 17:35:42 -0600, Eric Blake wrote:
+ bool noGetState; /* virDomainGetState is not supported in + * current connection */
Nice - remembering the failure once, so you don't have to repeat it. However, I don't like double negatives; could we instead have:
Yeah, I especially wanted this for virsh list to avoid calling virDomainGetState over and over even though it is not supported.
bool useGetInfo /* must use virDomainGetInfo, since virDomainGetState failed */
Makes sense.
@@ -3063,12 +3068,6 @@ cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd) return false; }
- if (virDomainGetInfo(dom, &info) != 0) { - virDomainFree(dom); - vshError(ctl, "%s", _("Unable to verify current MemorySize")); - return false; - } -
This seems like one case where we still want to keep the virDomainGetInfo and actually query the guest.
I don't think this is needed since it doesn't really verify anything. It just checks if virDomainGetInfo fails or not. And even if it did verify something, it's really a job of virDomainSetMaxMemory or virDomainSetMemoryFlags, virsh should only check the parameters it got from its user. Jirka

--- src/remote/remote_driver.c | 31 ++++++++++++++++++++++++++++++- 1 files changed, 30 insertions(+), 1 deletions(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 9796bb5..3baedf0 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2861,6 +2861,35 @@ done: } static int +remoteDomainGetState(virDomainPtr domain, int *state, int *reason) +{ + int rv = -1; + remote_domain_get_state_args args; + remote_domain_get_state_ret ret; + struct private_data *priv = domain->conn->privateData; + + remoteDriverLock(priv); + + make_nonnull_domain(&args.dom, domain); + + memset(&ret, 0, sizeof ret); + if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_STATE, + (xdrproc_t) xdr_remote_domain_get_state_args, (char *) &args, + (xdrproc_t) xdr_remote_domain_get_state_ret, (char *) &ret) == -1) + goto done; + + *state = ret.state; + if (reason) + *reason = ret.reason; + + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; +} + +static int remoteDomainSave (virDomainPtr domain, const char *to) { int rv = -1; @@ -11222,7 +11251,7 @@ static virDriver remote_driver = { remoteDomainSetBlkioParameters, /* domainSetBlkioParameters */ remoteDomainGetBlkioParameters, /* domainGetBlkioParameters */ remoteDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + remoteDomainGetState, /* domainGetState */ remoteDomainSave, /* domainSave */ remoteDomainRestore, /* domainRestore */ remoteDomainCoreDump, /* domainCoreDump */ -- 1.7.5.rc3

On 05/04/2011 08:45 AM, Jiri Denemark wrote:
--- src/remote/remote_driver.c | 31 ++++++++++++++++++++++++++++++- 1 files changed, 30 insertions(+), 1 deletions(-)
ACK, modulo addition of flags parameter. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

Reason is currently always set to 0 (i.e., *_UNKNOWN). --- src/esx/esx_driver.c | 54 ++++++++++++++++++++++++- src/libxl/libxl_driver.c | 31 +++++++++++++- src/lxc/lxc_driver.c | 33 ++++++++++++++- src/openvz/openvz_driver.c | 32 ++++++++++++++- src/phyp/phyp_driver.c | 12 +++++- src/qemu/qemu_driver.c | 33 ++++++++++++++- src/test/test_driver.c | 31 +++++++++++++- src/uml/uml_driver.c | 32 ++++++++++++++- src/vbox/vbox_tmpl.c | 56 +++++++++++++++++++++++++- src/vmware/vmware_driver.c | 31 +++++++++++++- src/xen/xen_driver.c | 18 ++++++++- src/xen/xen_hypervisor.c | 34 +++++++++++++++- src/xen/xen_hypervisor.h | 4 ++ src/xen/xend_internal.c | 97 ++++++++++++++++++++++++++++++++----------- src/xen/xend_internal.h | 1 + src/xen/xm_internal.c | 19 ++++++++- src/xen/xm_internal.h | 1 + src/xen/xs_internal.c | 32 ++++++++++++++- src/xen/xs_internal.h | 3 + src/xenapi/xenapi_driver.c | 45 ++++++++++++++++++++- 20 files changed, 559 insertions(+), 40 deletions(-) diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 543ebe6..94b0121 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -2425,6 +2425,58 @@ esxDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) static int +esxDomainGetState(virDomainPtr domain, int *state, int *reason) +{ + int result = -1; + esxPrivate *priv = domain->conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_VirtualMachinePowerState powerState; + + if (esxVI_EnsureSession(priv->primary) < 0) { + return -1; + } + + if (esxVI_String_AppendValueListToList(&propertyNameList, + "runtime.powerState\0") < 0 || + esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid, + propertyNameList, &virtualMachine, + esxVI_Occurrence_RequiredItem) < 0) { + goto cleanup; + } + + *state = VIR_DOMAIN_NOSTATE; + if (reason) + *reason = 0; + + for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "runtime.powerState")) { + if (esxVI_VirtualMachinePowerState_CastFromAnyType + (dynamicProperty->val, &powerState) < 0) { + goto cleanup; + } + + *state = esxVI_VirtualMachinePowerState_ConvertToLibvirt + (powerState); + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + result = 0; + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachine); + + return result; +} + + + +static int esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus, unsigned int flags) { @@ -4596,7 +4648,7 @@ static virDriver esxDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ esxDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + esxDomainGetState, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index db6f99c..7d62ed5 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -1566,6 +1566,35 @@ libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) } static int +libxlDomainGetState(virDomainPtr dom, int *state, int *reason) +{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + libxlDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + libxlDriverUnlock(driver); + + if (!vm) { + libxlError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + *state = vm->state; + if (reason) + *reason = 0; + + ret = 0; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int libxlDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, unsigned int flags) { @@ -2672,7 +2701,7 @@ static virDriver libxlDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ libxlDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + libxlDomainGetState, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index bc96ed4..ccedfe3 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -564,6 +564,37 @@ cleanup: return ret; } +static int +lxcDomainGetState(virDomainPtr dom, int *state, int *reason) +{ + lxc_driver_t *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + lxcDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + lxcDriverUnlock(driver); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + lxcError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + *state = vm->state; + if (reason) + *reason = 0; + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + static char *lxcGetOSType(virDomainPtr dom) { lxc_driver_t *driver = dom->conn->privateData; @@ -2830,7 +2861,7 @@ static virDriver lxcDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ lxcDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + lxcDomainGetState, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 268e752..0e774d9 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -377,6 +377,36 @@ cleanup: } +static int +openvzDomainGetState(virDomainPtr dom, int *state, int *reason) +{ + struct openvz_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + openvzDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + openvzDriverUnlock(driver); + + if (!vm) { + openvzError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + *state = vm->state; + if (reason) + *reason = 0; + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + + static int openvzDomainIsActive(virDomainPtr dom) { struct openvz_driver *driver = dom->conn->privateData; @@ -1591,7 +1621,7 @@ static virDriver openvzDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ openvzDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + openvzDomainGetState, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index fb365ba..18331cd 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -3471,6 +3471,16 @@ phypDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) } static int +phypDomainGetState(virDomainPtr dom, int *state, int *reason) +{ + *state = phypGetLparState(dom->conn, dom->id); + if (reason) + *reason = 0; + + return 0; +} + +static int phypDomainDestroy(virDomainPtr dom) { int result = -1; @@ -3752,7 +3762,7 @@ static virDriver phypDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ phypDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + phypDomainGetState, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 549cb2f..1fc4a22 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1783,6 +1783,37 @@ cleanup: return ret; } +static int +qemuDomainGetState(virDomainPtr dom, int *state, int *reason) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + qemuDriverUnlock(driver); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + *state = vm->state; + if (reason) + *reason = 0; + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + #define QEMUD_SAVE_MAGIC "LibvirtQemudSave" #define QEMUD_SAVE_VERSION 2 @@ -7140,7 +7171,7 @@ static virDriver qemuDriver = { qemuDomainSetBlkioParameters, /* domainSetBlkioParameters */ qemuDomainGetBlkioParameters, /* domainGetBlkioParameters */ qemudDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + qemuDomainGetState, /* domainGetState */ qemudDomainSave, /* domainSave */ qemuDomainRestore, /* domainRestore */ qemudDomainCoreDump, /* domainCoreDump */ diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 6f4ae75..1641747 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -1704,6 +1704,35 @@ cleanup: return ret; } +static int +testDomainGetState(virDomainPtr domain, int *state, int *reason) +{ + testConnPtr privconn = domain->conn->privateData; + virDomainObjPtr privdom; + int ret = -1; + + testDriverLock(privconn); + privdom = virDomainFindByName(&privconn->domains, + domain->name); + testDriverUnlock(privconn); + + if (privdom == NULL) { + testError(VIR_ERR_INVALID_ARG, __FUNCTION__); + goto cleanup; + } + + *state = privdom->state; + if (reason) + *reason = 0; + + ret = 0; + +cleanup: + if (privdom) + virDomainObjUnlock(privdom); + return ret; +} + #define TEST_SAVE_MAGIC "TestGuestMagic" static int testDomainSave(virDomainPtr domain, @@ -5371,7 +5400,7 @@ static virDriver testDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ testGetDomainInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + testDomainGetState, /* domainGetState */ testDomainSave, /* domainSave */ testDomainRestore, /* domainRestore */ testDomainCoreDump, /* domainCoreDump */ diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 6852a16..cd659db 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1522,6 +1522,36 @@ cleanup: } +static int +umlDomainGetState(virDomainPtr dom, int *state, int *reason) +{ + struct uml_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + umlDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + umlDriverUnlock(driver); + + if (!vm) { + umlReportError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + *state = vm->state; + if (reason) + *reason = 0; + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + + static char *umlDomainDumpXML(virDomainPtr dom, int flags ATTRIBUTE_UNUSED) { struct uml_driver *driver = dom->conn->privateData; @@ -2177,7 +2207,7 @@ static virDriver umlDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ umlDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + umlDomainGetState, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index d4a8924..26860c8 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -1909,6 +1909,60 @@ cleanup: return ret; } +static int +vboxDomainGetState(virDomainPtr dom, int *state, int *reason) +{ + VBOX_OBJECT_CHECK(dom->conn, int, -1); + vboxIID domiid = VBOX_IID_INITIALIZER; + IMachine *machine = NULL; + PRUint32 mstate = MachineState_Null; + nsresult rc; + + vboxIIDFromUUID(&domiid, dom->uuid); + rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); + if (NS_FAILED(rc)) { + vboxError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching UUID")); + goto cleanup; + } + + machine->vtbl->GetState(machine, &mstate); + + switch (mstate) { + case MachineState_Running: + *state = VIR_DOMAIN_RUNNING; + break; + case MachineState_Stuck: + *state = VIR_DOMAIN_BLOCKED; + break; + case MachineState_Paused: + *state = VIR_DOMAIN_PAUSED; + break; + case MachineState_Stopping: + *state = VIR_DOMAIN_SHUTDOWN; + break; + case MachineState_PoweredOff: + *state = VIR_DOMAIN_SHUTOFF; + break; + case MachineState_Aborted: + *state = VIR_DOMAIN_CRASHED; + break; + case MachineState_Null: + default: + *state = VIR_DOMAIN_NOSTATE; + break; + } + + if (reason) + *reason = 0; + + ret = 0; + +cleanup: + vboxIIDUnalloc(&domiid); + return ret; +} + static int vboxDomainSave(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IConsole *console = NULL; @@ -8566,7 +8620,7 @@ virDriver NAME(Driver) = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ vboxDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + vboxDomainGetState, /* domainGetState */ vboxDomainSave, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index c6c92c6..9b22d4a 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -896,6 +896,35 @@ vmwareDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) return ret; } +static int +vmwareDomainGetState(virDomainPtr dom, int *state, int *reason) +{ + struct vmware_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + *state = vm->state; + if (reason) + *reason = 0; + + ret = 0; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + static virDriver vmwareDriver = { VIR_DRV_VMWARE, "VMWARE", @@ -931,7 +960,7 @@ static virDriver vmwareDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ vmwareDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + vmwareDomainGetState, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 1646828..bdf70ad 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -1010,6 +1010,22 @@ xenUnifiedDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) } static int +xenUnifiedDomainGetState(virDomainPtr dom, int *state, int *reason) +{ + GET_PRIVATE(dom->conn); + int i; + + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) { + if (priv->opened[i] && + drivers[i]->domainGetState && + drivers[i]->domainGetState(dom, state, reason) == 0) + return 0; + } + + return -1; +} + +static int xenUnifiedDomainSave (virDomainPtr dom, const char *to) { GET_PRIVATE(dom->conn); @@ -2132,7 +2148,7 @@ static virDriver xenUnifiedDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ xenUnifiedDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + xenUnifiedDomainGetState, /* domainGetState */ xenUnifiedDomainSave, /* domainSave */ xenUnifiedDomainRestore, /* domainRestore */ xenUnifiedDomainCoreDump, /* domainCoreDump */ diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index f5218bc..98ff157 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -821,7 +821,7 @@ struct xenUnifiedDriver xenHypervisorDriver = { xenHypervisorSetMaxMemory, /* domainSetMaxMemory */ NULL, /* domainSetMemory */ xenHypervisorGetDomainInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + xenHypervisorGetDomainState, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ @@ -3239,6 +3239,38 @@ xenHypervisorGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info) } /** + * xenHypervisorGetDomainState: + * @domain: pointer to the domain block + * @state: returned state of the domain + * @reason: returned reason for the state + * + * Do a hypervisor call to get the related set of domain information. + * + * Returns 0 in case of success, -1 in case of error. + */ +int +xenHypervisorGetDomainState(virDomainPtr domain, int *state, int *reason) +{ + xenUnifiedPrivatePtr priv = domain->conn->privateData; + virDomainInfo info; + + if (domain->conn == NULL) + return -1; + + if (priv->handle < 0 || domain->id < 0) + return -1; + + if (xenHypervisorGetDomInfo(domain->conn, domain->id, &info) < 0) + return -1; + + *state = info.state; + if (reason) + *reason = 0; + + return 0; +} + +/** * xenHypervisorNodeGetCellsFreeMemory: * @conn: pointer to the hypervisor connection * @freeMems: pointer to the array of unsigned long long diff --git a/src/xen/xen_hypervisor.h b/src/xen/xen_hypervisor.h index 6018b84..e6b86b5 100644 --- a/src/xen/xen_hypervisor.h +++ b/src/xen/xen_hypervisor.h @@ -66,6 +66,10 @@ int xenHypervisorPauseDomain (virDomainPtr domain) int xenHypervisorGetDomainInfo (virDomainPtr domain, virDomainInfoPtr info) ATTRIBUTE_NONNULL (1); +int xenHypervisorGetDomainState (virDomainPtr domain, + int *state, + int *reason) + ATTRIBUTE_NONNULL (1); int xenHypervisorGetDomInfo (virConnectPtr conn, int id, virDomainInfoPtr info); diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 1fbb8e6..789af83 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -1020,6 +1020,43 @@ xend_detect_config_version(virConnectPtr conn) { /** + * sexpr_to_xend_domain_state: + * @root: an S-Expression describing a domain + * + * Internal routine getting the domain's state from the domain root provided. + * + * Returns domain's state. + */ +static int +ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) +sexpr_to_xend_domain_state(virDomainPtr domain, const struct sexpr *root) +{ + const char *flags; + int state = VIR_DOMAIN_NOSTATE; + + if ((flags = sexpr_node(root, "domain/state"))) { + if (strchr(flags, 'c')) + state = VIR_DOMAIN_CRASHED; + else if (strchr(flags, 's')) + state = VIR_DOMAIN_SHUTOFF; + else if (strchr(flags, 'd')) + state = VIR_DOMAIN_SHUTDOWN; + else if (strchr(flags, 'p')) + state = VIR_DOMAIN_PAUSED; + else if (strchr(flags, 'b')) + state = VIR_DOMAIN_BLOCKED; + else if (strchr(flags, 'r')) + state = VIR_DOMAIN_RUNNING; + } else if (domain->id < 0) { + /* Inactive domains don't have a state reported, so + mark them SHUTOFF, rather than NOSTATE */ + state = VIR_DOMAIN_SHUTOFF; + } + + return state; +} + +/** * sexpr_to_xend_domain_info: * @root: an S-Expression describing a domain * @info: a info data structure to fill=up @@ -1033,38 +1070,16 @@ static int sexpr_to_xend_domain_info(virDomainPtr domain, const struct sexpr *root, virDomainInfoPtr info) { - const char *flags; int vcpus; if ((root == NULL) || (info == NULL)) return (-1); + info->state = sexpr_to_xend_domain_state(domain, root); info->memory = sexpr_u64(root, "domain/memory") << 10; info->maxMem = sexpr_u64(root, "domain/maxmem") << 10; - flags = sexpr_node(root, "domain/state"); - - if (flags) { - if (strchr(flags, 'c')) - info->state = VIR_DOMAIN_CRASHED; - else if (strchr(flags, 's')) - info->state = VIR_DOMAIN_SHUTOFF; - else if (strchr(flags, 'd')) - info->state = VIR_DOMAIN_SHUTDOWN; - else if (strchr(flags, 'p')) - info->state = VIR_DOMAIN_PAUSED; - else if (strchr(flags, 'b')) - info->state = VIR_DOMAIN_BLOCKED; - else if (strchr(flags, 'r')) - info->state = VIR_DOMAIN_RUNNING; - } else { - /* Inactive domains don't have a state reported, so - mark them SHUTOFF, rather than NOSTATE */ - if (domain->id < 0) - info->state = VIR_DOMAIN_SHUTOFF; - else - info->state = VIR_DOMAIN_NOSTATE; - } info->cpuTime = sexpr_float(root, "domain/cpu_time") * 1000000000; + vcpus = sexpr_int(root, "domain/vcpus"); info->nrVirtCpu = count_one_bits_l(sexpr_u64(root, "domain/vcpu_avail")); if (!info->nrVirtCpu || vcpus < info->nrVirtCpu) @@ -1894,6 +1909,38 @@ xenDaemonDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) /** + * xenDaemonDomainGetState: + * @domain: a domain object + * @state: returned domain's state + * @reason: returned reason for the state + * + * This method looks up domain state and reason. + * + * Returns 0 in case of success, -1 in case of error + */ +int +xenDaemonDomainGetState(virDomainPtr domain, int *state, int *reason) +{ + xenUnifiedPrivatePtr priv = domain->conn->privateData; + struct sexpr *root; + + if (domain->id < 0 && priv->xendConfigVersion < 3) + return -1; + + root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name); + if (!root) + return -1; + + *state = sexpr_to_xend_domain_state(domain, root); + if (reason) + *reason = 0; + + sexpr_free(root); + return 0; +} + + +/** * xenDaemonLookupByName: * @conn: A xend instance * @name: The name of the domain @@ -3861,7 +3908,7 @@ struct xenUnifiedDriver xenDaemonDriver = { xenDaemonDomainSetMaxMemory, /* domainSetMaxMemory */ xenDaemonDomainSetMemory, /* domainMaxMemory */ xenDaemonDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + xenDaemonDomainGetState, /* domainGetState */ xenDaemonDomainSave, /* domainSave */ xenDaemonDomainRestore, /* domainRestore */ xenDaemonDomainCoreDump, /* domainCoreDump */ diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h index 805cf91..087ce08 100644 --- a/src/xen/xend_internal.h +++ b/src/xen/xend_internal.h @@ -110,6 +110,7 @@ int xenDaemonDomainRestore(virConnectPtr conn, const char *filename); int xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory); int xenDaemonDomainSetMaxMemory(virDomainPtr domain, unsigned long memory); int xenDaemonDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info); +int xenDaemonDomainGetState(virDomainPtr domain, int *state, int *reason); char *xenDaemonDomainDumpXML(virDomainPtr domain, int flags, const char *cpus); unsigned long xenDaemonDomainGetMaxMemory(virDomainPtr domain); char **xenDaemonListDomainsOld(virConnectPtr xend); diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index 06334a4..47a2c46 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -100,7 +100,7 @@ struct xenUnifiedDriver xenXMDriver = { xenXMDomainSetMaxMemory, /* domainSetMaxMemory */ xenXMDomainSetMemory, /* domainMaxMemory */ xenXMDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + xenXMDomainGetState, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ @@ -470,6 +470,23 @@ int xenXMClose(virConnectPtr conn) { } /* + * Since these are all offline domains, the state is always SHUTOFF. + */ +int +xenXMDomainGetState(virDomainPtr domain, int *state, int *reason) +{ + if (domain->id != -1) + return -1; + + *state = VIR_DOMAIN_SHUTOFF; + if (reason) + *reason = 0; + + return 0; +} + + +/* * Since these are all offline domains, we only return info about * VCPUs and memory. */ diff --git a/src/xen/xm_internal.h b/src/xen/xm_internal.h index 695bb3e..a289d5b 100644 --- a/src/xen/xm_internal.h +++ b/src/xen/xm_internal.h @@ -40,6 +40,7 @@ virDrvOpenStatus xenXMOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags int xenXMClose(virConnectPtr conn); const char *xenXMGetType(virConnectPtr conn); int xenXMDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info); +int xenXMDomainGetState(virDomainPtr domain, int *state, int *reason); char *xenXMDomainDumpXML(virDomainPtr domain, int flags); int xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory); int xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory); diff --git a/src/xen/xs_internal.c b/src/xen/xs_internal.c index 127161c..d834d76 100644 --- a/src/xen/xs_internal.c +++ b/src/xen/xs_internal.c @@ -62,7 +62,7 @@ struct xenUnifiedDriver xenStoreDriver = { NULL, /* domainSetMaxMemory */ xenStoreDomainSetMemory, /* domainSetMemory */ xenStoreGetDomainInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + xenStoreDomainGetState, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ @@ -450,6 +450,36 @@ xenStoreGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info) } /** + * xenStoreDomainGetState: + * @domain: pointer to the domain block + * @state: returned domain's state + * @reason: returned state reason + * + * Returns 0 in case of success, -1 in case of error. + */ +int +xenStoreDomainGetState(virDomainPtr domain, int *state, int *reason) +{ + char *running; + + if (domain->id == -1) + return -1; + + running = virDomainDoStoreQuery(domain->conn, domain->id, "running"); + + if (running && *running == '1') + *state = VIR_DOMAIN_RUNNING; + else + *state = VIR_DOMAIN_NOSTATE; + if (reason) + *reason = 0; + + VIR_FREE(running); + + return 0; +} + +/** * xenStoreDomainSetMemory: * @domain: pointer to the domain block * @memory: the max memory size in kilobytes. diff --git a/src/xen/xs_internal.h b/src/xen/xs_internal.h index d58e6c0..5c9fce4 100644 --- a/src/xen/xs_internal.h +++ b/src/xen/xs_internal.h @@ -23,6 +23,9 @@ virDrvOpenStatus xenStoreOpen (virConnectPtr conn, int xenStoreClose (virConnectPtr conn); int xenStoreGetDomainInfo (virDomainPtr domain, virDomainInfoPtr info); +int xenStoreDomainGetState (virDomainPtr domain, + int *state, + int *reason); int xenStoreNumOfDomains (virConnectPtr conn); int xenStoreListDomains (virConnectPtr conn, int *ids, diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 83417df..f863a54 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -994,6 +994,49 @@ xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) return -1; } +/* + * xenapiDomainGetState: + * + * Retrieves domain status and its reason. + * + * Returns 0 on success or -1 in case of error + */ +static int +xenapiDomainGetState(virDomainPtr dom, int *state, int *reason) +{ + struct _xenapiPrivate *priv = dom->conn->privateData; + enum xen_vm_power_state powerState = XEN_VM_POWER_STATE_UNDEFINED; + xen_vm_set *vms = NULL; + xen_vm vm; + int ret = -1; + + if (!xen_vm_get_by_name_label(priv->session, &vms, dom->name) || + vms->size == 0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + goto cleanup; + } + + if (vms->size != 1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, + _("Domain name is not unique")); + goto cleanup; + } + + vm = vms->contents[0]; + xen_vm_get_power_state(priv->session, &powerState, vm); + + *state = mapPowerState(powerState); + if (reason) + *reason = 0; + + ret = 0; + +cleanup: + if (vms) + xen_vm_set_free(vms); + return ret; +} + /* * xenapiDomainSetVcpusFlags @@ -1813,7 +1856,7 @@ static virDriver xenapiDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ xenapiDomainGetInfo, /* domainGetInfo */ - NULL, /* domainGetState */ + xenapiDomainGetState, /* domainGetState */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ -- 1.7.5.rc3

On 05/04/2011 08:45 AM, Jiri Denemark wrote:
Reason is currently always set to 0 (i.e., *_UNKNOWN). ---
+++ b/src/xen/xen_driver.c @@ -1010,6 +1010,22 @@ xenUnifiedDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) }
static int +xenUnifiedDomainGetState(virDomainPtr dom, int *state, int *reason) +{ + GET_PRIVATE(dom->conn); + int i; + + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) { + if (priv->opened[i] && + drivers[i]->domainGetState && + drivers[i]->domainGetState(dom, state, reason) == 0) + return 0; + }
...
+int +xenHypervisorGetDomainState(virDomainPtr domain, int *state, int *reason)
You definitely need this function in xen_hypervisor.c, but I still wonder if the for loop across callbacks in xen_driver.c is appropriate, given that we are trying to get rid of the secondary callback structure, or if we should just inline direct calls to the appropriate helper (I brought up this same point in my review of 2/8). After all, not all possible xen helpers implement the callback (for example, xen_inotify.c does not).
+++ b/src/xen/xen_hypervisor.h @@ -66,6 +66,10 @@ int xenHypervisorPauseDomain (virDomainPtr domain) int xenHypervisorGetDomainInfo (virDomainPtr domain, virDomainInfoPtr info) ATTRIBUTE_NONNULL (1); +int xenHypervisorGetDomainState (virDomainPtr domain, + int *state, + int *reason) + ATTRIBUTE_NONNULL (1);
That is, either we use the callback structure, and this function could be private, or we declare this function and call it directly, then we don't need an extra row in the secondary callback structure.
+++ b/src/xen/xs_internal.h @@ -23,6 +23,9 @@ virDrvOpenStatus xenStoreOpen (virConnectPtr conn, int xenStoreClose (virConnectPtr conn); int xenStoreGetDomainInfo (virDomainPtr domain, virDomainInfoPtr info); +int xenStoreDomainGetState (virDomainPtr domain,
Spacing looks awkward here (space vs. tab). You'll have tweaks to fold in a flag parameter, but overall this patch looked sane. ACK. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

2011/5/4 Jiri Denemark <jdenemar@redhat.com>:
Reason is currently always set to 0 (i.e., *_UNKNOWN). --- src/esx/esx_driver.c | 54 ++++++++++++++++++++++++- src/libxl/libxl_driver.c | 31 +++++++++++++- src/lxc/lxc_driver.c | 33 ++++++++++++++- src/openvz/openvz_driver.c | 32 ++++++++++++++- src/phyp/phyp_driver.c | 12 +++++- src/qemu/qemu_driver.c | 33 ++++++++++++++- src/test/test_driver.c | 31 +++++++++++++- src/uml/uml_driver.c | 32 ++++++++++++++- src/vbox/vbox_tmpl.c | 56 +++++++++++++++++++++++++- src/vmware/vmware_driver.c | 31 +++++++++++++- src/xen/xen_driver.c | 18 ++++++++- src/xen/xen_hypervisor.c | 34 +++++++++++++++- src/xen/xen_hypervisor.h | 4 ++ src/xen/xend_internal.c | 97 ++++++++++++++++++++++++++++++++----------- src/xen/xend_internal.h | 1 + src/xen/xm_internal.c | 19 ++++++++- src/xen/xm_internal.h | 1 + src/xen/xs_internal.c | 32 ++++++++++++++- src/xen/xs_internal.h | 3 + src/xenapi/xenapi_driver.c | 45 ++++++++++++++++++++- 20 files changed, 559 insertions(+), 40 deletions(-)
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 543ebe6..94b0121 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -2425,6 +2425,58 @@ esxDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
static int +esxDomainGetState(virDomainPtr domain, int *state, int *reason) +{ + int result = -1; + esxPrivate *priv = domain->conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_VirtualMachinePowerState powerState; + + if (esxVI_EnsureSession(priv->primary) < 0) { + return -1; + } + + if (esxVI_String_AppendValueListToList(&propertyNameList, + "runtime.powerState\0") < 0 || + esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid, + propertyNameList, &virtualMachine, + esxVI_Occurrence_RequiredItem) < 0) { + goto cleanup; + } + + *state = VIR_DOMAIN_NOSTATE; + if (reason) + *reason = 0; + + for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "runtime.powerState")) { + if (esxVI_VirtualMachinePowerState_CastFromAnyType + (dynamicProperty->val, &powerState) < 0) { + goto cleanup; + } + + *state = esxVI_VirtualMachinePowerState_ConvertToLibvirt + (powerState); + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + result = 0; + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachine); + + return result; +} +
This can be simplified to: static int esxDomainGetState(virDomainPtr domain, int *state, int *reason) { int result = -1; esxPrivate *priv = domain->conn->privateData; esxVI_String *propertyNameList = NULL; esxVI_ObjectContent *virtualMachine = NULL; esxVI_VirtualMachinePowerState powerState; if (esxVI_EnsureSession(priv->primary) < 0) { return -1; } if (esxVI_String_AppendValueToList(&propertyNameList, "runtime.powerState") < 0 || esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid, propertyNameList, &virtualMachine, esxVI_Occurrence_RequiredItem) < 0 || esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) { goto cleanup; } *state = esxVI_VirtualMachinePowerState_ConvertToLibvirt(powerState); if (reason) { *reason = 0; } result = 0; cleanup: esxVI_String_Free(&propertyNameList); esxVI_ObjectContent_Free(&virtualMachine); return result; } Matthias

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. --- 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 2a681d9..4f1b9f3 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -369,6 +369,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") @@ -1059,7 +1109,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); @@ -6250,6 +6301,8 @@ static virDomainObjPtr virDomainObjParseXML(virCapsPtr caps, xmlNodePtr config; xmlNodePtr oldnode; virDomainObjPtr obj; + int state; + int reason = 0; if (!(obj = virDomainObjNew(caps))) return NULL; @@ -6273,7 +6326,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); @@ -6281,6 +6334,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")); @@ -8454,9 +8519,13 @@ static char *virDomainObjFormat(virCapsPtr caps, { char *config_xml = NULL; virBuffer buf = VIR_BUFFER_INITIALIZER; + int state; + int reason; - virBufferVSprintf(&buf, "<domstatus state='%s' pid='%d'>\n", - virDomainStateTypeToString(obj->state), + state = virDomainObjGetState(obj, &reason); + virBufferVSprintf(&buf, "<domstatus state='%s' reason='%s' pid='%d'>\n", + virDomainStateTypeToString(state), + virDomainStateReasonToString(state, reason), obj->pid); if (caps->privateDataXMLFormat && @@ -9551,3 +9620,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 1dadf98..4a6ad4e 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1183,6 +1183,12 @@ struct _virDomainDef { }; /* Guest VM runtime state */ +typedef struct _virDomainStateReason virDomainStateReason; +struct _virDomainStateReason { + int state; + int reason; +}; + typedef struct _virDomainObj virDomainObj; typedef virDomainObj *virDomainObjPtr; struct _virDomainObj { @@ -1190,7 +1196,7 @@ struct _virDomainObj { int refs; int pid; - int state; + virDomainStateReason state; unsigned int autostart : 1; unsigned int persistent : 1; @@ -1426,6 +1432,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); @@ -1478,6 +1491,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 1b22be6..2dc6d9c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -291,6 +291,7 @@ virDomainNetTypeToString; virDomainObjAssignDef; virDomainObjCopyPersistentDef; virDomainObjGetPersistentDef; +virDomainObjGetState; virDomainObjIsDuplicate; virDomainObjListDeinit; virDomainObjListGetActiveIDs; @@ -300,6 +301,7 @@ virDomainObjListNumOfDomains; virDomainObjLock; virDomainObjRef; virDomainObjSetDefTransient; +virDomainObjSetState; virDomainObjUnlock; virDomainObjUnref; virDomainRemoveInactive; @@ -322,6 +324,8 @@ virDomainSnapshotObjListRemove; virDomainSoundDefFree; virDomainSoundModelTypeFromString; virDomainSoundModelTypeToString; +virDomainStateReasonFromString; +virDomainStateReasonToString; virDomainStateTypeFromString; virDomainStateTypeToString; virDomainTimerModeTypeFromString; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 7d62ed5..35a1f7d 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: @@ -552,9 +563,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); } @@ -573,7 +584,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); @@ -618,7 +629,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); @@ -626,7 +637,7 @@ libxlReconnectDomain(void *payload, return; out: - libxlVmCleanup(driver, vm); + libxlVmCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_UNKNOWN); if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); else @@ -1169,7 +1180,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"), @@ -1177,7 +1188,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); @@ -1228,7 +1239,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"), @@ -1236,7 +1247,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); @@ -1371,7 +1383,7 @@ libxlDomainDestroy(virDomainPtr dom) VIR_DOMAIN_EVENT_STOPPED_DESTROYED); priv = vm->privateData; - 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; @@ -1554,7 +1566,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; @@ -1582,10 +1594,7 @@ libxlDomainGetState(virDomainPtr dom, int *state, int *reason) 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 ccedfe3..1eae10a 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; @@ -583,10 +583,7 @@ lxcDomainGetState(virDomainPtr dom, int *state, int *reason) goto cleanup; } - *state = vm->state; - if (reason) - *reason = 0; - + *state = virDomainObjGetState(vm, reason); ret = 0; cleanup: @@ -979,15 +976,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; @@ -1009,7 +1007,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; @@ -1194,7 +1192,8 @@ error: static int lxcVmTerminate(lxc_driver_t *driver, - virDomainObjPtr vm) + virDomainObjPtr vm, + virDomainShutoffReason reason) { virCgroupPtr group = NULL; int rc; @@ -1221,7 +1220,7 @@ static int lxcVmTerminate(lxc_driver_t *driver, rc = -1; goto cleanup; } - lxcVmCleanup(driver, vm); + lxcVmCleanup(driver, vm, reason); rc = 0; @@ -1251,7 +1250,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, @@ -1477,6 +1476,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 * @@ -1484,7 +1484,8 @@ cleanup: */ static int lxcVmStart(virConnectPtr conn, lxc_driver_t * driver, - virDomainObjPtr vm) + virDomainObjPtr vm, + virDomainRunningReason reason) { int rc = -1, r; unsigned int i; @@ -1584,14 +1585,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; } @@ -1664,7 +1665,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, @@ -1735,7 +1736,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; @@ -1926,7 +1927,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); @@ -1974,7 +1975,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"), @@ -2048,14 +2050,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 { @@ -2669,13 +2672,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, @@ -2734,13 +2737,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 0e774d9..458dc6f 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; @@ -394,10 +394,7 @@ openvzDomainGetState(virDomainPtr dom, int *state, int *reason) goto cleanup; } - *state = vm->state; - if (reason) - *reason = 0; - + *state = virDomainObjGetState(vm, reason); ret = 0; cleanup: @@ -520,12 +517,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; @@ -558,12 +555,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; @@ -591,7 +588,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; @@ -601,7 +598,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; @@ -629,7 +626,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; @@ -639,6 +636,8 @@ static int openvzDomainReboot(virDomainPtr dom, goto cleanup; ret = 0; + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED); + cleanup: if (vm) virDomainObjUnlock(vm); @@ -1017,7 +1016,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) { @@ -1059,7 +1058,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; @@ -1073,7 +1072,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 1fc4a22..3efb1a8 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; @@ -1802,10 +1803,7 @@ qemuDomainGetState(virDomainPtr dom, int *state, int *reason) goto cleanup; } - *state = vm->state; - if (reason) - *reason = 0; - + *state = virDomainObjGetState(vm, reason); ret = 0; cleanup: @@ -1932,9 +1930,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)) { @@ -2086,7 +2084,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, @@ -2102,7 +2100,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"); } @@ -2415,11 +2414,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; @@ -2438,7 +2438,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, @@ -2449,7 +2449,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")); @@ -2515,7 +2516,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, @@ -3213,7 +3215,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")); @@ -6360,12 +6363,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; @@ -6382,7 +6385,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")); @@ -6432,7 +6436,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)) { @@ -6732,9 +6736,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, @@ -6753,7 +6761,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, @@ -6770,8 +6778,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 7f4b111..956ac78 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; @@ -334,7 +334,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); @@ -1066,8 +1066,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; } @@ -1082,7 +1083,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; @@ -1098,9 +1099,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 @@ -1239,7 +1241,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")); @@ -1250,7 +1253,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, @@ -1261,7 +1265,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 7691cbe..c685c82 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); @@ -1893,7 +1896,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; @@ -1901,27 +1904,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; } @@ -2027,7 +2035,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 @@ -2364,7 +2372,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); @@ -2408,15 +2415,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; @@ -2434,7 +2446,7 @@ cleanup: qemuCapsFree(qemuCaps); virCommandFree(cmd); VIR_FORCE_CLOSE(logfile); - qemuProcessStop(driver, vm, 0); + qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_FAILED); return -1; } @@ -2442,7 +2454,8 @@ cleanup: void qemuProcessStop(struct qemud_driver *driver, virDomainObjPtr vm, - int migrated) + int migrated, + virDomainShutoffReason reason) { int ret; int retries = 0; @@ -2599,7 +2612,7 @@ retry: 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; 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 1641747..ebedaee 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; @@ -1721,10 +1732,7 @@ testDomainGetState(virDomainPtr domain, int *state, int *reason) goto cleanup; } - *state = privdom->state; - if (reason) - *reason = 0; - + *state = virDomainObjGetState(privdom, reason); ret = 0; cleanup: @@ -1799,7 +1807,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); @@ -1897,7 +1905,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, @@ -1956,7 +1964,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); @@ -2509,13 +2517,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; @@ -2552,13 +2561,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 cd659db..dca2cbe 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; @@ -1539,10 +1544,7 @@ umlDomainGetState(virDomainPtr dom, int *state, int *reason) 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 9b22d4a..8d0af46 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; @@ -913,10 +915,7 @@ vmwareDomainGetState(virDomainPtr dom, int *state, int *reason) goto cleanup; } - *state = vm->state; - if (reason) - *reason = 0; - + *state = virDomainObjGetState(vm, reason); ret = 0; cleanup: -- 1.7.5.rc3

On 05/04/2011 08:45 AM, 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.
+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)
&&, not || ACK with that nit fixed. virDomainObjSetState does not need a flags parameter, even though the public API has one (a virCheckFlags at each of the public API is sufficient to be the end of the line for that argument, and it does not have to propagate into src/conf/domain_conf.c). -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On 05/04/2011 08:45 AM, Jiri Denemark wrote:
This new API solves several problems:
- calling virDomainGetInfo for just getting domain status is an overkill since it may result in sending requests to guest OS - since virDomainGetInfo can hang when guest OS is not responding and it is used by virsh list, listing domains can hang - virDomainGetState provides additional info about what action led to domain's current state, which can be used instead of listening to domain events
I'm undecided whether this API should support flags parameter or not. On one hand the API seems simple and focused enough not to allow any fine-tuning but on the other hand we've already had too many issues with APIs that didn't support flags.
Time has proven that we may want the flags argument in the future, even if we don't know why now. Definitely add it.
Another thing is that it would be nice to somehow report that a domain is running but libvirt is currently waiting for reply from hypervisor and is not able to do anything else with the domain until it gets the reply. In case of qemu driver, this translates to the driver being stuck in comunication with qemu monitor. I'm not sure if we should somehow integrate this into virDomainGetState API. Probably not.
In fact, this may be a use for the flags! If flags is 0, then block until the state information is available (that is, we wait for the qemu response to the prior command, just like any other blocking command); if flags is 1, then an additional state category that can tell us that some other command is pending (that is, we have a non-blocking way to query if some other blocking command is in progress). Compare to WNOHANG and WNOWAIT flags of waitpid - sometimes you want to query instantly and get extra return values, other times you want to block until the query completes and hide the extra return values. I'm also wondering if we should make the API flexible enough to tell which blocking commands are currently pending, or even for how long a command has been waiting for a qemu response. Obviously, this series is post-0.9.1. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Wed, May 04, 2011 at 10:40:38 -0600, Eric Blake wrote:
On 05/04/2011 08:45 AM, Jiri Denemark wrote:
This new API solves several problems:
- calling virDomainGetInfo for just getting domain status is an overkill since it may result in sending requests to guest OS - since virDomainGetInfo can hang when guest OS is not responding and it is used by virsh list, listing domains can hang - virDomainGetState provides additional info about what action led to domain's current state, which can be used instead of listening to domain events
I'm undecided whether this API should support flags parameter or not. On one hand the API seems simple and focused enough not to allow any fine-tuning but on the other hand we've already had too many issues with APIs that didn't support flags.
Time has proven that we may want the flags argument in the future, even if we don't know why now. Definitely add it.
Yeah, I'll do that.
Another thing is that it would be nice to somehow report that a domain is running but libvirt is currently waiting for reply from hypervisor and is not able to do anything else with the domain until it gets the reply. In case of qemu driver, this translates to the driver being stuck in comunication with qemu monitor. I'm not sure if we should somehow integrate this into virDomainGetState API. Probably not.
In fact, this may be a use for the flags! If flags is 0, then block until the state information is available (that is, we wait for the qemu response to the prior command, just like any other blocking command); if flags is 1, then an additional state category that can tell us that some other command is pending (that is, we have a non-blocking way to query if some other blocking command is in progress). Compare to WNOHANG and WNOWAIT flags of waitpid - sometimes you want to query instantly and get extra return values, other times you want to block until the query completes and hide the extra return values.
This looks like a misunderstanding... virDomainGetState doesn't block if we're waiting for qemu reply since it doesn't need to talk to it. And that's one of the reason this API was introduced. What I meant was that even though virDomainGetState reports running (or even paused), it doesn't mean that we can do anything with the domain because it can be hung and not replying to monitor commands.
I'm also wondering if we should make the API flexible enough to tell which blocking commands are currently pending, or even for how long a command has been waiting for a qemu response.
Thinking about it more, I feel like it would be better to introduce a new API for this purpose. An API that would check if we can operate a domain (virDomainIsOperable or whatever name we choose). That is, if we can send a command to hypervisor without blocking. In qemu context that would mean checking if we're waiting for qemu reply or not and if so, further details such as how long we've been waiting for it could also be provided. It wouldn't be very usable for checking in advance if it's safe to issue a command but applications could use that to detect if some of their commands got stuck in qemu monitor. Jirka
participants (3)
-
Eric Blake
-
Jiri Denemark
-
Matthias Bolte