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

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 | 158 ++++++++++++++++++++++ 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 | 68 +++++++++ python/generator.py | 2 python/libvirt-override-api.xml | 12 ++ python/libvirt-override.c | 14 ++ src/conf/domain_conf.c | 50 ++++++- src/conf/domain_conf.h | 12 +- src/driver.h | 12 ++ src/esx/esx_driver.c | 2 src/esx/esx_vmx.c | 30 ++-- src/libvirt.c | 103 ++++++++++++++ src/libvirt_private.syms | 6 + src/libvirt_public.syms | 6 + src/lxc/lxc_controller.c | 24 +++ src/lxc/lxc_driver.c | 213 ++++++++++++++++++++++++++++- 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 | 256 ++++++++++++++++++++++++++++++++++- src/remote/remote_driver.c | 146 ++++++++++++++++++++ src/remote/remote_protocol.c | 84 +++++++++++ src/remote/remote_protocol.h | 56 ++++++++ src/remote/remote_protocol.x | 42 ++++++ 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 tools/virsh.c | 130 ++++++++++++++++++ 36 files changed, 1592 insertions(+), 68 deletions(-)

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. 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 | 68 +++++++++++++++++++++++++++++++++++++++ python/generator.py | 2 + python/libvirt-override-api.xml | 12 +++++++ python/libvirt-override.c | 14 ++++++++ 4 files changed, 96 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index b45f7ec..a528f67 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -674,6 +674,74 @@ 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); +/* Get memory tunables for the domain, caller allocates the params if nparams + * is zero and params is NULL, the domain returns back number of parameters + * supported by the HV. This could be used by the caller to allocate the + * memory and call with params structure allocated. + */ +int virDomainGetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int *nparams); + /* * 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 Tue, Sep 28, 2010 at 03:26:15PM +0530, Nikunj A. Dadhania wrote:
+ +/* Set memory tunables for the domain*/ +int virDomainSetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int nparams); +/* Get memory tunables for the domain, caller allocates the params if nparams + * is zero and params is NULL, the domain returns back number of parameters + * supported by the HV. This could be used by the caller to allocate the + * memory and call with params structure allocated. + */ +int virDomainGetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int *nparams);
We should add an 'unsigned int flags' parameter to both of these, so we can extend their semantics in the future. The comment here can be moved to the libvirt.c file so it gets picked up in the API docs. 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 Thu, 7 Oct 2010 12:45:22 +0100, "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Tue, Sep 28, 2010 at 03:26:15PM +0530, Nikunj A. Dadhania wrote:
+ +/* Set memory tunables for the domain*/ +int virDomainSetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int nparams); +/* Get memory tunables for the domain, caller allocates the params if nparams + * is zero and params is NULL, the domain returns back number of parameters + * supported by the HV. This could be used by the caller to allocate the + * memory and call with params structure allocated. + */ +int virDomainGetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int *nparams);
We should add an 'unsigned int flags' parameter to both of these, so we can extend their semantics in the future. I have added this and mentioned it as unused at present.
The comment here can be moved to the libvirt.c file so it gets picked up in the API docs.
I have already put a detailed comment in libvirt.c for API docs. I am getting rid of this for now. Nikunj

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 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 | 12 +++++ src/esx/esx_driver.c | 2 + src/libvirt.c | 103 ++++++++++++++++++++++++++++++++++++++++++++ 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 + 11 files changed, 133 insertions(+), 0 deletions(-) diff --git a/src/driver.h b/src/driver.h index e443c1c..0580bee 100644 --- a/src/driver.h +++ b/src/driver.h @@ -128,6 +128,16 @@ typedef int (*virDrvDomainSetMemory) (virDomainPtr domain, unsigned long memory); typedef int + (*virDrvDomainSetMemoryParameters) + (virDomainPtr domain, + virMemoryParameterPtr params, + int nparams); +typedef int + (*virDrvDomainGetMemoryParameters) + (virDomainPtr domain, + virMemoryParameterPtr params, + int *nparams); +typedef int (*virDrvDomainGetInfo) (virDomainPtr domain, virDomainInfoPtr info); typedef int @@ -575,6 +585,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..0708e36 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3000,6 +3000,109 @@ 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) + * + * Change the memory tunables + * This function requires privileged access to the hypervisor. + * FIXME: Should we make changes to the domain configuration file as well? + * + * Returns -1 in case of error, 0 in case of success. + */ +int +virDomainSetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int nparams) +{ + virConnectPtr conn; + DEBUG("domain=%p, params=%p, nparams=%d", domain, params, nparams); + + 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); + 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 + * + * 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) +{ + virConnectPtr conn; + DEBUG("domain=%p, params=%p, nparams=%d", domain, params, (nparams)?*nparams:-1); + + 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); + 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/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 8eeba73..ec47289 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -3980,6 +3980,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 a945710..c1051a1 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -10358,6 +10358,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 Tue, Sep 28, 2010 at 03:26:20PM +0530, Nikunj A. Dadhania wrote:
diff --git a/src/libvirt.c b/src/libvirt.c index ca383ba..0708e36 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3000,6 +3000,109 @@ 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) + * + * Change the memory tunables + * This function requires privileged access to the hypervisor. + * FIXME: Should we make changes to the domain configuration file as well?
If we add the 'unsigned int flags' parameter, then we can later extend this with flags to specify whether the persistent config is changed at same time as the live config. 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 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 ccb8cf3..d75254c 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 Tue, Sep 28, 2010 at 03:26:25PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
The patch adds xml entries to the domain.rng file.
v2: + Fix typo min_guarantee
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- docs/schemas/domain.rng | 31 +++++++++++++++++++++++++++++++ 1 files changed, 31 insertions(+), 0 deletions(-)
ACK, looks fine 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> Adding parsing code for memory tunables in the domain xml file v2: + Fix typo min_guarantee Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/conf/domain_conf.c | 50 +++++++++++++++++++++++++++++++++++++------- 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 ++++++------ 11 files changed, 104 insertions(+), 64 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index e05d5d7..0dd74e4 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -4231,19 +4231,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; @@ -6382,10 +6401,25 @@ 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); + 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); + } + 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 7195c04..2ecc2af 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -864,9 +864,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 59eb3b2..6f1eb17 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>" @@ -979,7 +979,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; } @@ -991,7 +991,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, @@ -1003,10 +1003,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 */ @@ -2469,32 +2469,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;

* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-09-28 15:26:30]:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Adding parsing code for memory tunables in the domain xml file
v2: + Fix typo min_guarantee
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/conf/domain_conf.c | 50 +++++++++++++++++++++++++++++++++++++------- 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 ++++++------ 11 files changed, 104 insertions(+), 64 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index e05d5d7..0dd74e4 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -4231,19 +4231,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; +
Quick question, does 0 represent invalid values? I'd presume you'd want to use something like -1. We support unsigned long long for the values to be set (64 bit signed), unlimited translates to 2^63 - 1, is ULong sufficient to represent that value?
if (virXPathULong("string(./vcpu[1])", ctxt, &def->vcpus) < 0) def->vcpus = 1;
@@ -6382,10 +6401,25 @@ 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); + 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); + } + 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 7195c04..2ecc2af 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -864,9 +864,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;
The hard_limit, soft_limit, swap_hard_limit are s64 and the value is in bytes. What is the unit supported in this implementation?
+ } mem; unsigned long vcpus; int cpumasklen; char *cpumask; diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c index 59eb3b2..6f1eb17 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>"
@@ -979,7 +979,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; } @@ -991,7 +991,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, @@ -1003,10 +1003,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 */ @@ -2469,32 +2469,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;
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- Three Cheers, Balbir

