[libvirt] [PATCH v4 00/13] Implement memory control api

Changelog from v3: * Add unsigned int flags to the public api and make corresponding changes further down till the drivers(qemu, lxc and remote) * Move exporting of the api's to patch two * Added memtune test in tests/qemuxml2xmltest.c * Fix: src/conf/domain_conf.c - print memtune element only if tunable is present * Fix: src/qemu/qemu_driver.c - call cgroup apis only if nonzero * Fix: src/lxc/lxc_controller.c - call cgroup apis only if nonzero Changelog from v2: * Implement virDomainGetMemoryParameters api * Add virDomainGetMemoryParameters to memtune command in virsh * Provide domainGetMemoryParameters implementation for remote, QEmu and LXC drivers * Auto-generate code using rpcgen and remote_generate_stubs.pl * Squash all the changes related to remote driver and remote protocol into one single patch. * Patch re-ordering Changelog from v1: * Patch re-ordering for compilation * Folded python bindings changes to patch 01 * Added defines for string constants for memory tunables * Typo fix: min_guarantee * Moved initialization of function pointers in driver.h patch This patch series implement public api for controlling various memory tunables exported by the OS. This is based on the following RFC[1]. * Implement virDomainSetMemoryParameters api * Provide implementation for remote, QEmu and LXC drivers * Enable memory controller support fro QEmu * virsh command for runtime changes to the memory parameters * Domain configuration parsing for memory control parameters * Cgroup memory controller code for memory hard_limit/soft_limit, swap hard_limit To Do * Python bindings is just a place holder, need to implement 1. https://www.redhat.com/archives/libvir-list/2010-August/msg00607.html 2. https://www.redhat.com/archives/libvir-list/2010-August/msg00699.html --- Nikunj A. Dadhania (13): Adding structure and defines for virDomainSet/GetMemoryParameters Adding virDomainSetMemoryParameters and virDomainGetMemoryParameters API Adds xml entries for memory tunables XML parsing for memory tunables Implement cgroup memory controller tunables Implement driver interface domainSetMemoryParamters for QEmu Implement driver interface domainGetMemoryParamters for QEmu Adding memtunables to qemuSetupCgroup Adding memtunables to libvirt-lxc command Implement driver interface domainSetMemoryParamters for LXC Implement driver interface domainGetMemoryParamters for LXC Adding memtune command to virsh tool Remote protocol changes and implements virDomainSet/GetMemoryParameters daemon/remote.c | 162 +++++++++++++ daemon/remote_dispatch_args.h | 2 daemon/remote_dispatch_prototypes.h | 16 + daemon/remote_dispatch_ret.h | 1 daemon/remote_dispatch_table.h | 10 + docs/schemas/domain.rng | 31 +++ include/libvirt/libvirt.h.in | 63 +++++ python/generator.py | 2 python/libvirt-override-api.xml | 12 + python/libvirt-override.c | 14 + src/conf/domain_conf.c | 54 ++++ src/conf/domain_conf.h | 12 + src/driver.h | 14 + src/esx/esx_driver.c | 2 src/esx/esx_vmx.c | 30 +- src/libvirt.c | 104 +++++++++ src/libvirt_private.syms | 6 src/libvirt_public.syms | 6 src/lxc/lxc_controller.c | 32 +++ src/lxc/lxc_driver.c | 215 +++++++++++++++++- src/openvz/openvz_driver.c | 10 - src/phyp/phyp_driver.c | 2 src/qemu/qemu.conf | 4 src/qemu/qemu_conf.c | 11 - src/qemu/qemu_driver.c | 265 +++++++++++++++++++++- src/remote/remote_driver.c | 151 +++++++++++++ src/remote/remote_protocol.c | 88 +++++++ src/remote/remote_protocol.h | 58 +++++ src/remote/remote_protocol.x | 44 ++++ src/test/test_driver.c | 14 + src/uml/uml_conf.c | 2 src/uml/uml_driver.c | 16 + src/util/cgroup.c | 106 +++++++++ src/util/cgroup.h | 7 + src/xen/xen_driver.c | 2 tests/qemuxml2argvdata/qemuxml2argv-memtune.args | 1 tests/qemuxml2argvdata/qemuxml2argv-memtune.xml | 30 ++ tests/qemuxml2xmltest.c | 1 tools/virsh.c | 130 +++++++++++ 39 files changed, 1662 insertions(+), 68 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memtune.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memtune.xml

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> This patch adds a structure virMemoryParameter, it contains the name of the parameter and the type of the parameter along with a union. v4: + Add unsigned int flags to the public api for future extensions v3: + Protoype for virDomainGetMemoryParameters and dummy python binding. v2: + Includes dummy python bindings for the library to build cleanly. + Define string constants like "hard_limit", etc. + re-order this patch. Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- include/libvirt/libvirt.h.in | 63 +++++++++++++++++++++++++++++++++++++++ python/generator.py | 2 + python/libvirt-override-api.xml | 12 +++++++ python/libvirt-override.c | 14 +++++++++ 4 files changed, 91 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index b45f7ec..75a84fb 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -674,6 +674,69 @@ int virDomainGetInfo (virDomainPtr domain, char * virDomainGetSchedulerType(virDomainPtr domain, int *nparams); +/** + * virDomainMemoryParameterType: + * + * A memory parameter field type + */ +typedef enum { + VIR_DOMAIN_MEMORY_FIELD_INT = 1, /* integer case */ + VIR_DOMAIN_MEMORY_FIELD_UINT = 2, /* unsigned integer case */ + VIR_DOMAIN_MEMORY_FIELD_LLONG = 3, /* long long case */ + VIR_DOMAIN_MEMORY_FIELD_ULLONG = 4, /* unsigned long long case */ + VIR_DOMAIN_MEMORY_FIELD_DOUBLE = 5, /* double case */ + VIR_DOMAIN_MEMORY_FIELD_BOOLEAN = 6 /* boolean(character) case */ +} virMemoryParameterType; + +/** + * VIR_DOMAIN_MEMORY_FIELD_LENGTH: + * + * Macro providing the field length of virMemoryParameter + */ + +#define VIR_DOMAIN_MEMORY_FIELD_LENGTH 80 +#define VIR_DOMAIN_MEMORY_HARD_LIMIT "hard_limit" +#define VIR_DOMAIN_MEMORY_SOFT_LIMIT "soft_limit" +#define VIR_DOMAIN_MEMORY_MIN_GUARANTEE "min_guarantee" +#define VIR_DOMAIN_SWAP_HARD_LIMIT "swap_hard_limit" + +/** + * virDomainMemoryParameter: + * + * a virDomainMemoryParameter is the set of scheduler parameters + */ + +typedef struct _virMemoryParameter virMemoryParameter; + +struct _virMemoryParameter { + char field[VIR_DOMAIN_MEMORY_FIELD_LENGTH]; /* parameter name */ + int type; /* parameter type */ + union { + int i; /* data for integer case */ + unsigned int ui; /* data for unsigned integer case */ + long long int l; /* data for long long integer case */ + unsigned long long int ul; /* data for unsigned long long integer case */ + double d; /* data for double case */ + char b; /* data for char case */ + } value; /* parameter value */ +}; + +/** + * virMemoryParameterPtr: + * + * a virMemoryParameterPtr is a pointer to a virMemoryParameter structure. + */ + +typedef virMemoryParameter *virMemoryParameterPtr; + +/* Set memory tunables for the domain*/ +int virDomainSetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int nparams, unsigned int flags); +int virDomainGetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int *nparams, unsigned int flags); + /* * Dynamic control of domains */ diff --git a/python/generator.py b/python/generator.py index d876df6..68009b9 100755 --- a/python/generator.py +++ b/python/generator.py @@ -306,6 +306,8 @@ skip_impl = ( 'virDomainGetSchedulerType', 'virDomainGetSchedulerParameters', 'virDomainSetSchedulerParameters', + 'virDomainSetMemoryParameters', + 'virDomainGetMemoryParameters', 'virDomainGetVcpus', 'virDomainPinVcpu', 'virSecretGetValue', diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index ca16993..f209608 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -162,6 +162,18 @@ <arg name='domain' type='virDomainPtr' info='pointer to domain object'/> <arg name='params' type='virSchedParameterPtr' info='pointer to scheduler parameter objects'/> </function> + <function name='virDomainSetMemoryParameters' file='python'> + <info>Change the memory tunables</info> + <return type='int' info='-1 in case of error, 0 in case of success.'/> + <arg name='domain' type='virDomainPtr' info='pointer to domain object'/> + <arg name='params' type='virMemoryParameterPtr' info='pointer to memory tunable objects'/> + </function> + <function name='virDomainGetMemoryParameters' file='python'> + <info>Get the memory parameters, the @params array will be filled with the values.</info> + <return type='int' info='-1 in case of error, 0 in case of success.'/> + <arg name='domain' type='virDomainPtr' info='pointer to domain object'/> + <arg name='params' type='virMemoryParameterPtr' info='pointer to memory tunable objects'/> + </function> <function name='virConnectListStoragePools' file='python'> <info>list the storage pools, stores the pointers to the names in @names</info> <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 54a84c2..c43ab15 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -371,6 +371,20 @@ libvirt_virDomainSetSchedulerParameters(PyObject *self ATTRIBUTE_UNUSED, return VIR_PY_INT_SUCCESS; } +/* FIXME: This is a place holder for the implementation. */ +static PyObject * +libvirt_virDomainSetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + return VIR_PY_INT_FAIL; +} + +/* FIXME: This is a place holder for the implementation. */ +static PyObject * +libvirt_virDomainGetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + return VIR_PY_INT_FAIL; +} + static PyObject * libvirt_virDomainGetVcpus(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {

On Fri, Oct 08, 2010 at 05:44:48PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
This patch adds a structure virMemoryParameter, it contains the name of the parameter and the type of the parameter along with a union.
v4: + Add unsigned int flags to the public api for future extensions
v3: + Protoype for virDomainGetMemoryParameters and dummy python binding.
v2: + Includes dummy python bindings for the library to build cleanly. + Define string constants like "hard_limit", etc. + re-order this patch.
Okay, looks fine except :
+/** + * virDomainMemoryParameterType: + * + * A memory parameter field type + */ +typedef enum { + VIR_DOMAIN_MEMORY_FIELD_INT = 1, /* integer case */ + VIR_DOMAIN_MEMORY_FIELD_UINT = 2, /* unsigned integer case */ + VIR_DOMAIN_MEMORY_FIELD_LLONG = 3, /* long long case */ + VIR_DOMAIN_MEMORY_FIELD_ULLONG = 4, /* unsigned long long case */ + VIR_DOMAIN_MEMORY_FIELD_DOUBLE = 5, /* double case */ + VIR_DOMAIN_MEMORY_FIELD_BOOLEAN = 6 /* boolean(character) case */ +} virMemoryParameterType;
I'm renaming those to VIR_DOMAIN_MEMORY_PARAM_INT ... the 'field' is not an important information, but the fact it's a memory parameter type is the important point. [...]
+typedef virMemoryParameter *virMemoryParameterPtr; + +/* Set memory tunables for the domain*/ +int virDomainSetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int nparams, unsigned int flags); +int virDomainGetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int *nparams, unsigned int flags);
I also removed tabs here, we don't use tabs, please use "make syntax-check" otherwise looks fine, ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> Public api to set/get memory tunables supported by the hypervisors. RFC: https://www.redhat.com/archives/libvir-list/2010-August/msg00607.html v4: * Move exporting public API to this patch * Add unsigned int flags to the public api for future extensions v3: * Add domainGetMemoryParamters and NULL in all the driver interface v2: * Initialize domainSetMemoryParameters to NULL in all the driver interface structure. Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/driver.h | 14 ++++++ src/esx/esx_driver.c | 2 + src/libvirt.c | 104 ++++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 6 +++ src/lxc/lxc_driver.c | 2 + src/openvz/openvz_driver.c | 2 + src/phyp/phyp_driver.c | 2 + src/qemu/qemu_driver.c | 2 + src/remote/remote_driver.c | 2 + src/test/test_driver.c | 2 + src/uml/uml_driver.c | 2 + src/xen/xen_driver.c | 2 + 12 files changed, 142 insertions(+), 0 deletions(-) diff --git a/src/driver.h b/src/driver.h index e443c1c..32aeb04 100644 --- a/src/driver.h +++ b/src/driver.h @@ -128,6 +128,18 @@ typedef int (*virDrvDomainSetMemory) (virDomainPtr domain, unsigned long memory); typedef int + (*virDrvDomainSetMemoryParameters) + (virDomainPtr domain, + virMemoryParameterPtr params, + int nparams, + unsigned int flags); +typedef int + (*virDrvDomainGetMemoryParameters) + (virDomainPtr domain, + virMemoryParameterPtr params, + int *nparams, + unsigned int flags); +typedef int (*virDrvDomainGetInfo) (virDomainPtr domain, virDomainInfoPtr info); typedef int @@ -575,6 +587,8 @@ struct _virDriver { virDrvDomainRevertToSnapshot domainRevertToSnapshot; virDrvDomainSnapshotDelete domainSnapshotDelete; virDrvQemuDomainMonitorCommand qemuDomainMonitorCommand; + virDrvDomainSetMemoryParameters domainSetMemoryParameters; + virDrvDomainGetMemoryParameters domainGetMemoryParameters; }; typedef int diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index e382950..e959be2 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -4217,6 +4217,8 @@ static virDriver esxDriver = { esxDomainRevertToSnapshot, /* domainRevertToSnapshot */ esxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ + NULL, /* domainGetMemoryParameters */ }; diff --git a/src/libvirt.c b/src/libvirt.c index ca383ba..d964a44 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3000,6 +3000,110 @@ error: } /** + * virDomainSetMemoryParameters: + * @domain: pointer to domain object + * @params: pointer to memory parameter objects + * @nparams: number of memory parameter (this value should be same or + * less than the number of parameters supported) + * @flags: currently unused, for future extension + * + * Change the memory tunables + * This function requires privileged access to the hypervisor. + * + * Returns -1 in case of error, 0 in case of success. + */ +int +virDomainSetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int nparams, unsigned int flags) +{ + virConnectPtr conn; + DEBUG("domain=%p, params=%p, nparams=%d, flags=%u", domain, params, nparams, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + conn = domain->conn; + + if (conn->driver->domainSetMemoryParameters) { + int ret; + ret = conn->driver->domainSetMemoryParameters (domain, params, nparams, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + +/** + * virDomainGetMemoryParameters: + * @domain: pointer to domain object + * @params: pointer to memory parameter object + * (return value, allocated by the caller) + * @nparams: pointer to number of memory parameters + * @flags: currently unused, for future extension + * + * Get the memory parameters, the @params array will be filled with the values + * equal to the number of parameters suggested by @nparams + * + * As a special case, if @nparams is zero and @params is NULL, the API will + * set the number of parameters supported by the HV in @nparams and return + * SUCCESS. + * + * This function requires privileged access to the hypervisor. This function + * expects the caller to allocate the + * + * Returns -1 in case of error, 0 in case of success. + */ +int +virDomainGetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int *nparams, unsigned int flags) +{ + virConnectPtr conn; + DEBUG("domain=%p, params=%p, nparams=%d, flags=%u", domain, params, (nparams)?*nparams:-1, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + conn = domain->conn; + + if (conn->driver->domainGetMemoryParameters) { + int ret; + ret = conn->driver->domainGetMemoryParameters (domain, params, nparams, flags); + if (ret < 0) + goto error; + return ret; + } + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + +/** * virDomainGetInfo: * @domain: a domain object * @info: pointer to a virDomainInfo structure allocated by the user diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 849c163..fceb516 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -405,4 +405,10 @@ LIBVIRT_0.8.2 { virDomainCreateWithFlags; } LIBVIRT_0.8.1; +LIBVIRT_0.8.5 { + global: + virDomainSetMemoryParameters; + virDomainGetMemoryParameters; +} LIBVIRT_0.8.2; + # .... define new API here using predicted next version number .... diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 326fee6..a240e6d 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2620,6 +2620,8 @@ static virDriver lxcDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ + NULL, /* domainGetMemoryParameters */ }; static virStateDriver lxcStateDriver = { diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 1ad93d9..4247e0a 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1657,6 +1657,8 @@ static virDriver openvzDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ + NULL, /* domainGetMemoryParameters */ }; int openvzRegister(void) { diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 0a7d6f9..cf20624 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -4007,6 +4007,8 @@ static virDriver phypDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuMonitorCommand */ + NULL, /* domainSetMemoryParameters */ + NULL, /* domainGetMemoryParameters */ }; static virStorageDriver phypStorageDriver = { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 25695df..f44a18f 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12710,6 +12710,8 @@ static virDriver qemuDriver = { qemuDomainRevertToSnapshot, /* domainRevertToSnapshot */ qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ + NULL, /* domainGetMemoryParameters */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index acba01e..7337cad 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -10366,6 +10366,8 @@ static virDriver remote_driver = { remoteDomainRevertToSnapshot, /* domainRevertToSnapshot */ remoteDomainSnapshotDelete, /* domainSnapshotDelete */ remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ + NULL, /* domainGetMemoryParameters */ }; static virNetworkDriver network_driver = { diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 9d22339..906211c 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5327,6 +5327,8 @@ static virDriver testDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ + NULL, /* domainGetMemoryParameters */ }; static virNetworkDriver testNetworkDriver = { diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 9101928..1236abb 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2196,6 +2196,8 @@ static virDriver umlDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParamters */ + NULL, /* domainGetMemoryParamters */ }; static int diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 56ba41b..f958354 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -2006,6 +2006,8 @@ static virDriver xenUnifiedDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ + NULL, /* domainGetMemoryParameters */ }; /**