On Mon, 4 Oct 2010 12:16:42 +0530, Balbir Singh <balbir@linux.vnet.ibm.com> wrote:
* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-09-28 15:26:30]: <snip>
+ /* 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; +
Quick question, does 0 represent invalid values? If configuration file does not provide any value, we set this to 0, we do not call the lower layer calls in this case.
I'd presume you'd want to use something like -1. We support unsigned long long for the values to be set (64 bit signed), unlimited translates to 2^63 - 1, is ULong sufficient to represent that value? The unit here is KB, so we can have till 2^42 bytes. So to answer you question, no it does not represent 64 bit signed. I guess this should not be an issue to support if needed.
I understand that in case of cgroup unlimited is (-1), but again that would be cgroup specific at this level. I need to think of some way to address this independent of the lower layer.
+ unsigned long hard_limit; + unsigned long soft_limit; + unsigned long min_guarantee; + unsigned long swap_hard_limit;
The hard_limit, soft_limit, swap_hard_limit are s64 and the value is in bytes. What is the unit supported in this implementation? KB
Thanks for reviewing. Regard Nikunj

On Mon, Oct 04, 2010 at 12:47:22PM +0530, Nikunj A. Dadhania wrote:
On Mon, 4 Oct 2010 12:16:42 +0530, Balbir Singh <balbir@linux.vnet.ibm.com> wrote:
* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-09-28 15:26:30]: <snip>
+ /* 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; +
Quick question, does 0 represent invalid values? If configuration file does not provide any value, we set this to 0, we do not call the lower layer calls in this case.
I'd presume you'd want to use something like -1. We support unsigned long long for the values to be set (64 bit signed), unlimited translates to 2^63 - 1, is ULong sufficient to represent that value? The unit here is KB, so we can have till 2^42 bytes. So to answer you question, no it does not represent 64 bit signed. I guess this should not be an issue to support if needed.
I understand that in case of cgroup unlimited is (-1), but again that would be cgroup specific at this level. I need to think of some way to address this independent of the lower layer.
+ unsigned long hard_limit; + unsigned long soft_limit; + unsigned long min_guarantee; + unsigned long swap_hard_limit;
The hard_limit, soft_limit, swap_hard_limit are s64 and the value is in bytes. What is the unit supported in this implementation?
Actually if libvirt is built on 32bit these aren't big enough - make them into 'unsigned long long' data types I reckon. 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 Thu, 7 Oct 2010 12:49:29 +0100, "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Mon, Oct 04, 2010 at 12:47:22PM +0530, Nikunj A. Dadhania wrote:
On Mon, 4 Oct 2010 12:16:42 +0530, Balbir Singh <balbir@linux.vnet.ibm.com> wrote:
* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-09-28 15:26:30]: <snip>
+ unsigned long hard_limit; + unsigned long soft_limit; + unsigned long min_guarantee; + unsigned long swap_hard_limit;
The hard_limit, soft_limit, swap_hard_limit are s64 and the value is in bytes. What is the unit supported in this implementation?
Actually if libvirt is built on 32bit these aren't big enough - make them into 'unsigned long long' data types I reckon.
I was thinking that as we are having the unit of KB, we would be able to represent 2^42 bytes of memory limit, ie. 4 Terabytes. Won't this suffice in case of 32bit? Nikunj

* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-10-08 12:00:44]:
On Thu, 7 Oct 2010 12:49:29 +0100, "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Mon, Oct 04, 2010 at 12:47:22PM +0530, Nikunj A. Dadhania wrote:
On Mon, 4 Oct 2010 12:16:42 +0530, Balbir Singh <balbir@linux.vnet.ibm.com> wrote:
* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-09-28 15:26:30]: <snip>
+ unsigned long hard_limit; + unsigned long soft_limit; + unsigned long min_guarantee; + unsigned long swap_hard_limit;
The hard_limit, soft_limit, swap_hard_limit are s64 and the value is in bytes. What is the unit supported in this implementation?
Actually if libvirt is built on 32bit these aren't big enough - make them into 'unsigned long long' data types I reckon.
I was thinking that as we are having the unit of KB, we would be able to represent 2^42 bytes of memory limit, ie. 4 Terabytes. Won't this suffice in case of 32bit?
How would you represent -1 (2^63 -1) as unlimited or max limit we use today? -- Three Cheers, Balbir

On Fri, 8 Oct 2010 14:10:53 +0530, Balbir Singh <balbir@linux.vnet.ibm.com> wrote:
* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-10-08 12:00:44]:
On Thu, 7 Oct 2010 12:49:29 +0100, "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Mon, Oct 04, 2010 at 12:47:22PM +0530, Nikunj A. Dadhania wrote:
On Mon, 4 Oct 2010 12:16:42 +0530, Balbir Singh <balbir@linux.vnet.ibm.com> wrote:
* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-09-28 15:26:30]: <snip>
+ unsigned long hard_limit; + unsigned long soft_limit; + unsigned long min_guarantee; + unsigned long swap_hard_limit;
The hard_limit, soft_limit, swap_hard_limit are s64 and the value is in bytes. What is the unit supported in this implementation?
Actually if libvirt is built on 32bit these aren't big enough - make them into 'unsigned long long' data types I reckon.
I was thinking that as we are having the unit of KB, we would be able to represent 2^42 bytes of memory limit, ie. 4 Terabytes. Won't this suffice in case of 32bit?
How would you represent -1 (2^63 -1) as unlimited or max limit we use today?
I think I have answered this question in the thread: this is specific to cgroup that -1 means unlimited, this may not be true for other HVs. Nikunj

* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-10-08 14:43:34]:
On Fri, 8 Oct 2010 14:10:53 +0530, Balbir Singh <balbir@linux.vnet.ibm.com> wrote:
* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-10-08 12:00:44]:
On Thu, 7 Oct 2010 12:49:29 +0100, "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Mon, Oct 04, 2010 at 12:47:22PM +0530, Nikunj A. Dadhania wrote:
On Mon, 4 Oct 2010 12:16:42 +0530, Balbir Singh <balbir@linux.vnet.ibm.com> wrote:
* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-09-28 15:26:30]: <snip> > + unsigned long hard_limit; > + unsigned long soft_limit; > + unsigned long min_guarantee; > + unsigned long swap_hard_limit;
The hard_limit, soft_limit, swap_hard_limit are s64 and the value is in bytes. What is the unit supported in this implementation?
Actually if libvirt is built on 32bit these aren't big enough - make them into 'unsigned long long' data types I reckon.
I was thinking that as we are having the unit of KB, we would be able to represent 2^42 bytes of memory limit, ie. 4 Terabytes. Won't this suffice in case of 32bit?
How would you represent -1 (2^63 -1) as unlimited or max limit we use today?
I think I have answered this question in the thread: this is specific to cgroup that -1 means unlimited, this may not be true for other HVs.
OK, so how do we handle unlimited values in general? -- Three Cheers, Balbir

On Tue, 12 Oct 2010 19:19:21 +0530, Balbir Singh <balbir@linux.vnet.ibm.com> wrote:
* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-10-08 14:43:34]:
On Fri, 8 Oct 2010 14:10:53 +0530, Balbir Singh <balbir@linux.vnet.ibm.com> wrote:
* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-10-08 12:00:44]:
On Thu, 7 Oct 2010 12:49:29 +0100, "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Mon, Oct 04, 2010 at 12:47:22PM +0530, Nikunj A. Dadhania wrote:
On Mon, 4 Oct 2010 12:16:42 +0530, Balbir Singh <balbir@linux.vnet.ibm.com> wrote: > * Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-09-28 15:26:30]: <snip> > > + unsigned long hard_limit; > > + unsigned long soft_limit; > > + unsigned long min_guarantee; > > + unsigned long swap_hard_limit; > > The hard_limit, soft_limit, swap_hard_limit are s64 and the value is > in bytes. What is the unit supported in this implementation?
Actually if libvirt is built on 32bit these aren't big enough - make them into 'unsigned long long' data types I reckon.
I was thinking that as we are having the unit of KB, we would be able to represent 2^42 bytes of memory limit, ie. 4 Terabytes. Won't this suffice in case of 32bit?
How would you represent -1 (2^63 -1) as unlimited or max limit we use today?
I think I have answered this question in the thread: this is specific to cgroup that -1 means unlimited, this may not be true for other HVs.
OK, so how do we handle unlimited values in general?
At present, API does not have a way to do this. We have added a flag in the API, let me think of some way I could use it for such setting unlimited values. Regards Nikunj

On Tue, Sep 28, 2010 at 03:26:30PM +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
v2: + Fix typo min_guarantee
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/conf/domain_conf.c | 50 +++++++++++++++++++++++++++++++++++++------- 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 ++++++------ 11 files changed, 104 insertions(+), 64 deletions(-)
ACK, looks fine, though it'd be good to add one or two example data files to tests/qemuxml2xmltest.c to ensure that we roundtrip through the XML parser+formatter correctly. 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 Thu, 7 Oct 2010 12:48:26 +0100, "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Tue, Sep 28, 2010 at 03:26:30PM +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
v2: + Fix typo min_guarantee
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/conf/domain_conf.c | 50 +++++++++++++++++++++++++++++++++++++------- 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 ++++++------ 11 files changed, 104 insertions(+), 64 deletions(-)
ACK, looks fine, though it'd be good to add one or two example data files to tests/qemuxml2xmltest.c to ensure that we roundtrip through the XML parser+formatter correctly.
Sure, will add the files, and send the updated series Nikunj

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 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 c2905ba..038dd77 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,

* Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> [2010-09-28 15:26:35]:
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
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
The changes look good to me. unsigned long kb should cover all values in bytes as well. Acked-by: Balbir Singh <balbir@linux.vnet.ibm.com> -- Three Cheers, Balbir

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> Driver interface for setting memory hard_limit, soft_limit and swap hard_limit. v2: + Use #define string constants for "hard_limit", etc. + fix typo: min_guarantee Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/qemu/qemu_driver.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 93 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index bf4373a..b6be343 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -9365,6 +9365,98 @@ cleanup: return ret; } + +static int qemuDomainSetMemoryParameters(virDomainPtr dom, + virMemoryParameterPtr params, + int nparams) +{ + 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 +12802,7 @@ static virDriver qemuDriver = { qemuDomainRevertToSnapshot, /* domainRevertToSnapshot */ qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ - NULL, /* domainSetMemoryParameters */ + qemuDomainSetMemoryParameters, /* domainSetMemoryParameters */ NULL, /* domainGetMemoryParameters */ };

On Tue, Sep 28, 2010 at 03:26:41PM +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.
v2: + Use #define string constants for "hard_limit", etc. + fix typo: min_guarantee
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/qemu/qemu_driver.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 93 insertions(+), 1 deletions(-)
ACK, looks fine. 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> 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 | 119 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 118 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b6be343..fcb7f9d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -9457,6 +9457,123 @@ cleanup: return ret; } +static int qemuDomainGetMemoryParameters(virDomainPtr dom, + virMemoryParameterPtr params, + int *nparams) +{ + 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) @@ -12803,7 +12920,7 @@ static virDriver qemuDriver = { qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ qemuDomainSetMemoryParameters, /* domainSetMemoryParameters */ - NULL, /* domainGetMemoryParameters */ + qemuDomainGetMemoryParameters, /* domainGetMemoryParameters */ };

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> QEmu startup would pick up the memory tunables specified in the domain configuration file. 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 | 27 +++++++++++++++++++++++++++ 3 files changed, 31 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 fcb7f9d..6d05bf8 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3495,6 +3495,33 @@ static int qemuSetupCgroup(struct qemud_driver *driver, goto cleanup; } + if ((rc = qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY))) { + 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; + } + 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; + } + 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 Tue, Sep 28, 2010 at 03:26:55PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
QEmu startup would pick up the memory tunables specified in the domain configuration file.
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 | 27 +++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-)
ACK, looks fine. 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> libvirt-lxc now configures the hardlimit, softlimit and swaplimit, if specified in the domain xml file or picks up the defaults. Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/lxc/lxc_controller.c | 22 ++++++++++++++++++++++ 1 files changed, 22 insertions(+), 0 deletions(-) diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 82ecce0..dee99b7 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -109,6 +109,28 @@ static int lxcSetContainerResources(virDomainDefPtr def) def->name); goto cleanup; } + + 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; + } + 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; + } + 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 Tue, Sep 28, 2010 at 03:27:02PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
libvirt-lxc now configures the hardlimit, softlimit and swaplimit, if specified in the domain xml file or picks up the defaults.
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/lxc/lxc_controller.c | 22 ++++++++++++++++++++++ 1 files changed, 22 insertions(+), 0 deletions(-)
ACK 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> Add support in the lxc driver for various memory controllable parameters v2: + Use #define string constants for "hard_limit", etc + fix typo: min_guarantee Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/lxc/lxc_driver.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 89 insertions(+), 1 deletions(-) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 8977835..6912bb8 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -677,6 +677,94 @@ cleanup: return ret; } +static int lxcDomainSetMemoryParameters(virDomainPtr dom, + virMemoryParameterPtr params, + int nparams) +{ + 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 +2708,7 @@ static virDriver lxcDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ - NULL, /* domainSetMemoryParameters */ + lxcDomainSetMemoryParameters, /* domainSetMemoryParameters */ NULL, /* domainGetMemoryParameters */ };