On Fri, Oct 08, 2010 at 05:45:00PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Public api to set/get memory tunables supported by the hypervisors. RFC: https://www.redhat.com/archives/libvir-list/2010-August/msg00607.html
v4: * Move exporting public API to this patch * Add unsigned int flags to the public api for future extensions
v3: * Add domainGetMemoryParamters and NULL in all the driver interface
v2: * Initialize domainSetMemoryParameters to NULL in all the driver interface structure.
[...]
--- a/src/libvirt.c +++ b/src/libvirt.c @@ -3000,6 +3000,110 @@ error: }
/** + * virDomainSetMemoryParameters: + * @domain: pointer to domain object + * @params: pointer to memory parameter objects + * @nparams: number of memory parameter (this value should be same or + * less than the number of parameters supported) + * @flags: currently unused, for future extension + * + * Change the memory tunables + * This function requires privileged access to the hypervisor. + * + * Returns -1 in case of error, 0 in case of success. + */ +int +virDomainSetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int nparams, unsigned int flags)
I had to remove tabs and trailing spaces at end of lines here.
+{ + virConnectPtr conn; + DEBUG("domain=%p, params=%p, nparams=%d, flags=%u", domain, params, nparams, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + }
Seems that params <= 0 or a NULL params are errors in this function based on the API description, so I prefer to catch those here and added if ((nparams <= 0) || (params == NULL)) { virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); goto error; }
+ conn = domain->conn; + + if (conn->driver->domainSetMemoryParameters) { [...] +/** + * virDomainGetMemoryParameters: + * @domain: pointer to domain object + * @params: pointer to memory parameter object + * (return value, allocated by the caller) + * @nparams: pointer to number of memory parameters + * @flags: currently unused, for future extension + * + * Get the memory parameters, the @params array will be filled with the values + * equal to the number of parameters suggested by @nparams + * + * As a special case, if @nparams is zero and @params is NULL, the API will + * set the number of parameters supported by the HV in @nparams and return + * SUCCESS. + * + * This function requires privileged access to the hypervisor. This function + * expects the caller to allocate the
unterminated comment. I fixed this as * expects the caller to allocate the @param
+ * Returns -1 in case of error, 0 in case of success. + */ +int +virDomainGetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int *nparams, unsigned int flags) +{
same tabs and trailing spaces problems
+ virConnectPtr conn; + DEBUG("domain=%p, params=%p, nparams=%d, flags=%u", domain, params, (nparams)?*nparams:-1, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + }
in that case params can be NULL, but nparams must not, and we can't have *nparams < 0 strictly so I'm adding: if ((nparams == NULL) || (*nparams < 0)) { virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); goto error; }
+ conn = domain->conn;
That done, patch is fine, ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On 10/12/2010 08:01 AM, Daniel Veillard wrote:
Seems that params<= 0 or a NULL params are errors in this function based on the API description, so I prefer to catch those here and added
if ((nparams<= 0) || (params == NULL)) { virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); goto error; }
Or even one step further, and use annotations to mark the function arguments as ATTRIBUTE_NONNULL to get compiler checking of your logic. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Tue, Oct 12, 2010 at 08:16:11AM -0600, Eric Blake wrote:
On 10/12/2010 08:01 AM, Daniel Veillard wrote:
Seems that params<= 0 or a NULL params are errors in this function based on the API description, so I prefer to catch those here and added
if ((nparams<= 0) || (params == NULL)) { virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); goto error; }
Or even one step further, and use annotations to mark the function arguments as ATTRIBUTE_NONNULL to get compiler checking of your logic.
That's only true if the client application has the neccessary compile time warnings enabled during their build. If you annotate a function with nonnull, the docs say this activates further compiler optimizations. So I'd be concerned that annotating the public APIs with nonnull might let the compiler optimize away that 'params == NULL' check to nothing. At which point the app using libvirt would be at risk if they had not enabled compile warnings to activate the annotation Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> The patch adds xml entries to the domain.rng file. v2: + Fix typo min_guarantee Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- docs/schemas/domain.rng | 31 +++++++++++++++++++++++++++++++ 1 files changed, 31 insertions(+), 0 deletions(-) diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 2e0457b..6cbace0 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -299,6 +299,37 @@ </optional> </element> </optional> + + <!-- All the memory/swap related tunables would go in the memtune --> + <optional> + <element name="memtune"> + <!-- Maximum memory the VM can use --> + <optional> + <element name="hard_limit"> + <ref name="memoryKB"/> + </element> + </optional> + <!-- Minimum memory ascertained for the VM during contention --> + <optional> + <element name="soft_limit"> + <ref name="memoryKB"/> + </element> + </optional> + <!-- Minimum amount of memory required to start the VM --> + <optional> + <element name="min_guarantee"> + <ref name="memoryKB"/> + </element> + </optional> + <!-- Maximum swap area the VM can use --> + <optional> + <element name="swap_hard_limit"> + <ref name="memoryKB"/> + </element> + </optional> + </element> + </optional> + <optional> <element name="vcpu"> <optional>

On Fri, Oct 08, 2010 at 05:45:12PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
The patch adds xml entries to the domain.rng file.
Except for spurious tabs, looks fine, ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> Adding parsing code for memory tunables in the domain xml file v4: * Add memtune in tests/qemuxml2xmltest.c * Fix: insert memtune element only when any of them is set v2: + Fix typo min_guarantee Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/conf/domain_conf.c | 54 +++++++++++++++++++--- src/conf/domain_conf.h | 12 ++++- src/esx/esx_vmx.c | 30 ++++++------ src/lxc/lxc_controller.c | 2 - src/lxc/lxc_driver.c | 12 ++--- src/openvz/openvz_driver.c | 8 ++- src/qemu/qemu_conf.c | 8 ++- src/qemu/qemu_driver.c | 18 ++++--- src/test/test_driver.c | 12 ++--- src/uml/uml_conf.c | 2 - src/uml/uml_driver.c | 14 +++--- tests/qemuxml2argvdata/qemuxml2argv-memtune.args | 1 tests/qemuxml2argvdata/qemuxml2argv-memtune.xml | 30 ++++++++++++ tests/qemuxml2xmltest.c | 1 14 files changed, 140 insertions(+), 64 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memtune.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memtune.xml diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 539d443..146e7a7 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -4235,19 +4235,38 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, def->description = virXPathString("string(./description[1])", ctxt); /* Extract domain memory */ - if (virXPathULong("string(./memory[1])", ctxt, &def->maxmem) < 0) { + if (virXPathULong("string(./memory[1])", ctxt, + &def->mem.max_balloon) < 0) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing memory element")); goto error; } - if (virXPathULong("string(./currentMemory[1])", ctxt, &def->memory) < 0) - def->memory = def->maxmem; + if (virXPathULong("string(./currentMemory[1])", ctxt, + &def->mem.cur_balloon) < 0) + def->mem.cur_balloon = def->mem.max_balloon; node = virXPathNode("./memoryBacking/hugepages", ctxt); if (node) - def->hugepage_backed = 1; - + def->mem.hugepage_backed = 1; + + /* Extract other memory tunables */ + if (virXPathULong("string(./memtune/hard_limit)", ctxt, + &def->mem.hard_limit) < 0) + def->mem.hard_limit = 0; + + if (virXPathULong("string(./memtune/soft_limit[1])", ctxt, + &def->mem.soft_limit) < 0) + def->mem.soft_limit = 0; + + if (virXPathULong("string(./memtune/min_guarantee[1])", ctxt, + &def->mem.min_guarantee) < 0) + def->mem.min_guarantee = 0; + + if (virXPathULong("string(./memtune/swap_hard_limit[1])", ctxt, + &def->mem.swap_hard_limit) < 0) + def->mem.swap_hard_limit = 0; + if (virXPathULong("string(./vcpu[1])", ctxt, &def->vcpus) < 0) def->vcpus = 1; @@ -6384,10 +6403,29 @@ char *virDomainDefFormat(virDomainDefPtr def, virBufferEscapeString(&buf, " <description>%s</description>\n", def->description); - virBufferVSprintf(&buf, " <memory>%lu</memory>\n", def->maxmem); + virBufferVSprintf(&buf, " <memory>%lu</memory>\n", def->mem.max_balloon); virBufferVSprintf(&buf, " <currentMemory>%lu</currentMemory>\n", - def->memory); - if (def->hugepage_backed) { + def->mem.cur_balloon); + + /* add memtune only if there are any */ + if(def->mem.hard_limit || def->mem.hard_limit || def->mem.hard_limit) + virBufferVSprintf(&buf, " <memtune>\n"); + if (def->mem.hard_limit) { + virBufferVSprintf(&buf, " <hard_limit>%lu</hard_limit>\n", + def->mem.hard_limit); + } + if (def->mem.soft_limit) { + virBufferVSprintf(&buf, " <soft_limit>%lu</soft_limit>\n", + def->mem.soft_limit); + } + if (def->mem.swap_hard_limit) { + virBufferVSprintf(&buf, " <swap_hard_limit>%lu</swap_hard_limit>\n", + def->mem.swap_hard_limit); + } + if(def->mem.hard_limit || def->mem.hard_limit || def->mem.hard_limit) + virBufferVSprintf(&buf, " </memtune>\n"); + + if (def->mem.hugepage_backed) { virBufferAddLit(&buf, " <memoryBacking>\n"); virBufferAddLit(&buf, " <hugepages/>\n"); virBufferAddLit(&buf, " </memoryBacking>\n"); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 9bf13d8..7c5215f 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -866,9 +866,15 @@ struct _virDomainDef { char *name; char *description; - unsigned long memory; - unsigned long maxmem; - unsigned char hugepage_backed; + struct { + unsigned long max_balloon; + unsigned long cur_balloon; + unsigned long hugepage_backed; + unsigned long hard_limit; + unsigned long soft_limit; + unsigned long min_guarantee; + unsigned long swap_hard_limit; + } mem; unsigned long vcpus; int cpumasklen; char *cpumask; diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c index bfebc4a..ece16b2 100644 --- a/src/esx/esx_vmx.c +++ b/src/esx/esx_vmx.c @@ -48,8 +48,8 @@ domain-xml <=> vmx def->id = <value> <=> ??? # not representable def->uuid = <value> <=> uuid.bios = "<value>" def->name = <value> <=> displayName = "<value>" -def->maxmem = <value kilobyte> <=> memsize = "<value megabyte>" # must be a multiple of 4, defaults to 32 -def->memory = <value kilobyte> <=> sched.mem.max = "<value megabyte>" # defaults to "unlimited" -> def->memory = def->maxmem +def->mem.max_balloon = <value kilobyte> <=> memsize = "<value megabyte>" # must be a multiple of 4, defaults to 32 +def->mem.cur_balloon = <value kilobyte> <=> sched.mem.max = "<value megabyte>" # defaults to "unlimited" -> def->mem.cur_balloon = def->mem.max_balloon def->vcpus = <value> <=> numvcpus = "<value>" # must be 1 or a multiple of 2, defaults to 1 def->cpumask = <uint list> <=> sched.cpu.affinity = "<uint list>" @@ -1012,7 +1012,7 @@ esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx, *tmp2 = '\0'; } - /* vmx:memsize -> def:maxmem */ + /* vmx:memsize -> def:mem.max_balloon */ if (esxUtil_GetConfigLong(conf, "memsize", &memsize, 32, true) < 0) { goto cleanup; } @@ -1024,7 +1024,7 @@ esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx, goto cleanup; } - def->maxmem = memsize * 1024; /* Scale from megabytes to kilobytes */ + def->mem.max_balloon = memsize * 1024; /* Scale from megabytes to kilobytes */ /* vmx:sched.mem.max -> def:memory */ if (esxUtil_GetConfigLong(conf, "sched.mem.max", &memory, memsize, @@ -1036,10 +1036,10 @@ esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx, memory = memsize; } - def->memory = memory * 1024; /* Scale from megabytes to kilobytes */ + def->mem.cur_balloon = memory * 1024; /* Scale from megabytes to kilobytes */ - if (def->memory > def->maxmem) { - def->memory = def->maxmem; + if (def->mem.cur_balloon > def->mem.max_balloon) { + def->mem.cur_balloon = def->mem.max_balloon; } /* vmx:numvcpus -> def:vcpus */ @@ -2578,32 +2578,32 @@ esxVMX_FormatConfig(esxVMX_Context *ctx, virCapsPtr caps, virDomainDefPtr def, virBufferVSprintf(&buffer, "annotation = \"%s\"\n", annotation); } - /* def:maxmem -> vmx:memsize */ - if (def->maxmem <= 0 || def->maxmem % 4096 != 0) { + /* def:mem.max_balloon -> vmx:memsize */ + if (def->mem.max_balloon <= 0 || def->mem.max_balloon % 4096 != 0) { ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Expecting domain XML entry 'memory' to be an unsigned " "integer (multiple of 4096) but found %lld"), - (unsigned long long)def->maxmem); + (unsigned long long)def->mem.max_balloon); goto cleanup; } /* Scale from kilobytes to megabytes */ virBufferVSprintf(&buffer, "memsize = \"%d\"\n", - (int)(def->maxmem / 1024)); + (int)(def->mem.max_balloon / 1024)); /* def:memory -> vmx:sched.mem.max */ - if (def->memory < def->maxmem) { - if (def->memory <= 0 || def->memory % 1024 != 0) { + if (def->mem.cur_balloon < def->mem.max_balloon) { + if (def->mem.cur_balloon <= 0 || def->mem.cur_balloon % 1024 != 0) { ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Expecting domain XML entry 'currentMemory' to be an " "unsigned integer (multiple of 1024) but found %lld"), - (unsigned long long)def->memory); + (unsigned long long)def->mem.cur_balloon); goto cleanup; } /* Scale from kilobytes to megabytes */ virBufferVSprintf(&buffer, "sched.mem.max = \"%d\"\n", - (int)(def->memory / 1024)); + (int)(def->mem.cur_balloon / 1024)); } /* def:vcpus -> vmx:numvcpus */ diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 7dc51a5..82ecce0 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -102,7 +102,7 @@ static int lxcSetContainerResources(virDomainDefPtr def) goto cleanup; } - rc = virCgroupSetMemory(cgroup, def->maxmem); + rc = virCgroupSetMemory(cgroup, def->mem.max_balloon); if (rc != 0) { virReportSystemError(-rc, _("Unable to set memory limit for domain %s"), diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index a240e6d..8977835 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -500,7 +500,7 @@ static int lxcDomainGetInfo(virDomainPtr dom, if (!virDomainObjIsActive(vm) || driver->cgroup == NULL) { info->cpuTime = 0; - info->memory = vm->def->memory; + info->memory = vm->def->mem.cur_balloon; } else { if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { lxcError(VIR_ERR_INTERNAL_ERROR, @@ -520,7 +520,7 @@ static int lxcDomainGetInfo(virDomainPtr dom, } } - info->maxMem = vm->def->maxmem; + info->maxMem = vm->def->mem.max_balloon; info->nrVirtCpu = 1; ret = 0; @@ -580,7 +580,7 @@ static unsigned long lxcDomainGetMaxMemory(virDomainPtr dom) { goto cleanup; } - ret = vm->def->maxmem; + ret = vm->def->mem.max_balloon; cleanup: if (vm) @@ -605,13 +605,13 @@ static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) { goto cleanup; } - if (newmax < vm->def->memory) { + if (newmax < vm->def->mem.cur_balloon) { lxcError(VIR_ERR_INVALID_ARG, "%s", _("Cannot set max memory lower than current memory")); goto cleanup; } - vm->def->maxmem = newmax; + vm->def->mem.max_balloon = newmax; ret = 0; cleanup: @@ -637,7 +637,7 @@ static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem) { goto cleanup; } - if (newmem > vm->def->maxmem) { + if (newmem > vm->def->mem.max_balloon) { lxcError(VIR_ERR_INVALID_ARG, "%s", _("Cannot set memory higher than max memory")); goto cleanup; diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 4247e0a..92cf4a1 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -403,8 +403,8 @@ static int openvzDomainGetInfo(virDomainPtr dom, } } - info->maxMem = vm->def->maxmem; - info->memory = vm->def->memory; + info->maxMem = vm->def->mem.max_balloon; + info->memory = vm->def->mem.cur_balloon; info->nrVirtCpu = vm->def->vcpus; ret = 0; @@ -934,8 +934,8 @@ openvzDomainDefineXML(virConnectPtr conn, const char *xml) } } - if (vm->def->memory > 0) { - if (openvzDomainSetMemoryInternal(vm, vm->def->memory) < 0) { + if (vm->def->mem.cur_balloon > 0) { + if (openvzDomainSetMemoryInternal(vm, vm->def->mem.cur_balloon) < 0) { openvzError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not set memory size")); goto cleanup; diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 7a37c70..731c554 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -3846,7 +3846,7 @@ int qemudBuildCommandLine(virConnectPtr conn, * is set post-startup using the balloon driver. If balloon driver * is not supported, then they're out of luck anyway */ - snprintf(memory, sizeof(memory), "%lu", def->maxmem/1024); + snprintf(memory, sizeof(memory), "%lu", def->mem.max_balloon/1024); snprintf(domid, sizeof(domid), "%d", def->id); ADD_ENV_LIT("LC_ALL=C"); @@ -3892,7 +3892,7 @@ int qemudBuildCommandLine(virConnectPtr conn, ADD_ARG_LIT("-enable-kvm"); ADD_ARG_LIT("-m"); ADD_ARG_LIT(memory); - if (def->hugepage_backed) { + if (def->mem.hugepage_backed) { if (!driver->hugetlbfs_mount) { qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("hugetlbfs filesystem is not mounted")); @@ -6119,7 +6119,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps, virUUIDGenerate(def->uuid); def->id = -1; - def->memory = def->maxmem = 64 * 1024; + def->mem.cur_balloon = def->mem.max_balloon = 64 * 1024; def->vcpus = 1; def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC; def->features = (1 << VIR_DOMAIN_FEATURE_ACPI) @@ -6234,7 +6234,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps, _("cannot parse memory level '%s'"), val); goto error; } - def->memory = def->maxmem = mem * 1024; + def->mem.cur_balloon = def->mem.max_balloon = mem * 1024; } else if (STREQ(arg, "-smp")) { WANT_VALUE(); if (qemuParseCommandLineSmp(def, val) < 0) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f44a18f..bf4373a 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3939,7 +3939,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, DEBUG0("Setting initial memory amount"); qemuDomainObjEnterMonitorWithDriver(driver, vm); - if (qemuMonitorSetBalloon(priv->mon, vm->def->memory) < 0) { + if (qemuMonitorSetBalloon(priv->mon, vm->def->mem.cur_balloon) < 0) { qemuDomainObjExitMonitorWithDriver(driver, vm); goto cleanup; } @@ -4862,7 +4862,7 @@ static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) { goto cleanup; } - ret = vm->def->maxmem; + ret = vm->def->mem.max_balloon; cleanup: if (vm) @@ -4893,7 +4893,7 @@ static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) { goto cleanup; } - if (newmem > vm->def->maxmem) { + if (newmem > vm->def->mem.max_balloon) { qemuReportError(VIR_ERR_INVALID_ARG, "%s", _("cannot set memory higher than max memory")); goto cleanup; @@ -4957,14 +4957,14 @@ static int qemudDomainGetInfo(virDomainPtr dom, } } - info->maxMem = vm->def->maxmem; + info->maxMem = vm->def->mem.max_balloon; if (virDomainObjIsActive(vm)) { qemuDomainObjPrivatePtr priv = vm->privateData; if ((vm->def->memballoon != NULL) && (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) { - info->memory = vm->def->maxmem; + info->memory = vm->def->mem.max_balloon; } else if (!priv->jobActive) { if (qemuDomainObjBeginJob(vm) < 0) goto cleanup; @@ -4980,7 +4980,7 @@ static int qemudDomainGetInfo(virDomainPtr dom, if (err == 0) /* Balloon not supported, so maxmem is always the allocation */ - info->memory = vm->def->maxmem; + info->memory = vm->def->mem.max_balloon; else info->memory = balloon; @@ -4989,10 +4989,10 @@ static int qemudDomainGetInfo(virDomainPtr dom, goto cleanup; } } else { - info->memory = vm->def->memory; + info->memory = vm->def->mem.cur_balloon; } } else { - info->memory = vm->def->memory; + info->memory = vm->def->mem.cur_balloon; } info->nrVirtCpu = vm->def->vcpus; @@ -6774,7 +6774,7 @@ static char *qemudDomainDumpXML(virDomainPtr dom, if (err < 0) goto cleanup; if (err > 0) - vm->def->memory = balloon; + vm->def->mem.cur_balloon = balloon; /* err == 0 indicates no balloon support, so ignore it */ } } diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 906211c..7d4d119 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -1681,8 +1681,8 @@ static int testGetDomainInfo (virDomainPtr domain, } info->state = privdom->state; - info->memory = privdom->def->memory; - info->maxMem = privdom->def->maxmem; + info->memory = privdom->def->mem.cur_balloon; + info->maxMem = privdom->def->mem.max_balloon; info->nrVirtCpu = privdom->def->vcpus; info->cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll)); ret = 0; @@ -1963,7 +1963,7 @@ static unsigned long testGetMaxMemory(virDomainPtr domain) { goto cleanup; } - ret = privdom->def->maxmem; + ret = privdom->def->mem.max_balloon; cleanup: if (privdom) @@ -1989,7 +1989,7 @@ static int testSetMaxMemory(virDomainPtr domain, } /* XXX validate not over host memory wrt to other domains */ - privdom->def->maxmem = memory; + privdom->def->mem.max_balloon = memory; ret = 0; cleanup: @@ -2015,12 +2015,12 @@ static int testSetMemory(virDomainPtr domain, goto cleanup; } - if (memory > privdom->def->maxmem) { + if (memory > privdom->def->mem.max_balloon) { testError(VIR_ERR_INVALID_ARG, __FUNCTION__); goto cleanup; } - privdom->def->memory = memory; + privdom->def->mem.cur_balloon = memory; ret = 0; cleanup: diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index f2eaef5..33b2b04 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -502,7 +502,7 @@ int umlBuildCommandLine(virConnectPtr conn, } \ } while (0) - snprintf(memory, sizeof(memory), "%luK", vm->def->memory); + snprintf(memory, sizeof(memory), "%luK", vm->def->mem.cur_balloon); ADD_ENV_LIT("LC_ALL=C"); diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 1236abb..e195541 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1420,7 +1420,7 @@ static unsigned long umlDomainGetMaxMemory(virDomainPtr dom) { _("no domain with matching uuid '%s'"), uuidstr); goto cleanup; } - ret = vm->def->maxmem; + ret = vm->def->mem.max_balloon; cleanup: if (vm) @@ -1446,13 +1446,13 @@ static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) { goto cleanup; } - if (newmax < vm->def->memory) { + if (newmax < vm->def->mem.cur_balloon) { umlReportError(VIR_ERR_INVALID_ARG, "%s", _("cannot set max memory lower than current memory")); goto cleanup; } - vm->def->maxmem = newmax; + vm->def->mem.max_balloon = newmax; ret = 0; cleanup: @@ -1485,13 +1485,13 @@ static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) { goto cleanup; } - if (newmem > vm->def->maxmem) { + if (newmem > vm->def->mem.max_balloon) { umlReportError(VIR_ERR_INVALID_ARG, "%s", _("cannot set memory higher than max memory")); goto cleanup; } - vm->def->memory = newmem; + vm->def->mem.cur_balloon = newmem; ret = 0; cleanup: @@ -1528,8 +1528,8 @@ static int umlDomainGetInfo(virDomainPtr dom, } } - info->maxMem = vm->def->maxmem; - info->memory = vm->def->memory; + info->maxMem = vm->def->mem.max_balloon; + info->memory = vm->def->mem.cur_balloon; info->nrVirtCpu = vm->def->vcpus; ret = 0; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-memtune.args b/tests/qemuxml2argvdata/qemuxml2argv-memtune.args new file mode 100644 index 0000000..50da44f --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-memtune.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -name QEMUGuest1 -nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-memtune.xml b/tests/qemuxml2argvdata/qemuxml2argv-memtune.xml new file mode 100644 index 0000000..9f713f0 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-memtune.xml @@ -0,0 +1,30 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <memtune> + <hard_limit>512000</hard_limit> + <soft_limit>128000</soft_limit> + <swap_hard_limit>1024000</swap_hard_limit> + </memtune> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 904183c..a33d435 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -178,6 +178,7 @@ mymain(int argc, char **argv) DO_TEST("hostdev-pci-address"); DO_TEST("encrypted-disk"); + DO_TEST("memtune"); /* These tests generate different XML */ DO_TEST_DIFFERENT("balloon-device-auto");

On Fri, Oct 08, 2010 at 05:45:23PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Adding parsing code for memory tunables in the domain xml file
v4: * Add memtune in tests/qemuxml2xmltest.c * Fix: insert memtune element only when any of them is set
v2: + Fix typo min_guarantee
The patch is fine except the usual space and tabs mixups and the fact that a number of drivers still needed to be converted to the change of the definition structure. "grep -- "->memory" src/*/*" isn't that hard and would have shown that even the driver for your own IBM Phyp hardware failed to compile after your patch !! anyway once cleaned up the patch makes sensei, ACK, but please use "make syntax-check" and do not configure out drivers when you are developping patches, thanks, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

2010/10/12 Daniel Veillard <veillard@redhat.com>:
On Fri, Oct 08, 2010 at 05:45:23PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Adding parsing code for memory tunables in the domain xml file
v4: * Add memtune in tests/qemuxml2xmltest.c * Fix: insert memtune element only when any of them is set
v2: + Fix typo min_guarantee
 The patch is fine except the usual space and tabs mixups and the fact that a number of drivers still needed to be converted to the change of the definition structure. "grep -- "->memory" src/*/*" isn't that hard and would have shown that even the driver for your own IBM Phyp hardware failed to compile after your patch !!
 anyway once cleaned up the patch makes sensei, ACK, but please use "make syntax-check" and do not configure out drivers when you are developping patches,
 thanks,
Daniel
This patch should have added documentation about the new XML elements to docs/formatdomain.html.in. Matthias

On Tue, Oct 12, 2010 at 09:33:03PM +0200, Matthias Bolte wrote:
2010/10/12 Daniel Veillard <veillard@redhat.com>:
On Fri, Oct 08, 2010 at 05:45:23PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Adding parsing code for memory tunables in the domain xml file
v4: * Add memtune in tests/qemuxml2xmltest.c * Fix: insert memtune element only when any of them is set
v2: + Fix typo min_guarantee
 The patch is fine except the usual space and tabs mixups and the fact that a number of drivers still needed to be converted to the change of the definition structure. "grep -- "->memory" src/*/*" isn't that hard and would have shown that even the driver for your own IBM Phyp hardware failed to compile after your patch !!
 anyway once cleaned up the patch makes sensei, ACK, but please use "make syntax-check" and do not configure out drivers when you are developping patches,
 thanks,
Daniel
This patch should have added documentation about the new XML elements to docs/formatdomain.html.in.
right! virsh man page need to be completed too, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, 12 Oct 2010 16:54:39 +0200, Daniel Veillard <veillard@redhat.com> wrote:
On Fri, Oct 08, 2010 at 05:45:23PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Adding parsing code for memory tunables in the domain xml file
v4: * Add memtune in tests/qemuxml2xmltest.c * Fix: insert memtune element only when any of them is set
v2: + Fix typo min_guarantee
The patch is fine except the usual space and tabs mixups and the fact that a number of drivers still needed to be converted to the change of the definition structure. "grep -- "->memory" src/*/*" isn't that hard and would have shown that even the driver for your own IBM Phyp hardware failed to compile after your patch !!
anyway once cleaned up the patch makes sensei, ACK, but please use "make syntax-check" and do not configure out drivers when you are developping patches,
Thanks Daniel, Did not know about the make syntax-check. And as you guessed, I did not compile it for other drivers, just went out of my mind, I will take care next time. Regards, Nikunj

On Wed, Oct 13, 2010 at 10:39:00AM +0530, Nikunj A. Dadhania wrote:
On Tue, 12 Oct 2010 16:54:39 +0200, Daniel Veillard <veillard@redhat.com> wrote:
anyway once cleaned up the patch makes sensei, ACK, but please use "make syntax-check" and do not configure out drivers when you are developping patches,
Thanks Daniel,
Did not know about the make syntax-check. And as you guessed, I did not compile it for other drivers, just went out of my mind, I will take care next time.
Okay, HACKING in the git checkout and http://libvirt.org/hacking.html gives a set of advices for people developping patches it lists "make syntax-check" and also suggestsi ./configure --enable-compile-warnings=error which would likely have caught the C&P error in the remote code. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> Provides interfaces for setting/getting memory tunables like hard_limit, soft_limit and swap_hard_limit Acked-by: Balbir Singh <balbir@linux.vnet.ibm.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/libvirt_private.syms | 6 +++ src/util/cgroup.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/cgroup.h | 7 +++ 3 files changed, 119 insertions(+), 0 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 301b0ef..09b108c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -77,6 +77,12 @@ virCgroupControllerTypeFromString; virCgroupGetCpuacctUsage; virCgroupGetFreezerState; virCgroupSetFreezerState; +virCgroupSetMemoryHardLimit; +virCgroupGetMemoryHardLimit; +virCgroupSetMemorySoftLimit; +virCgroupGetMemorySoftLimit; +virCgroupSetSwapHardLimit; +virCgroupGetSwapHardLimit; # cpu.h diff --git a/src/util/cgroup.c b/src/util/cgroup.c index 024036a..f94db12 100644 --- a/src/util/cgroup.c +++ b/src/util/cgroup.c @@ -874,6 +874,112 @@ int virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb) } /** + * virCgroupSetMemoryHardLimit: + * + * @group: The cgroup to change memory hard limit for + * @kb: The memory amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupSetMemoryHardLimit(virCgroupPtr group, unsigned long kb) +{ + return virCgroupSetMemory(group, kb); +} + +/** + * virCgroupGetMemoryHardLimit: + * + * @group: The cgroup to get the memory hard limit for + * @kb: The memory amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupGetMemoryHardLimit(virCgroupPtr group, unsigned long *kb) +{ + long long unsigned int limit_in_bytes; + int ret; + ret = virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.limit_in_bytes", &limit_in_bytes); + if (ret == 0) + *kb = (unsigned long) limit_in_bytes >> 10; + return ret; +} + +/** + * virCgroupSetMemorySoftLimit: + * + * @group: The cgroup to change memory soft limit for + * @kb: The memory amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long kb) +{ + return virCgroupSetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.soft_limit_in_bytes", + kb << 10); +} + + +/** + * virCgroupGetMemorySoftLimit: + * + * @group: The cgroup to get the memory soft limit for + * @kb: The memory amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long *kb) +{ + long long unsigned int limit_in_bytes; + int ret; + ret = virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.soft_limit_in_bytes", &limit_in_bytes); + if (ret == 0) + *kb = (unsigned long) limit_in_bytes >> 10; + return ret; +} + +/** + * virCgroupSetSwapHardLimit: + * + * @group: The cgroup to change swap hard limit for + * @kb: The swap amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupSetSwapHardLimit(virCgroupPtr group, unsigned long kb) +{ + return virCgroupSetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.memsw.limit_in_bytes", + kb << 10); +} + +/** + * virCgroupGetSwapHardLimit: + * + * @group: The cgroup to get swap hard limit for + * @kb: The swap amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupGetSwapHardLimit(virCgroupPtr group, unsigned long *kb) +{ + long long unsigned int limit_in_bytes; + int ret; + ret = virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.memsw.limit_in_bytes", &limit_in_bytes); + if (ret == 0) + *kb = (unsigned long) limit_in_bytes >> 10; + return ret; +} + +/** * virCgroupDenyAllDevices: * * @group: The cgroup to deny devices for diff --git a/src/util/cgroup.h b/src/util/cgroup.h index 2bea49f..b8f2d08 100644 --- a/src/util/cgroup.h +++ b/src/util/cgroup.h @@ -43,6 +43,13 @@ int virCgroupAddTask(virCgroupPtr group, pid_t pid); int virCgroupSetMemory(virCgroupPtr group, unsigned long kb); int virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb); +int virCgroupSetMemoryHardLimit(virCgroupPtr group, unsigned long kb); +int virCgroupGetMemoryHardLimit(virCgroupPtr group, unsigned long *kb); +int virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long kb); +int virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long *kb); +int virCgroupSetSwapHardLimit(virCgroupPtr group, unsigned long kb); +int virCgroupGetSwapHardLimit(virCgroupPtr group, unsigned long *kb); + int virCgroupDenyAllDevices(virCgroupPtr group); int virCgroupAllowDevice(virCgroupPtr group,

On Fri, Oct 08, 2010 at 05:45:34PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Provides interfaces for setting/getting memory tunables like hard_limit, soft_limit and swap_hard_limit
ACK, just one extra misplaced space, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> Driver interface for setting memory hard_limit, soft_limit and swap hard_limit. v4: + prototype change: include "unsigned int flags" arg v2: + Use #define string constants for "hard_limit", etc. + fix typo: min_guarantee Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/qemu/qemu_driver.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 94 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index bf4373a..471db39 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -9365,6 +9365,99 @@ cleanup: return ret; } + +static int qemuDomainSetMemoryParameters(virDomainPtr dom, + virMemoryParameterPtr params, + int nparams, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct qemud_driver *driver = dom->conn->privateData; + int i; + virCgroupPtr group = NULL; + virDomainObjPtr vm = NULL; + int ret = -1; + + qemuDriverLock(driver); + if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) { + qemuReportError(VIR_ERR_NO_SUPPORT, + __FUNCTION__); + goto cleanup; + } + + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (vm == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("No such domain %s"), dom->uuid); + goto cleanup; + } + + if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find cgroup for domain %s"), vm->def->name); + goto cleanup; + } + + for (i = 0; i < nparams; i++) { + virMemoryParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) { + int rc; + if (param->type != VIR_DOMAIN_MEMORY_FIELD_ULLONG) { + qemuReportError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for memory hard_limit tunable, expected a 'ullong'")); + continue; + } + + rc = virCgroupSetMemoryHardLimit(group, params[i].value.ul); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to set memory hard_limit tunable")); + } + } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) { + int rc; + if (param->type != VIR_DOMAIN_MEMORY_FIELD_ULLONG) { + qemuReportError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for memory soft_limit tunable, expected a 'ullong'")); + continue; + } + + rc = virCgroupSetMemorySoftLimit(group, params[i].value.ul); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to set memory soft_limit tunable")); + } + } else if (STREQ(param->field, VIR_DOMAIN_SWAP_HARD_LIMIT)) { + int rc; + if (param->type != VIR_DOMAIN_MEMORY_FIELD_ULLONG) { + qemuReportError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for swap_hard_limit tunable, expected a 'ullong'")); + continue; + } + + rc = virCgroupSetSwapHardLimit(group, params[i].value.ul); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to set swap_hard_limit tunable")); + } + } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) { + qemuReportError(VIR_ERR_INVALID_ARG, + _("Memory tunable `%s' not implemented"), param->field); + } else { + qemuReportError(VIR_ERR_INVALID_ARG, + _("Parameter `%s' not supported"), param->field); + } + } + ret = 0; + +cleanup: + virCgroupFree(&group); + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + static int qemuSetSchedulerParameters(virDomainPtr dom, virSchedParameterPtr params, int nparams) @@ -12710,7 +12803,7 @@ static virDriver qemuDriver = { qemuDomainRevertToSnapshot, /* domainRevertToSnapshot */ qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ - NULL, /* domainSetMemoryParameters */ + qemuDomainSetMemoryParameters, /* domainSetMemoryParameters */ NULL, /* domainGetMemoryParameters */ };

On Fri, Oct 08, 2010 at 05:45:44PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Driver interface for setting memory hard_limit, soft_limit and swap hard_limit. [...] +static int qemuDomainSetMemoryParameters(virDomainPtr dom, + virMemoryParameterPtr params, + int nparams, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct qemud_driver *driver = dom->conn->privateData; + int i; + virCgroupPtr group = NULL; + virDomainObjPtr vm = NULL; + int ret = -1; + + qemuDriverLock(driver); + if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) { + qemuReportError(VIR_ERR_NO_SUPPORT, + __FUNCTION__); + goto cleanup; + } + + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (vm == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("No such domain %s"), dom->uuid); + goto cleanup; + } + + if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find cgroup for domain %s"), vm->def->name); + goto cleanup; + } + + for (i = 0; i < nparams; i++) { + virMemoryParameterPtr param = ¶ms[i];
Bingo if you passed a NULL pointer at the library entry point this would just crash. Well you can still get this to crash with a value of nparams bigger than the array. It's one of my main concern with this API, it's a bit easy for the user to get things wrong, at least we should provide minimal checkings. I still prefer to keep those checks in the top function in libvirt.c to avoid duplicating in all drivers, but here we could check that nparams is between 1 and 3 c.f. the comment on next patch: + /* Current number of memory parameters supported by cgroups is 3 + * FIXME: Magic number, need to see where should this go + */ + *nparams = 3; that 3 need to be abstracted somehow as #define QEMU_NB_MEM_PARAM 3 which I'm adding at the beginning of the file. However if we check that nparams > 3, we will introduce an incompatibility, for example if we try to set tunables from a newver library version but talking to an older server not implementing the new ones, we return an error, but ... [...]
+ } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) { + qemuReportError(VIR_ERR_INVALID_ARG, + _("Memory tunable `%s' not implemented"), param->field); + } else { + qemuReportError(VIR_ERR_INVALID_ARG, + _("Parameter `%s' not supported"), param->field); + }
right now the code just ignores if you failed to set a tunable. I think this is a problem, we should at least return an error if a tunable could not be set. Right now the error would be raised within libvirt daemon but since there is no error code the application may not get the problem. So in those 2 cases I suggest to set an error. So I'm changing this to set ret to 0 before the loop and setting ret = -1; in any of the error cases found within.
+ } + ret = 0;
moved in front of loop. Quite a bit of change but once done I commited it to my tree Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> V4: * prototype change: add unsigned int flags Driver interface for getting memory parameters, eg. hard_limit, soft_limit and swap_hard_limit. Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/qemu/qemu_driver.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 119 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 471db39..8eaa762 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -9458,6 +9458,124 @@ cleanup: return ret; } +static int qemuDomainGetMemoryParameters(virDomainPtr dom, + virMemoryParameterPtr params, + int *nparams, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct qemud_driver *driver = dom->conn->privateData; + int i; + virCgroupPtr group = NULL; + virDomainObjPtr vm = NULL; + unsigned long val; + int ret = -1; + int rc; + + qemuDriverLock(driver); + + if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) { + qemuReportError(VIR_ERR_NO_SUPPORT, + __FUNCTION__); + goto cleanup; + } + + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (vm == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("No such domain %s"), dom->uuid); + goto cleanup; + } + + if ((*nparams) == 0) { + /* Current number of memory parameters supported by cgroups is 3 + * FIXME: Magic number, need to see where should this go + */ + *nparams = 3; + ret = 0; + goto cleanup; + } + + if ((*nparams) != 3) { + qemuReportError(VIR_ERR_INVALID_ARG, + "%s", _("Invalid parameter count")); + goto cleanup; + } + + if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find cgroup for domain %s"), vm->def->name); + goto cleanup; + } + + for (i = 0; i < *nparams; i++) { + virMemoryParameterPtr param = ¶ms[i]; + val = 0; + param->value.ul = 0; + param->type = VIR_DOMAIN_MEMORY_FIELD_ULLONG; + + switch(i) { + case 0: /* fill memory hard limit here */ + rc = virCgroupGetMemoryHardLimit(group, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get memory hard limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field memory hard limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + case 1: /* fill memory soft limit here */ + rc = virCgroupGetMemorySoftLimit(group, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get memory soft limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field memory soft limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + case 2: /* fill swap hard limit here */ + rc = virCgroupGetSwapHardLimit(group, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get swap hard limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_SWAP_HARD_LIMIT) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field swap hard limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + default: + break; + /* should not hit here */ + } + } + ret = 0; + +cleanup: + if (group) + virCgroupFree(&group); + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + static int qemuSetSchedulerParameters(virDomainPtr dom, virSchedParameterPtr params, int nparams) @@ -12804,7 +12922,7 @@ static virDriver qemuDriver = { qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ qemuDomainSetMemoryParameters, /* domainSetMemoryParameters */ - NULL, /* domainGetMemoryParameters */ + qemuDomainGetMemoryParameters, /* domainGetMemoryParameters */ };

On Fri, Oct 08, 2010 at 05:45:55PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
V4: * prototype change: add unsigned int flags
Driver interface for getting memory parameters, eg. hard_limit, soft_limit and swap_hard_limit.
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/qemu/qemu_driver.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 119 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 471db39..8eaa762 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -9458,6 +9458,124 @@ cleanup: return ret; }
same things about crashing if the arguments are invalid
+ if ((*nparams) == 0) { + /* Current number of memory parameters supported by cgroups is 3 + * FIXME: Magic number, need to see where should this go + */ + *nparams = 3; + ret = 0; + goto cleanup; + } + + if ((*nparams) != 3) {
using QEMU_NB_MEM_PARAM instead of the raw 3 value c.f. previous patch comment
+ qemuReportError(VIR_ERR_INVALID_ARG, + "%s", _("Invalid parameter count")); + goto cleanup; + }
okay, this mean the application must always call with 0 first to get the exact value or this will break, fine but probably need to be made more clear from the description in libvirt.c .... TODO
+ if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find cgroup for domain %s"), vm->def->name); + goto cleanup; + } + + for (i = 0; i < *nparams; i++) { + virMemoryParameterPtr param = ¶ms[i]; + val = 0; + param->value.ul = 0; + param->type = VIR_DOMAIN_MEMORY_FIELD_ULLONG; + + switch(i) { + case 0: /* fill memory hard limit here */ + rc = virCgroupGetMemoryHardLimit(group, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get memory hard limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field memory hard limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + case 1: /* fill memory soft limit here */ + rc = virCgroupGetMemorySoftLimit(group, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get memory soft limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field memory soft limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + case 2: /* fill swap hard limit here */ + rc = virCgroupGetSwapHardLimit(group, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get swap hard limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_SWAP_HARD_LIMIT) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field swap hard limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + default: + break; + /* should not hit here */ + } + }
Okay, I'm not sure we actually need a loop here, but it may help refactoring... I'm still having a problem with the code ignoring any error occuring in the loop, and fixing this in the same way. If there is an error the application *must* learn about it instead of trusting uninitialized memory as being data ! Maybe a memset is in order actually before entering that loop to avoid edge case problems... TODO too
+ ret = 0; + +cleanup: + if (group) + virCgroupFree(&group); + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + static int qemuSetSchedulerParameters(virDomainPtr dom, virSchedParameterPtr params, int nparams) @@ -12804,7 +12922,7 @@ static virDriver qemuDriver = { qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ qemuDomainSetMemoryParameters, /* domainSetMemoryParameters */ - NULL, /* domainGetMemoryParameters */ + qemuDomainGetMemoryParameters, /* domainGetMemoryParameters */ };
Okay, once heavilly patched as described, ACK, I commited this to my tree, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, 12 Oct 2010 17:51:54 +0200, Daniel Veillard <veillard@redhat.com> wrote:
On Fri, Oct 08, 2010 at 05:45:55PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
V4: * prototype change: add unsigned int flags
Driver interface for getting memory parameters, eg. hard_limit, soft_limit and swap_hard_limit.
+ qemuReportError(VIR_ERR_INVALID_ARG, + "%s", _("Invalid parameter count")); + goto cleanup; + }
okay, this mean the application must always call with 0 first to get the exact value or this will break, fine but probably need to be made more clear from the description in libvirt.c .... TODO
+ if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find cgroup for domain %s"), vm->def->name); + goto cleanup; + } + + for (i = 0; i < *nparams; i++) { + virMemoryParameterPtr param = ¶ms[i]; + val = 0; + param->value.ul = 0; + param->type = VIR_DOMAIN_MEMORY_FIELD_ULLONG; + + switch(i) { + case 0: /* fill memory hard limit here */ + rc = virCgroupGetMemoryHardLimit(group, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get memory hard limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field memory hard limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + case 1: /* fill memory soft limit here */ + rc = virCgroupGetMemorySoftLimit(group, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get memory soft limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field memory soft limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + case 2: /* fill swap hard limit here */ + rc = virCgroupGetSwapHardLimit(group, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get swap hard limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_SWAP_HARD_LIMIT) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field swap hard limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + default: + break; + /* should not hit here */ + } + }
Okay, I'm not sure we actually need a loop here, but it may help refactoring... I guess this is related to my previous thinking, if nparams < QEMU_NB_MEM_PARAM, fill only till nparams and return. But with the change of
Sure, I will take care of updating the api desc in libvirt.c, I haven't used word always there. the logic, I think loop may not be required now.
I'm still having a problem with the code ignoring any error occuring in the loop, and fixing this in the same way. If there is an error the application *must* learn about it instead of trusting uninitialized memory as being data ! Maybe a memset is in order actually before entering that loop to avoid edge case problems... TODO too
By TODO you mean the error handling, right? I am taking care of setting the values to zero currently, and it does not tell the application whether to use this value or not. One option could be adding VIR_DOMAIN_MEMORY_INVALID in virMemoryParameterType and setting it in the beginning of the loop. Comments? Nikunj