On Tue, Sep 28, 2010 at 03:27:08PM +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
v2: + Use #define string constants for "hard_limit", etc + fix typo: min_guarantee
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/lxc/lxc_driver.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 89 insertions(+), 1 deletions(-)
ACK, basically the same as the QEMU impl. 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> 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 | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 112 insertions(+), 1 deletions(-) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 6912bb8..e60a569 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -765,6 +765,117 @@ cleanup: return ret; } +static int lxcDomainGetMemoryParameters(virDomainPtr dom, + virMemoryParameterPtr params, + int *nparams) +{ + 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) { @@ -2709,7 +2820,7 @@ static virDriver lxcDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ lxcDomainSetMemoryParameters, /* domainSetMemoryParameters */ - NULL, /* domainGetMemoryParameters */ + lxcDomainGetMemoryParameters, /* domainGetMemoryParameters */ }; static virStateDriver lxcStateDriver = {

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) 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> --- src/libvirt_public.syms | 6 ++ tools/virsh.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 0 deletions(-) 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/tools/virsh.c b/tools/virsh.c index 85014f2..0500cb5 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 && (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)) { + 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) + 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 Tue, Sep 28, 2010 at 03:27:19PM +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)
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> --- src/libvirt_public.syms | 6 ++ tools/virsh.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 0 deletions(-)
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;
This chunk should actually be with the change to 'src/libvirt.c' in the second patch. 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 Thu, 7 Oct 2010 12:59:57 +0100, "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Tue, Sep 28, 2010 at 03:27:19PM +0530, Nikunj A. Dadhania wrote:
+LIBVIRT_0.8.5 { + global: + virDomainSetMemoryParameters; + virDomainGetMemoryParameters; +} LIBVIRT_0.8.2;
This chunk should actually be with the change to 'src/libvirt.c' in the second patch.
Done Nikunj

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> 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 Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- daemon/remote.c | 158 +++++++++++++++++++++++++++++++++++ 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 | 148 ++++++++++++++++++++++++++++++++- src/remote/remote_protocol.c | 84 +++++++++++++++++++ src/remote/remote_protocol.h | 56 ++++++++++++ src/remote/remote_protocol.x | 42 +++++++++ 9 files changed, 514 insertions(+), 3 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 118654c..c8977d8 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -2332,6 +2332,164 @@ 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; + + nparams = args->params.params_len; + + 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); + 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; + + nparams = args->nparams; + + 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); + 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 c1051a1..1204f6a 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2284,6 +2284,150 @@ done: } static int +remoteDomainSetMemoryParameters (virDomainPtr domain, + virMemoryParameterPtr params, int nparams) +{ + 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; + 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) +{ + 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; + + 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; @@ -10358,8 +10502,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..f05a66d 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,43 @@ 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; + 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; + 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..83fd191 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,30 @@ 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; +}; +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; +}; +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 +2277,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 +2334,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 +2356,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 +2674,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 +2696,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..aa24f98 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,21 @@ 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>; +}; + +struct remote_domain_get_memory_parameters_args { + remote_nonnull_domain dom; + int nparams; +}; + +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 +2058,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 Tue, Sep 28, 2010 at 03:27:24PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
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
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- daemon/remote.c | 158 +++++++++++++++++++++++++++++++++++ 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 | 148 ++++++++++++++++++++++++++++++++- src/remote/remote_protocol.c | 84 +++++++++++++++++++ src/remote/remote_protocol.h | 56 ++++++++++++ src/remote/remote_protocol.x | 42 +++++++++ 9 files changed, 514 insertions(+), 3 deletions(-)
ACK, looks ok 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 :|
participants (3)
-
Balbir Singh
-
Daniel P. Berrange
-
Nikunj A. Dadhania