On Wed, Oct 13, 2010 at 10:57:17AM +0530, Nikunj A. Dadhania wrote:
On Tue, 12 Oct 2010 17:51:54 +0200, Daniel Veillard <veillard@redhat.com> wrote:
On Fri, Oct 08, 2010 at 05:45:55PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
V4: * prototype change: add unsigned int flags
Driver interface for getting memory parameters, eg. hard_limit, soft_limit and swap_hard_limit.
+ qemuReportError(VIR_ERR_INVALID_ARG, + "%s", _("Invalid parameter count")); + goto cleanup; + }
okay, this mean the application must always call with 0 first to get the exact value or this will break, fine but probably need to be made more clear from the description in libvirt.c .... TODO
Sure, I will take care of updating the api desc in libvirt.c, I haven't used word always there.
+ if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find cgroup for domain %s"), vm->def->name); + goto cleanup; + } + + for (i = 0; i < *nparams; i++) { + virMemoryParameterPtr param = ¶ms[i]; + val = 0; + param->value.ul = 0; + param->type = VIR_DOMAIN_MEMORY_FIELD_ULLONG; + + switch(i) { + case 0: /* fill memory hard limit here */ + rc = virCgroupGetMemoryHardLimit(group, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get memory hard limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field memory hard limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + case 1: /* fill memory soft limit here */ + rc = virCgroupGetMemorySoftLimit(group, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get memory soft limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field memory soft limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + case 2: /* fill swap hard limit here */ + rc = virCgroupGetSwapHardLimit(group, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get swap hard limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_SWAP_HARD_LIMIT) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field swap hard limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + default: + break; + /* should not hit here */ + } + }
Okay, I'm not sure we actually need a loop here, but it may help refactoring... I guess this is related to my previous thinking, if nparams < QEMU_NB_MEM_PARAM, fill only till nparams and return. But with the change of the logic, I think loop may not be required now.
I think keeping the loop is fine at this point, even if not strictly necessary.
I'm still having a problem with the code ignoring any error occuring in the loop, and fixing this in the same way. If there is an error the application *must* learn about it instead of trusting uninitialized memory as being data ! Maybe a memset is in order actually before entering that loop to avoid edge case problems... TODO too
By TODO you mean the error handling, right?
the error handling is done, I fixed those before commiting. Please fetch the new git tree before trying to make any further patches.
I am taking care of setting the values to zero currently, and it does not tell the application whether to use this value or not. One option could be adding VIR_DOMAIN_MEMORY_INVALID in virMemoryParameterType and setting it in the beginning of the loop. Comments?
That would be one way for the user when getting back an error to find out if there were still useful values. It makes the application more complex, and using that call is already too complex IMHO. If we fail in the loop, it's a internal error using cgroups, not sure the user should trust any returned values in that case. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> v4: * Fix: call cgroup apis only if tunables are non zero QEmu startup would pick up the memory tunables specified in the domain configuration file. Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/qemu/qemu.conf | 4 ++-- src/qemu/qemu_conf.c | 3 ++- src/qemu/qemu_driver.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index dc8eb83..bfb9f6a 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -111,13 +111,13 @@ # the adminsitrator has mounted cgroups. eg # # mkdir /dev/cgroup -# mount -t cgroup -o devices,cpu none /dev/cgroup +# mount -t cgroup -o devices,cpu,memory none /dev/cgroup # # They can be mounted anywhere, and different controlers # can be mounted in different locations. libvirt will detect # where they are located. # -# cgroup_controllers = [ "cpu", "devices" ] +# cgroup_controllers = [ "cpu", "devices", "memory" ] # This is the basic set of devices allowed / required by # all virtual machines. diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 731c554..3f5c1ac 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -275,7 +275,8 @@ int qemudLoadDriverConfig(struct qemud_driver *driver, } else { driver->cgroupControllers = (1 << VIR_CGROUP_CONTROLLER_CPU) | - (1 << VIR_CGROUP_CONTROLLER_DEVICES); + (1 << VIR_CGROUP_CONTROLLER_DEVICES) | + (1 << VIR_CGROUP_CONTROLLER_MEMORY); } for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { if (driver->cgroupControllers & (1 << i)) { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8eaa762..70b9bac 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3495,6 +3495,40 @@ static int qemuSetupCgroup(struct qemud_driver *driver, goto cleanup; } + if ((rc = qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY))) { + if (vm->def->mem.hard_limit != 0) { + rc = virCgroupSetMemoryHardLimit(cgroup, vm->def->mem.hard_limit); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set memory hard limit for domain %s"), + vm->def->name); + goto cleanup; + } + } + if (vm->def->mem.soft_limit != 0) { + rc = virCgroupSetMemorySoftLimit(cgroup, vm->def->mem.soft_limit); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set memory soft limit for domain %s"), + vm->def->name); + goto cleanup; + } + } + + if (vm->def->mem.swap_hard_limit != 0) { + rc = virCgroupSetSwapHardLimit(cgroup, vm->def->mem.swap_hard_limit); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set swap hard limit for domain %s"), + vm->def->name); + goto cleanup; + } + } + } else { + VIR_WARN("Memory cgroup is disabled in qemu configuration file: %s", + vm->def->name); + } + done: virCgroupFree(&cgroup); return 0;

On Fri, Oct 08, 2010 at 05:46:05PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
v4: * Fix: call cgroup apis only if tunables are non zero
QEmu startup would pick up the memory tunables specified in the domain configuration file.
Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> v4: * Fix: call cgroup apis only if tunables are non zero v1: libvirt-lxc now configures the hardlimit, softlimit and swaplimit, if specified in the domain xml file or picks up the defaults. Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/lxc/lxc_controller.c | 30 ++++++++++++++++++++++++++++++ 1 files changed, 30 insertions(+), 0 deletions(-) diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 82ecce0..258130d 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -109,6 +109,36 @@ static int lxcSetContainerResources(virDomainDefPtr def) def->name); goto cleanup; } + + if(def->mem.hard_limit) { + rc = virCgroupSetMemoryHardLimit(cgroup, def->mem.hard_limit); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set memory hard limit for domain %s"), + def->name); + goto cleanup; + } + } + + if(def->mem.soft_limit) { + rc = virCgroupSetMemorySoftLimit(cgroup, def->mem.soft_limit); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set memory soft limit for domain %s"), + def->name); + goto cleanup; + } + } + + if(def->mem.swap_hard_limit) { + rc = virCgroupSetSwapHardLimit(cgroup, def->mem.swap_hard_limit); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set swap hard limit for domain %s"), + def->name); + goto cleanup; + } + } rc = virCgroupDenyAllDevices(cgroup); if (rc != 0) {

On Fri, Oct 08, 2010 at 05:46:15PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
v4: * Fix: call cgroup apis only if tunables are non zero
v1: libvirt-lxc now configures the hardlimit, softlimit and swaplimit, if specified in the domain xml file or picks up the defaults.
Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> Add support in the lxc driver for various memory controllable parameters v4: + prototype change: add unsigned int flags v2: + Use #define string constants for "hard_limit", etc + fix typo: min_guarantee Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/lxc/lxc_driver.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 90 insertions(+), 1 deletions(-) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 8977835..984a5fa 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -677,6 +677,95 @@ cleanup: return ret; } +static int lxcDomainSetMemoryParameters(virDomainPtr dom, + virMemoryParameterPtr params, + int nparams, + unsigned int flags ATTRIBUTE_UNUSED) +{ + lxc_driver_t *driver = dom->conn->privateData; + int i; + virCgroupPtr cgroup = NULL; + virDomainObjPtr vm = NULL; + int ret = -1; + + lxcDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (vm == NULL) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + lxcError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("Unable to get cgroup for %s"), vm->def->name); + goto cleanup; + } + + for (i = 0; i < nparams; i++) { + virMemoryParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) { + int rc; + if (param->type != VIR_DOMAIN_MEMORY_FIELD_ULLONG) { + lxcError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for memory hard_limit tunable, expected a 'ullong'")); + continue; + } + + rc = virCgroupSetMemoryHardLimit(cgroup, params[i].value.ul); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to set memory hard_limit tunable")); + } + } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) { + int rc; + if (param->type != VIR_DOMAIN_MEMORY_FIELD_ULLONG) { + lxcError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for memory soft_limit tunable, expected a 'ullong'")); + continue; + } + + rc = virCgroupSetMemorySoftLimit(cgroup, params[i].value.ul); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to set memory soft_limit tunable")); + } + } else if (STREQ(param->field, VIR_DOMAIN_SWAP_HARD_LIMIT)) { + int rc; + if (param->type != VIR_DOMAIN_MEMORY_FIELD_ULLONG) { + lxcError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for swap_hard_limit tunable, expected a 'ullong'")); + continue; + } + + rc = virCgroupSetSwapHardLimit(cgroup, params[i].value.ul); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to set swap_hard_limit tunable")); + } + } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) { + lxcError(VIR_ERR_INVALID_ARG, + _("Memory tunable `%s' not implemented"), param->field); + } else { + lxcError(VIR_ERR_INVALID_ARG, + _("Parameter `%s' not supported"), param->field); + } + } + ret = 0; + +cleanup: + if (cgroup) + virCgroupFree(&cgroup); + if (vm) + virDomainObjUnlock(vm); + lxcDriverUnlock(driver); + return ret; +} + static char *lxcDomainDumpXML(virDomainPtr dom, int flags) { @@ -2620,7 +2709,7 @@ static virDriver lxcDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ - NULL, /* domainSetMemoryParameters */ + lxcDomainSetMemoryParameters, /* domainSetMemoryParameters */ NULL, /* domainGetMemoryParameters */ };

On Fri, Oct 08, 2010 at 05:46:28PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Add support in the lxc driver for various memory controllable parameters
v4: + prototype change: add unsigned int flags
v2: + Use #define string constants for "hard_limit", etc + fix typo: min_guarantee
Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [...] +static int lxcDomainSetMemoryParameters(virDomainPtr dom, + virMemoryParameterPtr params, + int nparams, + unsigned int flags ATTRIBUTE_UNUSED) +{ + lxc_driver_t *driver = dom->conn->privateData; + int i; + virCgroupPtr cgroup = NULL; + virDomainObjPtr vm = NULL; + int ret = -1; + + lxcDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (vm == NULL) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + lxcError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); + goto cleanup; + }
Hum, the qemu driver was reporting if (vm == NULL) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("No such domain %s"), dom->uuid); goto cleanup; } the 2 should be harmonized I guess, but since the LXC reporting is better I left this as a TODO, seems that's a more general cleanup needed between drivers.
+ if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("Unable to get cgroup for %s"), vm->def->name); + goto cleanup; + }
And QEmu reported here: qemuReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; why diverging strings ? ... I used the same string instead !
+ for (i = 0; i < nparams; i++) { + virMemoryParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) { + int rc; + if (param->type != VIR_DOMAIN_MEMORY_FIELD_ULLONG) { + lxcError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for memory hard_limit tunable, expected a 'ullong'")); + continue; + } + + rc = virCgroupSetMemoryHardLimit(cgroup, params[i].value.ul); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to set memory hard_limit tunable")); + } + } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) { + int rc; + if (param->type != VIR_DOMAIN_MEMORY_FIELD_ULLONG) { + lxcError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for memory soft_limit tunable, expected a 'ullong'")); + continue; + } + + rc = virCgroupSetMemorySoftLimit(cgroup, params[i].value.ul); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to set memory soft_limit tunable")); + } + } else if (STREQ(param->field, VIR_DOMAIN_SWAP_HARD_LIMIT)) { + int rc; + if (param->type != VIR_DOMAIN_MEMORY_FIELD_ULLONG) { + lxcError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for swap_hard_limit tunable, expected a 'ullong'")); + continue; + } + + rc = virCgroupSetSwapHardLimit(cgroup, params[i].value.ul); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to set swap_hard_limit tunable")); + } + } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) { + lxcError(VIR_ERR_INVALID_ARG, + _("Memory tunable `%s' not implemented"), param->field); + } else { + lxcError(VIR_ERR_INVALID_ARG, + _("Parameter `%s' not supported"), param->field); + } + } + ret = 0;
Same problem of error reporting as in the QEmu driver, I moved ret = 0; before the loop and et ret = -1; on all errors !
+cleanup: + if (cgroup) + virCgroupFree(&cgroup); + if (vm) + virDomainObjUnlock(vm); + lxcDriverUnlock(driver); + return ret; +} +
After those modifications, ACK, applied to my tree, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, 12 Oct 2010 18:32:19 +0200, Daniel Veillard <veillard@redhat.com> wrote:
On Fri, Oct 08, 2010 at 05:46:28PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Add support in the lxc driver for various memory controllable parameters
v4: + prototype change: add unsigned int flags
v2: + Use #define string constants for "hard_limit", etc + fix typo: min_guarantee
Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [...] + if (vm == NULL) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + lxcError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); + goto cleanup; + }
Hum, the qemu driver was reporting
if (vm == NULL) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("No such domain %s"), dom->uuid); goto cleanup; }
the 2 should be harmonized I guess, but since the LXC reporting is better I left this as a TODO, seems that's a more general cleanup needed between drivers.
Let me look at this and I will provide a patch.
+ for (i = 0; i < nparams; i++) { + virMemoryParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) { + int rc; + if (param->type != VIR_DOMAIN_MEMORY_FIELD_ULLONG) { + lxcError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for memory hard_limit tunable, expected a 'ullong'")); + continue; + } + + rc = virCgroupSetMemoryHardLimit(cgroup, params[i].value.ul); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to set memory hard_limit tunable")); + } + } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) { + int rc; + if (param->type != VIR_DOMAIN_MEMORY_FIELD_ULLONG) { + lxcError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for memory soft_limit tunable, expected a 'ullong'")); + continue; + } + + rc = virCgroupSetMemorySoftLimit(cgroup, params[i].value.ul); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to set memory soft_limit tunable")); + } + } else if (STREQ(param->field, VIR_DOMAIN_SWAP_HARD_LIMIT)) { + int rc; + if (param->type != VIR_DOMAIN_MEMORY_FIELD_ULLONG) { + lxcError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for swap_hard_limit tunable, expected a 'ullong'")); + continue; + } + + rc = virCgroupSetSwapHardLimit(cgroup, params[i].value.ul); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to set swap_hard_limit tunable")); + } + } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) { + lxcError(VIR_ERR_INVALID_ARG, + _("Memory tunable `%s' not implemented"), param->field); + } else { + lxcError(VIR_ERR_INVALID_ARG, + _("Parameter `%s' not supported"), param->field); + } + } + ret = 0;
Same problem of error reporting as in the QEmu driver, I moved ret = 0; before the loop and et ret = -1; on all errors !
One clarification: Will it return error back immediately if an error occurs? Or will it try setting all of them one by one and if anyone of them succeed, success is returned.
+cleanup: + if (cgroup) + virCgroupFree(&cgroup); + if (vm) + virDomainObjUnlock(vm); + lxcDriverUnlock(driver); + return ret; +} +
After those modifications, ACK, applied to my tree,
Thanks Nikunj

On Wed, Oct 13, 2010 at 11:07:47AM +0530, Nikunj A. Dadhania wrote:
On Tue, 12 Oct 2010 18:32:19 +0200, Daniel Veillard <veillard@redhat.com> wrote:
On Fri, Oct 08, 2010 at 05:46:28PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Add support in the lxc driver for various memory controllable parameters
v4: + prototype change: add unsigned int flags
v2: + Use #define string constants for "hard_limit", etc + fix typo: min_guarantee
Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [...] + if (vm == NULL) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + lxcError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); + goto cleanup; + }
Hum, the qemu driver was reporting
if (vm == NULL) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("No such domain %s"), dom->uuid); goto cleanup; }
the 2 should be harmonized I guess, but since the LXC reporting is better I left this as a TODO, seems that's a more general cleanup needed between drivers.
Let me look at this and I will provide a patch.
Probably too complex and outside the scope of this patch, I would rather prefer if you focused on the documentation patch(es) still needed at this point,
Same problem of error reporting as in the QEmu driver, I moved ret = 0; before the loop and et ret = -1; on all errors !
One clarification: Will it return error back immediately if an error occurs?
No
Or will it try setting all of them one by one and if anyone of them succeed, success is returned.
Check the code from git ! It will try all of them. If any of them fails it will return an error. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> v4: * prototype change: add unsigned int flags Driver interface for getting memory parameters, eg. hard_limit, soft_limit and swap_hard_limit. Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/lxc/lxc_driver.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 113 insertions(+), 1 deletions(-) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 984a5fa..036dedf 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -766,6 +766,118 @@ cleanup: return ret; } +static int lxcDomainGetMemoryParameters(virDomainPtr dom, + virMemoryParameterPtr params, + int *nparams, + unsigned int flags ATTRIBUTE_UNUSED) +{ + lxc_driver_t *driver = dom->conn->privateData; + int i; + virCgroupPtr cgroup = NULL; + virDomainObjPtr vm = NULL; + unsigned long val; + int ret = -1; + int rc; + + lxcDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (vm == NULL) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + lxcError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if ((*nparams) == 0) { + /* Current number of memory parameters supported by cgroups is 3 + * FIXME: Magic number, need to see where should this go + */ + *nparams = 3; + ret = 0; + goto cleanup; + } + if ((*nparams) != 3) { + lxcError(VIR_ERR_INVALID_ARG, + "%s", _("Invalid parameter count")); + goto cleanup; + } + + if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("Unable to get cgroup for %s"), vm->def->name); + goto cleanup; + } + + for (i = 0; i < *nparams; i++) { + virMemoryParameterPtr param = ¶ms[i]; + val = 0; + param->value.ul = 0; + param->type = VIR_DOMAIN_MEMORY_FIELD_ULLONG; + + switch(i) { + case 0: /* fill memory hard limit here */ + rc = virCgroupGetMemoryHardLimit(cgroup, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get memory hard limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT) == NULL) { + lxcError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field memory hard limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + case 1: /* fill memory soft limit here */ + rc = virCgroupGetMemorySoftLimit(cgroup, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get memory soft limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT) == NULL) { + lxcError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field memory soft limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + case 2: /* fill swap hard limit here */ + rc = virCgroupGetSwapHardLimit(cgroup, &val); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("unable to get swap hard limit")); + continue; + } + if (virStrcpyStatic(param->field, VIR_DOMAIN_SWAP_HARD_LIMIT) == NULL) { + lxcError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field swap hard limit too long for destination")); + continue; + } + param->value.ul = val; + break; + + default: + break; + /* should not hit here */ + } + } + ret = 0; + +cleanup: + if (cgroup) + virCgroupFree(&cgroup); + if (vm) + virDomainObjUnlock(vm); + lxcDriverUnlock(driver); + return ret; +} + static char *lxcDomainDumpXML(virDomainPtr dom, int flags) { @@ -2710,7 +2822,7 @@ static virDriver lxcDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ lxcDomainSetMemoryParameters, /* domainSetMemoryParameters */ - NULL, /* domainGetMemoryParameters */ + lxcDomainGetMemoryParameters, /* domainGetMemoryParameters */ }; static virStateDriver lxcStateDriver = {

On Fri, Oct 08, 2010 at 05:46:40PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
v4: * prototype change: add unsigned int flags
Driver interface for getting memory parameters, eg. hard_limit, soft_limit and swap_hard_limit.
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/lxc/lxc_driver.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 113 insertions(+), 1 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 984a5fa..036dedf 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -766,6 +766,118 @@ cleanup: return ret; }
same as for the QEmu driver equivalent, I fixed the error handling and create a new constant at the top of the file. Once done, ACK, and pushed to my tree, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> The command helps to control the memory/swap parameters for the system, for eg. hard_limit (max memory the vm can use), soft_limit (limit during memory contention), swap_hard_limit(max swap the vm can use) v4: + virDomainSet/GetMemoryParameters prototype change + Move exporting of the symbol to patch 2 v3: + Added call to virDomainGetMemoryParameters and print them. + Added virDomainGetMemoryParameters and virDomainSetMemoryParamters to libvirt_public.syms v2: + Use #define string constants for "hard_limit", etc Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- tools/virsh.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 130 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 85014f2..a9fcc28 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2614,6 +2614,135 @@ cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd) } /* + * "memtune" command + */ +static const vshCmdInfo info_memtune[] = { + {"help", N_("Get/Set memory paramters")}, + {"desc", N_("Get/Set the current memory paramters for the guest domain.\n" \ + " To get the memory parameters use following command: \n\n" \ + " virsh # memtune <domain>")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_memtune[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {VIR_DOMAIN_MEMORY_HARD_LIMIT, VSH_OT_STRING, VSH_OFLAG_NONE, N_("Max memory in kilobytes")}, + {VIR_DOMAIN_MEMORY_SOFT_LIMIT, VSH_OT_STRING, VSH_OFLAG_NONE, N_("Memory during contention in kilobytes")}, + {VIR_DOMAIN_SWAP_HARD_LIMIT, VSH_OT_STRING, VSH_OFLAG_NONE, N_("Max swap in kilobytes")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdMemtune(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int hard_limit, soft_limit, swap_hard_limit; + int nparams = 0; + unsigned int i = 0; + virMemoryParameterPtr params = NULL, temp = NULL; + int ret = FALSE; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return FALSE; + + hard_limit = vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_HARD_LIMIT, &hard_limit); + if (hard_limit) + nparams++; + + soft_limit = vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_SOFT_LIMIT, &soft_limit); + if (soft_limit) + nparams++; + + swap_hard_limit = vshCommandOptInt(cmd, VIR_DOMAIN_SWAP_HARD_LIMIT, &swap_hard_limit); + if (swap_hard_limit) + nparams++; + + if(nparams == 0) { + /* get the number of memory parameters */ + if (virDomainGetMemoryParameters(dom, NULL, &nparams, 0) != 0 && (nparams != 0)) { + vshError(ctl, "%s", _("Unable to get number of memory parameters")); + goto cleanup; + } + + /* now go get all the memory parameters */ + params = vshMalloc(ctl, sizeof(virMemoryParameter)* nparams); + memset(params, 0, sizeof(virMemoryParameter)* nparams); + if (virDomainGetMemoryParameters(dom, params, &nparams, 0)) { + vshError(ctl, "%s", _("Unable to get memory parameters")); + goto cleanup; + } + + for (i = 0; i < nparams; i++){ + switch (params[i].type) { + case VIR_DOMAIN_MEMORY_FIELD_INT: + vshPrint(ctl, "%-15s: %d\n", params[i].field, params[i].value.i); + break; + case VIR_DOMAIN_MEMORY_FIELD_UINT: + vshPrint(ctl, "%-15s: %u\n", params[i].field, params[i].value.ui); + break; + case VIR_DOMAIN_MEMORY_FIELD_LLONG: + vshPrint(ctl, "%-15s: %lld\n", params[i].field, params[i].value.l); + break; + case VIR_DOMAIN_MEMORY_FIELD_ULLONG: + vshPrint(ctl, "%-15s: %llu\n", params[i].field, params[i].value.ul); + break; + case VIR_DOMAIN_MEMORY_FIELD_DOUBLE: + vshPrint(ctl, "%-15s: %f\n", params[i].field, params[i].value.d); + break; + case VIR_DOMAIN_MEMORY_FIELD_BOOLEAN: + vshPrint(ctl, "%-15s: %d\n", params[i].field, params[i].value.b); + break; + default: + vshPrint(ctl, "not implemented scheduler parameter type\n"); + } + } + + ret = TRUE; + } else { + /* set the memory parameters */ + params = vshMalloc(ctl, sizeof(virMemoryParameter)* nparams); + + memset(params, 0, sizeof(virMemoryParameter)* nparams); + for(i = 0; i < nparams; i++) + { + temp = ¶ms[i]; + temp->type = VIR_DOMAIN_MEMORY_FIELD_ULLONG; + + /* + * Some magic here, this is used to fill the params structure with + * the valid arguments passed, after filling the particular + * argument we purposely make them 0, so on the next pass it goes + * to the next valid argument and so on. + */ + if (soft_limit) { + temp->value.ul = soft_limit; + strncpy(temp->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT, sizeof(temp->field)); + soft_limit = 0; + } else if (hard_limit) { + temp->value.ul = hard_limit; + strncpy(temp->field, VIR_DOMAIN_MEMORY_HARD_LIMIT, sizeof(temp->field)); + hard_limit = 0; + } else if (swap_hard_limit) { + temp->value.ul = swap_hard_limit; + strncpy(temp->field, VIR_DOMAIN_SWAP_HARD_LIMIT, sizeof(temp->field)); + swap_hard_limit = 0; + } + } + if (virDomainSetMemoryParameters(dom, params, nparams, 0) != 0) + vshError(ctl, "%s", _("Unable to change Memory Parameters")); + else + ret = TRUE; + } + +cleanup: + virDomainFree(dom); + return ret; +} + +/* * "nodeinfo" command */ static const vshCmdInfo info_nodeinfo[] = { @@ -9431,6 +9560,7 @@ static const vshCmdDef commands[] = { {"shutdown", cmdShutdown, opts_shutdown, info_shutdown}, {"setmem", cmdSetmem, opts_setmem, info_setmem}, {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem}, + {"memtune", cmdMemtune, opts_memtune, info_memtune}, {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus}, {"suspend", cmdSuspend, opts_suspend, info_suspend}, {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole},

On Fri, Oct 08, 2010 at 05:46:51PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
The command helps to control the memory/swap parameters for the system, for eg. hard_limit (max memory the vm can use), soft_limit (limit during memory contention), swap_hard_limit(max swap the vm can use)
Okay, after some cleanups including a heavy reformatting I pushed this to my tree. But it still misses the part of the man page documentation, please provide a patch for tools/virsh.pod adding the description of the new command in the man page, thanks, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On 10/08/2010 06:16 AM, Nikunj A. Dadhania wrote:
+static int +cmdMemtune(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int hard_limit, soft_limit, swap_hard_limit;
This is inherently limited to 32 bits.
+ hard_limit = vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_HARD_LIMIT,&hard_limit);
You should instead be using vshCommandOptLongLong, and larger types,
+ } else { + /* set the memory parameters */ + params = vshMalloc(ctl, sizeof(virMemoryParameter)* nparams); + + memset(params, 0, sizeof(virMemoryParameter)* nparams); + for(i = 0; i< nparams; i++) + { + temp =¶ms[i]; + temp->type = VIR_DOMAIN_MEMORY_FIELD_ULLONG;
to match the fact that you claim to be passing a long long. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

* tools/virsh.c (cmdMemtune): Use long long for memory sizes. Simplify allocation, and plug memory leak. --- tools/virsh.c | 21 ++++++++++----------- 1 files changed, 10 insertions(+), 11 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index cd4485f..4f41c6f 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2905,7 +2905,7 @@ static int cmdMemtune(vshControl * ctl, const vshCmd * cmd) { virDomainPtr dom; - int hard_limit, soft_limit, swap_hard_limit, min_guarantee; + long long hard_limit, soft_limit, swap_hard_limit, min_guarantee; int nparams = 0; unsigned int i = 0; virMemoryParameterPtr params = NULL, temp = NULL; @@ -2918,24 +2918,24 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) return FALSE; hard_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_HARD_LIMIT, &hard_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_HARD_LIMIT, &hard_limit); if (hard_limit) nparams++; soft_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_SOFT_LIMIT, &soft_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_SOFT_LIMIT, &soft_limit); if (soft_limit) nparams++; swap_hard_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_SWAP_HARD_LIMIT, - &swap_hard_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_SWAP_HARD_LIMIT, + &swap_hard_limit); if (swap_hard_limit) nparams++; min_guarantee = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_MIN_GUARANTEE, - &min_guarantee); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_MIN_GUARANTEE, + &min_guarantee); if (min_guarantee) nparams++; @@ -2949,8 +2949,7 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) } /* now go get all the memory parameters */ - params = vshMalloc(ctl, sizeof(virMemoryParameter) * nparams); - memset(params, 0, sizeof(virMemoryParameter) * nparams); + params = vshCalloc(ctl, nparams, sizeof(*params)); if (virDomainGetMemoryParameters(dom, params, &nparams, 0)) { vshError(ctl, "%s", _("Unable to get memory parameters")); goto cleanup; @@ -2990,9 +2989,8 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) ret = TRUE; } else { /* set the memory parameters */ - params = vshMalloc(ctl, sizeof(virMemoryParameter) * nparams); + params = vshCalloc(ctl, nparams, sizeof(*params)); - memset(params, 0, sizeof(virMemoryParameter) * nparams); for (i = 0; i < nparams; i++) { temp = ¶ms[i]; temp->type = VIR_DOMAIN_MEMORY_PARAM_ULLONG; @@ -3032,6 +3030,7 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) } cleanup: + VIR_FREE(params); virDomainFree(dom); return ret; } -- 1.7.2.3

On 10/19/2010 10:46 AM, Eric Blake wrote:
* tools/virsh.c (cmdMemtune): Use long long for memory sizes. Simplify allocation, and plug memory leak. --- tools/virsh.c | 21 ++++++++++----------- 1 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c index cd4485f..4f41c6f 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2905,7 +2905,7 @@ static int cmdMemtune(vshControl * ctl, const vshCmd * cmd) { virDomainPtr dom; - int hard_limit, soft_limit, swap_hard_limit, min_guarantee; + long long hard_limit, soft_limit, swap_hard_limit, min_guarantee; int nparams = 0; unsigned int i = 0; virMemoryParameterPtr params = NULL, temp = NULL; @@ -2918,24 +2918,24 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) return FALSE;
hard_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_HARD_LIMIT,&hard_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_HARD_LIMIT,&hard_limit);
Self-NAK - this fails to compile. v2 coming up soon. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

* tools/virsh.c (cmdMemtune): Use long long for memory sizes. Simplify allocation, and plug memory leak. --- No need to cripple virsh with a 32-bit limit. Change from v1: fix compilation failure, rebase on top of other recent memtune fixes tools/virsh.c | 19 ++++++++----------- 1 files changed, 8 insertions(+), 11 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index ca9a61e..6a11a7a 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2905,7 +2905,7 @@ static int cmdMemtune(vshControl * ctl, const vshCmd * cmd) { virDomainPtr dom; - int hard_limit, soft_limit, swap_hard_limit, min_guarantee; + long long hard_limit, soft_limit, swap_hard_limit, min_guarantee; int nparams = 0; unsigned int i = 0; virMemoryParameterPtr params = NULL, temp = NULL; @@ -2918,24 +2918,22 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) return FALSE; hard_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_HARD_LIMIT, &hard_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_HARD_LIMIT, NULL); if (hard_limit) nparams++; soft_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_SOFT_LIMIT, &soft_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_SOFT_LIMIT, NULL); if (soft_limit) nparams++; swap_hard_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT, - &swap_hard_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT, NULL); if (swap_hard_limit) nparams++; min_guarantee = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_MIN_GUARANTEE, - &min_guarantee); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_MIN_GUARANTEE, NULL); if (min_guarantee) nparams++; @@ -2954,8 +2952,7 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) } /* now go get all the memory parameters */ - params = vshMalloc(ctl, sizeof(virMemoryParameter) * nparams); - memset(params, 0, sizeof(virMemoryParameter) * nparams); + params = vshCalloc(ctl, nparams, sizeof(*params)); if (virDomainGetMemoryParameters(dom, params, &nparams, 0) != 0) { vshError(ctl, "%s", _("Unable to get memory parameters")); goto cleanup; @@ -2995,9 +2992,8 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) ret = TRUE; } else { /* set the memory parameters */ - params = vshMalloc(ctl, sizeof(virMemoryParameter) * nparams); + params = vshCalloc(ctl, nparams, sizeof(*params)); - memset(params, 0, sizeof(virMemoryParameter) * nparams); for (i = 0; i < nparams; i++) { temp = ¶ms[i]; temp->type = VIR_DOMAIN_MEMORY_PARAM_ULLONG; @@ -3037,6 +3033,7 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) } cleanup: + VIR_FREE(params); virDomainFree(dom); return ret; } -- 1.7.2.3

On 10/20/2010 03:29 PM, Eric Blake wrote:
* tools/virsh.c (cmdMemtune): Use long long for memory sizes. Simplify allocation, and plug memory leak. ---
No need to cripple virsh with a 32-bit limit.
Change from v1: fix compilation failure, rebase on top of other recent memtune fixes
tools/virsh.c | 19 ++++++++----------- 1 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c index ca9a61e..6a11a7a 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2905,7 +2905,7 @@ static int cmdMemtune(vshControl * ctl, const vshCmd * cmd) { virDomainPtr dom; - int hard_limit, soft_limit, swap_hard_limit, min_guarantee; + long long hard_limit, soft_limit, swap_hard_limit, min_guarantee; int nparams = 0; unsigned int i = 0; virMemoryParameterPtr params = NULL, temp = NULL; @@ -2918,24 +2918,22 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) return FALSE;
hard_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_HARD_LIMIT,&hard_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_HARD_LIMIT, NULL); if (hard_limit) nparams++;
soft_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_SOFT_LIMIT,&soft_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_SOFT_LIMIT, NULL); if (soft_limit) nparams++;
swap_hard_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT, -&swap_hard_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT, NULL); if (swap_hard_limit) nparams++;
min_guarantee = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_MIN_GUARANTEE, -&min_guarantee); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_MIN_GUARANTEE, NULL); if (min_guarantee) nparams++;
@@ -2954,8 +2952,7 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) }
/* now go get all the memory parameters */ - params = vshMalloc(ctl, sizeof(virMemoryParameter) * nparams); - memset(params, 0, sizeof(virMemoryParameter) * nparams); + params = vshCalloc(ctl, nparams, sizeof(*params)); if (virDomainGetMemoryParameters(dom, params,&nparams, 0) != 0) { vshError(ctl, "%s", _("Unable to get memory parameters")); goto cleanup; @@ -2995,9 +2992,8 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) ret = TRUE; } else { /* set the memory parameters */ - params = vshMalloc(ctl, sizeof(virMemoryParameter) * nparams); + params = vshCalloc(ctl, nparams, sizeof(*params));
- memset(params, 0, sizeof(virMemoryParameter) * nparams); for (i = 0; i< nparams; i++) { temp =¶ms[i]; temp->type = VIR_DOMAIN_MEMORY_PARAM_ULLONG; @@ -3037,6 +3033,7 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) }
cleanup: + VIR_FREE(params); virDomainFree(dom); return ret; } ACK. Stefan

On Wed, 20 Oct 2010 13:29:45 -0600, Eric Blake <eblake@redhat.com> wrote:
* tools/virsh.c (cmdMemtune): Use long long for memory sizes. Simplify allocation, and plug memory leak. ---
No need to cripple virsh with a 32-bit limit.
Change from v1: fix compilation failure, rebase on top of other recent memtune fixes
tools/virsh.c | 19 ++++++++----------- 1 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c index ca9a61e..6a11a7a 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2905,7 +2905,7 @@ static int cmdMemtune(vshControl * ctl, const vshCmd * cmd) { virDomainPtr dom; - int hard_limit, soft_limit, swap_hard_limit, min_guarantee; + long long hard_limit, soft_limit, swap_hard_limit, min_guarantee; int nparams = 0; unsigned int i = 0; virMemoryParameterPtr params = NULL, temp = NULL; @@ -2918,24 +2918,22 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) return FALSE;
hard_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_HARD_LIMIT, &hard_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_HARD_LIMIT, NULL); if (hard_limit) nparams++;
soft_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_SOFT_LIMIT, &soft_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_SOFT_LIMIT, NULL); if (soft_limit) nparams++;
swap_hard_limit = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT, - &swap_hard_limit); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT, NULL); if (swap_hard_limit) nparams++;
min_guarantee = - vshCommandOptInt(cmd, VIR_DOMAIN_MEMORY_MIN_GUARANTEE, - &min_guarantee); + vshCommandOptLongLong(cmd, VIR_DOMAIN_MEMORY_MIN_GUARANTEE, NULL); if (min_guarantee) nparams++;
@@ -2954,8 +2952,7 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) }
/* now go get all the memory parameters */ - params = vshMalloc(ctl, sizeof(virMemoryParameter) * nparams); - memset(params, 0, sizeof(virMemoryParameter) * nparams); + params = vshCalloc(ctl, nparams, sizeof(*params)); if (virDomainGetMemoryParameters(dom, params, &nparams, 0) != 0) { vshError(ctl, "%s", _("Unable to get memory parameters")); goto cleanup; @@ -2995,9 +2992,8 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) ret = TRUE; } else { /* set the memory parameters */ - params = vshMalloc(ctl, sizeof(virMemoryParameter) * nparams); + params = vshCalloc(ctl, nparams, sizeof(*params));
- memset(params, 0, sizeof(virMemoryParameter) * nparams); for (i = 0; i < nparams; i++) { temp = ¶ms[i]; temp->type = VIR_DOMAIN_MEMORY_PARAM_ULLONG; @@ -3037,6 +3033,7 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd) }
cleanup: + VIR_FREE(params); virDomainFree(dom); return ret; }
ACK Nikunj

On 10/25/2010 11:06 PM, Nikunj A. Dadhania wrote:
On Wed, 20 Oct 2010 13:29:45 -0600, Eric Blake<eblake@redhat.com> wrote:
* tools/virsh.c (cmdMemtune): Use long long for memory sizes. Simplify allocation, and plug memory leak.
ACK
Thanks; pushed. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> v4: * prototype change: add unsigned int flags, regenerate files v3: * Squased all the remote driver changes to one single big patch and auto-generated is around 40% * Implements domainSetMemoryParameters and domainGetMemoryParameters for remote driver daemon/remote.c src/remote/remote_driver.c * Auto generate the files using rpcgen and helper scripts in daemon/ directory src/remote/remote_protocol.x daemon/remote_dispatch_args.h daemon/remote_dispatch_prototypes.h daemon/remote_dispatch_ret.h daemon/remote_dispatch_table.h src/remote/remote_protocol.c src/remote/remote_protocol.h Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- daemon/remote.c | 162 +++++++++++++++++++++++++++++++++++ daemon/remote_dispatch_args.h | 2 daemon/remote_dispatch_prototypes.h | 16 +++ daemon/remote_dispatch_ret.h | 1 daemon/remote_dispatch_table.h | 10 ++ src/remote/remote_driver.c | 153 +++++++++++++++++++++++++++++++++ src/remote/remote_protocol.c | 88 +++++++++++++++++++ src/remote/remote_protocol.h | 58 +++++++++++++ src/remote/remote_protocol.x | 44 +++++++++- 9 files changed, 531 insertions(+), 3 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 6b67678..d5a8a9c 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -2332,6 +2332,168 @@ remoteDispatchDomainSetMemory (struct qemud_server *server ATTRIBUTE_UNUSED, } static int +remoteDispatchDomainSetMemoryParameters (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_set_memory_parameters_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virDomainPtr dom; + int i, r, nparams; + virMemoryParameterPtr params; + unsigned int flags; + + nparams = args->params.params_len; + nparams = args->flags; + + if (nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) { + remoteDispatchFormatError (rerr, "%s", _("nparams too large")); + return -1; + } + if (VIR_ALLOC_N(params, nparams) < 0) { + remoteDispatchOOMError(rerr); + return -1; + } + + /* Deserialise parameters. */ + for (i = 0; i < nparams; ++i) { + if (virStrcpyStatic(params[i].field, args->params.params_val[i].field) == NULL) { + remoteDispatchFormatError(rerr, _("Field %s too big for destination"), + args->params.params_val[i].field); + return -1; + } + params[i].type = args->params.params_val[i].value.type; + switch (params[i].type) { + case VIR_DOMAIN_MEMORY_FIELD_INT: + params[i].value.i = args->params.params_val[i].value.remote_memory_param_value_u.i; break; + case VIR_DOMAIN_MEMORY_FIELD_UINT: + params[i].value.ui = args->params.params_val[i].value.remote_memory_param_value_u.ui; break; + case VIR_DOMAIN_MEMORY_FIELD_LLONG: + params[i].value.l = args->params.params_val[i].value.remote_memory_param_value_u.l; break; + case VIR_DOMAIN_MEMORY_FIELD_ULLONG: + params[i].value.ul = args->params.params_val[i].value.remote_memory_param_value_u.ul; break; + case VIR_DOMAIN_MEMORY_FIELD_DOUBLE: + params[i].value.d = args->params.params_val[i].value.remote_memory_param_value_u.d; break; + case VIR_DOMAIN_MEMORY_FIELD_BOOLEAN: + params[i].value.b = args->params.params_val[i].value.remote_memory_param_value_u.b; break; + } + } + + dom = get_nonnull_domain (conn, args->dom); + if (dom == NULL) { + VIR_FREE(params); + remoteDispatchConnError(rerr, conn); + return -1; + } + + r = virDomainSetMemoryParameters (dom, params, nparams, flags); + virDomainFree(dom); + VIR_FREE(params); + if (r == -1) { + remoteDispatchConnError(rerr, conn); + return -1; + } + + return 0; +} + +static int remoteDispatchDomainGetMemoryParameters (struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *rerr, + remote_domain_get_memory_parameters_args *args, + remote_domain_get_memory_parameters_ret *ret) +{ + virDomainPtr dom; + virMemoryParameterPtr params; + int i, r, nparams; + unsigned int flags; + + nparams = args->nparams; + flags = args->flags; + + if (nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) { + remoteDispatchFormatError (rerr, "%s", _("nparams too large")); + return -1; + } + if (VIR_ALLOC_N(params, nparams) < 0) { + remoteDispatchOOMError(rerr); + return -1; + } + + dom = get_nonnull_domain (conn, args->dom); + if (dom == NULL) { + VIR_FREE(params); + remoteDispatchConnError(rerr, conn); + return -1; + } + + r = virDomainGetMemoryParameters (dom, params, &nparams, flags); + if (r == -1) { + virDomainFree(dom); + VIR_FREE(params); + remoteDispatchConnError(rerr, conn); + return -1; + } + /* In this case, we need to send back the number of parameters + * supported + */ + if (args->nparams == 0) { + ret->nparams = nparams; + goto success; + } + + /* Serialise the memory parameters. */ + ret->params.params_len = nparams; + if (VIR_ALLOC_N(ret->params.params_val, nparams) < 0) + goto oom; + + for (i = 0; i < nparams; ++i) { + // remoteDispatchClientRequest will free this: + ret->params.params_val[i].field = strdup (params[i].field); + if (ret->params.params_val[i].field == NULL) + goto oom; + + ret->params.params_val[i].value.type = params[i].type; + switch (params[i].type) { + case VIR_DOMAIN_MEMORY_FIELD_INT: + ret->params.params_val[i].value.remote_memory_param_value_u.i = params[i].value.i; break; + case VIR_DOMAIN_MEMORY_FIELD_UINT: + ret->params.params_val[i].value.remote_memory_param_value_u.ui = params[i].value.ui; break; + case VIR_DOMAIN_MEMORY_FIELD_LLONG: + ret->params.params_val[i].value.remote_memory_param_value_u.l = params[i].value.l; break; + case VIR_DOMAIN_MEMORY_FIELD_ULLONG: + ret->params.params_val[i].value.remote_memory_param_value_u.ul = params[i].value.ul; break; + case VIR_DOMAIN_MEMORY_FIELD_DOUBLE: + ret->params.params_val[i].value.remote_memory_param_value_u.d = params[i].value.d; break; + case VIR_DOMAIN_MEMORY_FIELD_BOOLEAN: + ret->params.params_val[i].value.remote_memory_param_value_u.b = params[i].value.b; break; + default: + remoteDispatchFormatError (rerr, "%s", _("unknown type")); + goto cleanup; + } + } + +success: + virDomainFree(dom); + VIR_FREE(params); + + return 0; + +oom: + remoteDispatchOOMError(rerr); +cleanup: + virDomainFree(dom); + for (i = 0 ; i < nparams ; i++) + VIR_FREE(ret->params.params_val[i].field); + VIR_FREE(params); + return -1; +} + +static int remoteDispatchDomainSetVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, struct qemud_client *client ATTRIBUTE_UNUSED, virConnectPtr conn, diff --git a/daemon/remote_dispatch_args.h b/daemon/remote_dispatch_args.h index ee95043..d8528b6 100644 --- a/daemon/remote_dispatch_args.h +++ b/daemon/remote_dispatch_args.h @@ -165,3 +165,5 @@ remote_domain_snapshot_delete_args val_remote_domain_snapshot_delete_args; remote_domain_get_block_info_args val_remote_domain_get_block_info_args; remote_domain_create_with_flags_args val_remote_domain_create_with_flags_args; + remote_domain_set_memory_parameters_args val_remote_domain_set_memory_parameters_args; + remote_domain_get_memory_parameters_args val_remote_domain_get_memory_parameters_args; diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h index cf1a0f9..b674bb4 100644 --- a/daemon/remote_dispatch_prototypes.h +++ b/daemon/remote_dispatch_prototypes.h @@ -258,6 +258,14 @@ static int remoteDispatchDomainGetMaxVcpus( remote_error *err, remote_domain_get_max_vcpus_args *args, remote_domain_get_max_vcpus_ret *ret); +static int remoteDispatchDomainGetMemoryParameters( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + remote_domain_get_memory_parameters_args *args, + remote_domain_get_memory_parameters_ret *ret); static int remoteDispatchDomainGetOsType( struct qemud_server *server, struct qemud_client *client, @@ -522,6 +530,14 @@ static int remoteDispatchDomainSetMemory( remote_error *err, remote_domain_set_memory_args *args, void *ret); +static int remoteDispatchDomainSetMemoryParameters( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + remote_domain_set_memory_parameters_args *args, + void *ret); static int remoteDispatchDomainSetSchedulerParameters( struct qemud_server *server, struct qemud_client *client, diff --git a/daemon/remote_dispatch_ret.h b/daemon/remote_dispatch_ret.h index 75ac0b2..17c9bca 100644 --- a/daemon/remote_dispatch_ret.h +++ b/daemon/remote_dispatch_ret.h @@ -135,3 +135,4 @@ remote_domain_snapshot_current_ret val_remote_domain_snapshot_current_ret; remote_domain_get_block_info_ret val_remote_domain_get_block_info_ret; remote_domain_create_with_flags_ret val_remote_domain_create_with_flags_ret; + remote_domain_get_memory_parameters_ret val_remote_domain_get_memory_parameters_ret; diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index ef00edd..47d95eb 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -987,3 +987,13 @@ .args_filter = (xdrproc_t) xdr_remote_domain_create_with_flags_args, .ret_filter = (xdrproc_t) xdr_remote_domain_create_with_flags_ret, }, +{ /* DomainSetMemoryParameters => 197 */ + .fn = (dispatch_fn) remoteDispatchDomainSetMemoryParameters, + .args_filter = (xdrproc_t) xdr_remote_domain_set_memory_parameters_args, + .ret_filter = (xdrproc_t) xdr_void, +}, +{ /* DomainGetMemoryParameters => 198 */ + .fn = (dispatch_fn) remoteDispatchDomainGetMemoryParameters, + .args_filter = (xdrproc_t) xdr_remote_domain_get_memory_parameters_args, + .ret_filter = (xdrproc_t) xdr_remote_domain_get_memory_parameters_ret, +}, diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 7337cad..abb95fa 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2284,6 +2284,155 @@ done: } static int +remoteDomainSetMemoryParameters (virDomainPtr domain, + virMemoryParameterPtr params, + int nparams, + unsigned int flags) +{ + int rv = -1; + remote_domain_set_memory_parameters_args args; + int i, do_error; + struct private_data *priv = domain->conn->privateData; + + remoteDriverLock(priv); + + make_nonnull_domain (&args.dom, domain); + + /* Serialise the memory parameters. */ + args.params.params_len = nparams; + args.flags = flags; + if (VIR_ALLOC_N(args.params.params_val, nparams) < 0) { + virReportOOMError(); + goto done; + } + + do_error = 0; + for (i = 0; i < nparams; ++i) { + // call() will free this: + args.params.params_val[i].field = strdup (params[i].field); + if (args.params.params_val[i].field == NULL) { + virReportOOMError(); + do_error = 1; + } + args.params.params_val[i].value.type = params[i].type; + switch (params[i].type) { + case VIR_DOMAIN_MEMORY_FIELD_INT: + args.params.params_val[i].value.remote_memory_param_value_u.i = params[i].value.i; break; + case VIR_DOMAIN_MEMORY_FIELD_UINT: + args.params.params_val[i].value.remote_memory_param_value_u.ui = params[i].value.ui; break; + case VIR_DOMAIN_MEMORY_FIELD_LLONG: + args.params.params_val[i].value.remote_memory_param_value_u.l = params[i].value.l; break; + case VIR_DOMAIN_MEMORY_FIELD_ULLONG: + args.params.params_val[i].value.remote_memory_param_value_u.ul = params[i].value.ul; break; + case VIR_DOMAIN_MEMORY_FIELD_DOUBLE: + args.params.params_val[i].value.remote_memory_param_value_u.d = params[i].value.d; break; + case VIR_DOMAIN_MEMORY_FIELD_BOOLEAN: + args.params.params_val[i].value.remote_memory_param_value_u.b = params[i].value.b; break; + default: + remoteError(VIR_ERR_RPC, "%s", _("unknown parameter type")); + do_error = 1; + } + } + + if (do_error) { + xdr_free ((xdrproc_t) xdr_remote_domain_set_memory_parameters_args, (char *) &args); + goto done; + } + + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SET_MEMORY_PARAMETERS, + (xdrproc_t) xdr_remote_domain_set_memory_parameters_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + goto done; + + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; +} + +static int +remoteDomainGetMemoryParameters (virDomainPtr domain, + virMemoryParameterPtr params, int *nparams, + unsigned int flags) +{ + int rv = -1; + remote_domain_get_memory_parameters_args args; + remote_domain_get_memory_parameters_ret ret; + int i = -1; + struct private_data *priv = domain->conn->privateData; + + remoteDriverLock(priv); + + make_nonnull_domain (&args.dom, domain); + args.nparams = *nparams; + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_MEMORY_PARAMETERS, + (xdrproc_t) xdr_remote_domain_get_memory_parameters_args, (char *) &args, + (xdrproc_t) xdr_remote_domain_get_memory_parameters_ret, (char *) &ret) == -1) + goto done; + + /* Check the length of the returned list carefully. */ + if (ret.params.params_len > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX || + ret.params.params_len > *nparams) { + remoteError(VIR_ERR_RPC, "%s", + _("remoteDomainGetMemoryParameters: " + "returned number of parameters exceeds limit")); + goto cleanup; + } + /* Handle the case when the caller does not know the number of parameters + * and is asking for the number of parameters supported + */ + if (*nparams == 0) { + *nparams = ret.nparams; + rv = 0; + goto cleanup; + } + + *nparams = ret.params.params_len; + + /* Deserialise the result. */ + for (i = 0; i < *nparams; ++i) { + if (virStrcpyStatic(params[i].field, ret.params.params_val[i].field) == NULL) { + remoteError(VIR_ERR_INTERNAL_ERROR, + _("Parameter %s too big for destination"), + ret.params.params_val[i].field); + goto cleanup; + } + params[i].type = ret.params.params_val[i].value.type; + switch (params[i].type) { + case VIR_DOMAIN_MEMORY_FIELD_INT: + params[i].value.i = ret.params.params_val[i].value.remote_memory_param_value_u.i; break; + case VIR_DOMAIN_MEMORY_FIELD_UINT: + params[i].value.ui = ret.params.params_val[i].value.remote_memory_param_value_u.ui; break; + case VIR_DOMAIN_MEMORY_FIELD_LLONG: + params[i].value.l = ret.params.params_val[i].value.remote_memory_param_value_u.l; break; + case VIR_DOMAIN_MEMORY_FIELD_ULLONG: + params[i].value.ul = ret.params.params_val[i].value.remote_memory_param_value_u.ul; break; + case VIR_DOMAIN_MEMORY_FIELD_DOUBLE: + params[i].value.d = ret.params.params_val[i].value.remote_memory_param_value_u.d; break; + case VIR_DOMAIN_MEMORY_FIELD_BOOLEAN: + params[i].value.b = ret.params.params_val[i].value.remote_memory_param_value_u.b; break; + default: + remoteError(VIR_ERR_RPC, "%s", + _("remoteDomainGetMemoryParameters: " + "unknown parameter type")); + goto cleanup; + } + } + + rv = 0; + +cleanup: + xdr_free ((xdrproc_t) xdr_remote_domain_get_memory_parameters_ret, (char *) &ret); +done: + remoteDriverUnlock(priv); + return rv; +} + +static int remoteDomainGetInfo (virDomainPtr domain, virDomainInfoPtr info) { int rv = -1; @@ -10366,8 +10515,8 @@ static virDriver remote_driver = { remoteDomainRevertToSnapshot, /* domainRevertToSnapshot */ remoteDomainSnapshotDelete, /* domainSnapshotDelete */ remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ - NULL, /* domainSetMemoryParameters */ - NULL, /* domainGetMemoryParameters */ + remoteDomainSetMemoryParameters, /* domainSetMemoryParameters */ + remoteDomainGetMemoryParameters, /* domainGetMemoryParameters */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 2483004..3f2abec 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -308,6 +308,53 @@ xdr_remote_sched_param (XDR *xdrs, remote_sched_param *objp) } bool_t +xdr_remote_memory_param_value (XDR *xdrs, remote_memory_param_value *objp) +{ + + if (!xdr_int (xdrs, &objp->type)) + return FALSE; + switch (objp->type) { + case VIR_DOMAIN_MEMORY_FIELD_INT: + return FALSE; + break; + case VIR_DOMAIN_MEMORY_FIELD_UINT: + if (!xdr_u_int (xdrs, &objp->remote_memory_param_value_u.ui)) + return FALSE; + break; + case VIR_DOMAIN_MEMORY_FIELD_LLONG: + if (!xdr_int64_t (xdrs, &objp->remote_memory_param_value_u.l)) + return FALSE; + break; + case VIR_DOMAIN_MEMORY_FIELD_ULLONG: + if (!xdr_uint64_t (xdrs, &objp->remote_memory_param_value_u.ul)) + return FALSE; + break; + case VIR_DOMAIN_MEMORY_FIELD_DOUBLE: + if (!xdr_double (xdrs, &objp->remote_memory_param_value_u.d)) + return FALSE; + break; + case VIR_DOMAIN_MEMORY_FIELD_BOOLEAN: + if (!xdr_int (xdrs, &objp->remote_memory_param_value_u.b)) + return FALSE; + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t +xdr_remote_memory_param (XDR *xdrs, remote_memory_param *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->field)) + return FALSE; + if (!xdr_remote_memory_param_value (xdrs, &objp->value)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_open_args (XDR *xdrs, remote_open_args *objp) { @@ -581,6 +628,47 @@ xdr_remote_domain_set_scheduler_parameters_args (XDR *xdrs, remote_domain_set_sc } bool_t +xdr_remote_domain_set_memory_parameters_args (XDR *xdrs, remote_domain_set_memory_parameters_args *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->params.params_val; + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->params.params_len, REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX, + sizeof (remote_memory_param), (xdrproc_t) xdr_remote_memory_param)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_domain_get_memory_parameters_args (XDR *xdrs, remote_domain_get_memory_parameters_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_int (xdrs, &objp->nparams)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_domain_get_memory_parameters_ret (XDR *xdrs, remote_domain_get_memory_parameters_ret *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->params.params_val; + + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->params.params_len, REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX, + sizeof (remote_memory_param), (xdrproc_t) xdr_remote_memory_param)) + return FALSE; + if (!xdr_int (xdrs, &objp->nparams)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_domain_block_stats_args (XDR *xdrs, remote_domain_block_stats_args *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index afe9287..756da11 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -53,6 +53,7 @@ typedef remote_nonnull_string *remote_string; #define REMOTE_NODE_DEVICE_CAPS_LIST_MAX 16384 #define REMOTE_NWFILTER_NAME_LIST_MAX 1024 #define REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX 16 +#define REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX 16 #define REMOTE_NODE_MAX_CELLS 1024 #define REMOTE_AUTH_SASL_DATA_MAX 65536 #define REMOTE_AUTH_TYPE_LIST_MAX 20 @@ -186,6 +187,25 @@ struct remote_sched_param { }; typedef struct remote_sched_param remote_sched_param; +struct remote_memory_param_value { + int type; + union { + int i; + u_int ui; + int64_t l; + uint64_t ul; + double d; + int b; + } remote_memory_param_value_u; +}; +typedef struct remote_memory_param_value remote_memory_param_value; + +struct remote_memory_param { + remote_nonnull_string field; + remote_memory_param_value value; +}; +typedef struct remote_memory_param remote_memory_param; + struct remote_open_args { remote_string name; int flags; @@ -307,6 +327,32 @@ struct remote_domain_set_scheduler_parameters_args { }; typedef struct remote_domain_set_scheduler_parameters_args remote_domain_set_scheduler_parameters_args; +struct remote_domain_set_memory_parameters_args { + remote_nonnull_domain dom; + struct { + u_int params_len; + remote_memory_param *params_val; + } params; + u_int flags; +}; +typedef struct remote_domain_set_memory_parameters_args remote_domain_set_memory_parameters_args; + +struct remote_domain_get_memory_parameters_args { + remote_nonnull_domain dom; + int nparams; + u_int flags; +}; +typedef struct remote_domain_get_memory_parameters_args remote_domain_get_memory_parameters_args; + +struct remote_domain_get_memory_parameters_ret { + struct { + u_int params_len; + remote_memory_param *params_val; + } params; + int nparams; +}; +typedef struct remote_domain_get_memory_parameters_ret remote_domain_get_memory_parameters_ret; + struct remote_domain_block_stats_args { remote_nonnull_domain dom; remote_nonnull_string path; @@ -2233,6 +2279,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_BLOCK_INFO = 194, REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON = 195, REMOTE_PROC_DOMAIN_CREATE_WITH_FLAGS = 196, + REMOTE_PROC_DOMAIN_SET_MEMORY_PARAMETERS = 197, + REMOTE_PROC_DOMAIN_GET_MEMORY_PARAMETERS = 198, }; typedef enum remote_procedure remote_procedure; @@ -2288,6 +2336,8 @@ extern bool_t xdr_remote_auth_type (XDR *, remote_auth_type*); extern bool_t xdr_remote_vcpu_info (XDR *, remote_vcpu_info*); extern bool_t xdr_remote_sched_param_value (XDR *, remote_sched_param_value*); extern bool_t xdr_remote_sched_param (XDR *, remote_sched_param*); +extern bool_t xdr_remote_memory_param_value (XDR *, remote_memory_param_value*); +extern bool_t xdr_remote_memory_param (XDR *, remote_memory_param*); extern bool_t xdr_remote_open_args (XDR *, remote_open_args*); extern bool_t xdr_remote_supports_feature_args (XDR *, remote_supports_feature_args*); extern bool_t xdr_remote_supports_feature_ret (XDR *, remote_supports_feature_ret*); @@ -2308,6 +2358,9 @@ extern bool_t xdr_remote_domain_get_scheduler_type_ret (XDR *, remote_domain_ge extern bool_t xdr_remote_domain_get_scheduler_parameters_args (XDR *, remote_domain_get_scheduler_parameters_args*); extern bool_t xdr_remote_domain_get_scheduler_parameters_ret (XDR *, remote_domain_get_scheduler_parameters_ret*); extern bool_t xdr_remote_domain_set_scheduler_parameters_args (XDR *, remote_domain_set_scheduler_parameters_args*); +extern bool_t xdr_remote_domain_set_memory_parameters_args (XDR *, remote_domain_set_memory_parameters_args*); +extern bool_t xdr_remote_domain_get_memory_parameters_args (XDR *, remote_domain_get_memory_parameters_args*); +extern bool_t xdr_remote_domain_get_memory_parameters_ret (XDR *, remote_domain_get_memory_parameters_ret*); extern bool_t xdr_remote_domain_block_stats_args (XDR *, remote_domain_block_stats_args*); extern bool_t xdr_remote_domain_block_stats_ret (XDR *, remote_domain_block_stats_ret*); extern bool_t xdr_remote_domain_interface_stats_args (XDR *, remote_domain_interface_stats_args*); @@ -2623,6 +2676,8 @@ extern bool_t xdr_remote_auth_type (); extern bool_t xdr_remote_vcpu_info (); extern bool_t xdr_remote_sched_param_value (); extern bool_t xdr_remote_sched_param (); +extern bool_t xdr_remote_memory_param_value (); +extern bool_t xdr_remote_memory_param (); extern bool_t xdr_remote_open_args (); extern bool_t xdr_remote_supports_feature_args (); extern bool_t xdr_remote_supports_feature_ret (); @@ -2643,6 +2698,9 @@ extern bool_t xdr_remote_domain_get_scheduler_type_ret (); extern bool_t xdr_remote_domain_get_scheduler_parameters_args (); extern bool_t xdr_remote_domain_get_scheduler_parameters_ret (); extern bool_t xdr_remote_domain_set_scheduler_parameters_args (); +extern bool_t xdr_remote_domain_set_memory_parameters_args (); +extern bool_t xdr_remote_domain_get_memory_parameters_args (); +extern bool_t xdr_remote_domain_get_memory_parameters_ret (); extern bool_t xdr_remote_domain_block_stats_args (); extern bool_t xdr_remote_domain_block_stats_ret (); extern bool_t xdr_remote_domain_interface_stats_args (); diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 8af469c..f5dcb5c 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -128,6 +128,9 @@ const REMOTE_NWFILTER_NAME_LIST_MAX = 1024; /* Upper limit on list of scheduler parameters. */ const REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX = 16; +/* Upper limit on list of memory parameters. */ +const REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX = 16; + /* Upper limit on number of NUMA cells */ const REMOTE_NODE_MAX_CELLS = 1024; @@ -313,6 +316,26 @@ struct remote_sched_param { remote_sched_param_value value; }; +union remote_memory_param_value switch (int type) { + case VIR_DOMAIN_MEMORY_FIELD_INT: + int i; + case VIR_DOMAIN_MEMORY_FIELD_UINT: + unsigned int ui; + case VIR_DOMAIN_MEMORY_FIELD_LLONG: + hyper l; + case VIR_DOMAIN_MEMORY_FIELD_ULLONG: + unsigned hyper ul; + case VIR_DOMAIN_MEMORY_FIELD_DOUBLE: + double d; + case VIR_DOMAIN_MEMORY_FIELD_BOOLEAN: + int b; +}; + +struct remote_memory_param { + remote_nonnull_string field; + remote_memory_param_value value; +}; + /*----- Calls. -----*/ /* For each call we may have a 'remote_CALL_args' and 'remote_CALL_ret' @@ -422,6 +445,23 @@ struct remote_domain_set_scheduler_parameters_args { remote_sched_param params<REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX>; }; +struct remote_domain_set_memory_parameters_args { + remote_nonnull_domain dom; + remote_memory_param params<REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX>; + unsigned int flags; +}; + +struct remote_domain_get_memory_parameters_args { + remote_nonnull_domain dom; + int nparams; + unsigned int flags; +}; + +struct remote_domain_get_memory_parameters_ret { + remote_memory_param params<REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX>; + int nparams; +}; + struct remote_domain_block_stats_args { remote_nonnull_domain dom; remote_nonnull_string path; @@ -2020,7 +2060,9 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SNAPSHOT_DELETE = 193, REMOTE_PROC_DOMAIN_GET_BLOCK_INFO = 194, REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON = 195, - REMOTE_PROC_DOMAIN_CREATE_WITH_FLAGS = 196 + REMOTE_PROC_DOMAIN_CREATE_WITH_FLAGS = 196, + REMOTE_PROC_DOMAIN_SET_MEMORY_PARAMETERS = 197, + REMOTE_PROC_DOMAIN_GET_MEMORY_PARAMETERS = 198 /* * Notice how the entries are grouped in sets of 10 ?

On Fri, Oct 08, 2010 at 05:47:03PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
v4: * prototype change: add unsigned int flags, regenerate files
v3: * Squased all the remote driver changes to one single big patch and auto-generated is around 40% * Implements domainSetMemoryParameters and domainGetMemoryParameters for remote driver daemon/remote.c src/remote/remote_driver.c
* Auto generate the files using rpcgen and helper scripts in daemon/ directory src/remote/remote_protocol.x daemon/remote_dispatch_args.h daemon/remote_dispatch_prototypes.h daemon/remote_dispatch_ret.h daemon/remote_dispatch_table.h src/remote/remote_protocol.c src/remote/remote_protocol.h
Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [...] static int +remoteDispatchDomainSetMemoryParameters (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_set_memory_parameters_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virDomainPtr dom; + int i, r, nparams; + virMemoryParameterPtr params; + unsigned int flags; + + nparams = args->params.params_len; + nparams = args->flags;
obvious bug: flags = args->flags; That reminds me that I didn't see flags being checked against 0 on the QEmu and LXC drivers, we should check them !
+ if (nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) { + remoteDispatchFormatError (rerr, "%s", _("nparams too large")); + return -1;
I did a lot of reformating and code cleanups in the non-generated files, to try to keep the source readable on a 80 columns editor.
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 8af469c..f5dcb5c 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -128,6 +128,9 @@ const REMOTE_NWFILTER_NAME_LIST_MAX = 1024; /* Upper limit on list of scheduler parameters. */ const REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX = 16;
+/* Upper limit on list of memory parameters. */ +const REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX = 16; +
Hopefully we won't exhaust that crucial limit
/* Upper limit on number of NUMA cells */ const REMOTE_NODE_MAX_CELLS = 1024;
@@ -313,6 +316,26 @@ struct remote_sched_param { remote_sched_param_value value; };
+union remote_memory_param_value switch (int type) { + case VIR_DOMAIN_MEMORY_FIELD_INT: + int i; + case VIR_DOMAIN_MEMORY_FIELD_UINT: + unsigned int ui; + case VIR_DOMAIN_MEMORY_FIELD_LLONG: + hyper l; + case VIR_DOMAIN_MEMORY_FIELD_ULLONG: + unsigned hyper ul; + case VIR_DOMAIN_MEMORY_FIELD_DOUBLE: + double d; + case VIR_DOMAIN_MEMORY_FIELD_BOOLEAN: + int b; +}; + +struct remote_memory_param { + remote_nonnull_string field; + remote_memory_param_value value; +}; + /*----- Calls. -----*/
/* For each call we may have a 'remote_CALL_args' and 'remote_CALL_ret' @@ -422,6 +445,23 @@ struct remote_domain_set_scheduler_parameters_args { remote_sched_param params<REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX>; };
+struct remote_domain_set_memory_parameters_args { + remote_nonnull_domain dom; + remote_memory_param params<REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX>; + unsigned int flags; +}; + +struct remote_domain_get_memory_parameters_args { + remote_nonnull_domain dom; + int nparams; + unsigned int flags; +}; + +struct remote_domain_get_memory_parameters_ret { + remote_memory_param params<REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX>; + int nparams; +}; + struct remote_domain_block_stats_args { remote_nonnull_domain dom; remote_nonnull_string path; @@ -2020,7 +2060,9 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SNAPSHOT_DELETE = 193, REMOTE_PROC_DOMAIN_GET_BLOCK_INFO = 194, REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON = 195, - REMOTE_PROC_DOMAIN_CREATE_WITH_FLAGS = 196 + REMOTE_PROC_DOMAIN_CREATE_WITH_FLAGS = 196, + REMOTE_PROC_DOMAIN_SET_MEMORY_PARAMETERS = 197, + REMOTE_PROC_DOMAIN_GET_MEMORY_PARAMETERS = 198
/* * Notice how the entries are grouped in sets of 10 ?
With that done, I think I can ACK the whole serie, and pushed it, but there is still a number of small TODOs for which I would appreciate patches, thanks a lot ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, Oct 12, 2010 at 07:27:05PM +0200, Daniel Veillard wrote:
On Fri, Oct 08, 2010 at 05:47:03PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
v4: * prototype change: add unsigned int flags, regenerate files
v3: * Squased all the remote driver changes to one single big patch and auto-generated is around 40% * Implements domainSetMemoryParameters and domainGetMemoryParameters for remote driver daemon/remote.c src/remote/remote_driver.c
* Auto generate the files using rpcgen and helper scripts in daemon/ directory src/remote/remote_protocol.x daemon/remote_dispatch_args.h daemon/remote_dispatch_prototypes.h daemon/remote_dispatch_ret.h daemon/remote_dispatch_table.h src/remote/remote_protocol.c src/remote/remote_protocol.h
Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [...] static int +remoteDispatchDomainSetMemoryParameters (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_set_memory_parameters_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virDomainPtr dom; + int i, r, nparams; + virMemoryParameterPtr params; + unsigned int flags; + + nparams = args->params.params_len; + nparams = args->flags;
obvious bug: flags = args->flags;
That reminds me that I didn't see flags being checked against 0 on the QEmu and LXC drivers, we should check them !
+ if (nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) { + remoteDispatchFormatError (rerr, "%s", _("nparams too large")); + return -1;
I did a lot of reformating and code cleanups in the non-generated files, to try to keep the source readable on a 80 columns editor.
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 8af469c..f5dcb5c 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -128,6 +128,9 @@ const REMOTE_NWFILTER_NAME_LIST_MAX = 1024; /* Upper limit on list of scheduler parameters. */ const REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX = 16;
+/* Upper limit on list of memory parameters. */ +const REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX = 16; +
Hopefully we won't exhaust that crucial limit
That limit isn't ABI critical. It is simply to prevent DOS when de-marshalling data, so we can raise it at will in the future. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Tue, 12 Oct 2010 19:27:05 +0200, Daniel Veillard <veillard@redhat.com> wrote:
On Fri, Oct 08, 2010 at 05:47:03PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
v4: * prototype change: add unsigned int flags, regenerate files
v3: * Squased all the remote driver changes to one single big patch and auto-generated is around 40% * Implements domainSetMemoryParameters and domainGetMemoryParameters for remote driver daemon/remote.c src/remote/remote_driver.c
* Auto generate the files using rpcgen and helper scripts in daemon/ directory src/remote/remote_protocol.x daemon/remote_dispatch_args.h daemon/remote_dispatch_prototypes.h daemon/remote_dispatch_ret.h daemon/remote_dispatch_table.h src/remote/remote_protocol.c src/remote/remote_protocol.h
Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [...] + nparams = args->params.params_len; + nparams = args->flags;
obvious bug: flags = args->flags; Oops :) - C&P
That reminds me that I didn't see flags being checked against 0 on the QEmu and LXC drivers, we should check them !
I will take care of this.
+ if (nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) { + remoteDispatchFormatError (rerr, "%s", _("nparams too large")); + return -1;
I did a lot of reformating and code cleanups in the non-generated files, to try to keep the source readable on a 80 columns editor.
Thanks,
With that done, I think I can ACK the whole serie, and pushed it, but there is still a number of small TODOs for which I would appreciate patches,
thanks a lot !
Thanks a lot to you and Daniel Berrange. Both of you have spend a lot of time on reviewing and on top of that fixing the patches as well. Regards, Nikunj

On Wed, Oct 13, 2010 at 11:12:49AM +0530, Nikunj A. Dadhania wrote:
On Tue, 12 Oct 2010 19:27:05 +0200, Daniel Veillard <veillard@redhat.com> wrote:
On Fri, Oct 08, 2010 at 05:47:03PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
v4: * prototype change: add unsigned int flags, regenerate files
v3: * Squased all the remote driver changes to one single big patch and auto-generated is around 40% * Implements domainSetMemoryParameters and domainGetMemoryParameters for remote driver daemon/remote.c src/remote/remote_driver.c
* Auto generate the files using rpcgen and helper scripts in daemon/ directory src/remote/remote_protocol.x daemon/remote_dispatch_args.h daemon/remote_dispatch_prototypes.h daemon/remote_dispatch_ret.h daemon/remote_dispatch_table.h src/remote/remote_protocol.c src/remote/remote_protocol.h
Acked-by: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [...] + nparams = args->params.params_len; + nparams = args->flags;
obvious bug: flags = args->flags; Oops :) - C&P
That reminds me that I didn't see flags being checked against 0 on the QEmu and LXC drivers, we should check them !
I will take care of this.
virCheckFlags(0, -1); as in qemuDomainGetBlockInfo() for example.
With that done, I think I can ACK the whole serie, and pushed it, but there is still a number of small TODOs for which I would appreciate patches,
thanks a lot !
Thanks a lot to you and Daniel Berrange. Both of you have spend a lot of time on reviewing and on top of that fixing the patches as well.
Well this would have been a bit simpler if you had used "make syntax-check " from the beginning, but most of the time spent was actually code review and fixes, not those trivial issues :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Fri, 08 Oct 2010 17:44:32 +0530, "Nikunj A. Dadhania" <nikunj@linux.vnet.ibm.com> wrote:
Changelog from v3: * Add unsigned int flags to the public api and make corresponding changes further down till the drivers(qemu, lxc and remote) * Move exporting of the api's to patch two * Added memtune test in tests/qemuxml2xmltest.c * Fix: src/conf/domain_conf.c - print memtune element only if tunable is present * Fix: src/qemu/qemu_driver.c - call cgroup apis only if nonzero * Fix: src/lxc/lxc_controller.c - call cgroup apis only if nonzero
Hi Daniel, Let me know if I need to push the patches, 8 of them have the ACKs. I suppose it will be the libvirt requirement for the complete series to be acked, before the series goes in. I was waiting for the ACKs for the rest of patches (Patch number 01,02,07,11,12). Regards, Nikunj
participants (6)
-
Daniel P. Berrange
-
Daniel Veillard
-
Eric Blake
-
Matthias Bolte
-
Nikunj A. Dadhania
-
Stefan Berger