[libvirt] [PATCH 00/12] Implement memory control api

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 * virDomainGetMemoryParameters 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 (12): Adding virDomainSetMemoryParameters API Adding structure for virDomainSetMemoryParameter Adds xml entries for memory tunables XML parsing for memory tunables Hand-coded python bindings for virDomainSetMemoryParameters Implement driver interface domainSetMemoryParamters for QEmu Implement cgroup memory controller tunables Adding memtunables to libvirt-lxc command Adding memtunables to qemuSetupCgroup Adding memtune command to virsh tool Implements virDomainSetMemoryParameters for the remote driver Implement domainSetMemoryParameters function daemon/remote.c | 66 +++++++++++++++++ daemon/remote_dispatch_prototypes.h | 8 ++ daemon/remote_dispatch_table.h | 5 + docs/schemas/domain.rng | 31 ++++++++ include/libvirt/libvirt.h.in | 56 ++++++++++++++ python/generator.py | 1 python/libvirt-override-api.xml | 6 ++ python/libvirt-override.c | 7 ++ src/conf/domain_conf.c | 50 +++++++++++-- src/conf/domain_conf.h | 12 ++- src/driver.h | 6 ++ src/esx/esx_driver.c | 1 src/esx/esx_vmx.c | 30 ++++---- src/libvirt.c | 48 ++++++++++++ src/libvirt_private.syms | 6 ++ src/libvirt_public.syms | 5 + src/lxc/lxc_controller.c | 24 ++++++ src/lxc/lxc_driver.c | 101 ++++++++++++++++++++++++-- src/openvz/openvz_driver.c | 9 +- src/phyp/phyp_driver.c | 1 src/qemu/qemu.conf | 4 + src/qemu/qemu_conf.c | 11 ++- src/qemu/qemu_driver.c | 138 +++++++++++++++++++++++++++++++++-- src/remote/remote_driver.c | 66 +++++++++++++++++ src/remote/remote_protocol.c | 62 +++++++++++++++- src/remote/remote_protocol.h | 36 +++++++++ src/test/test_driver.c | 13 ++- src/uml/uml_conf.c | 2 - src/uml/uml_driver.c | 15 ++-- src/util/cgroup.c | 106 +++++++++++++++++++++++++++ src/util/cgroup.h | 7 ++ src/xen/xen_driver.c | 1 tools/virsh.c | 89 +++++++++++++++++++++++ 33 files changed, 955 insertions(+), 68 deletions(-)

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> Public api to set memory tunables supported by the hypervisors. RFC: https://www.redhat.com/archives/libvir-list/2010-August/msg00607.html Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- include/libvirt/libvirt.h.in | 5 ++++ src/driver.h | 6 +++++ src/libvirt.c | 49 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index b45f7ec..f546ba6 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -674,6 +674,11 @@ int virDomainGetInfo (virDomainPtr domain, char * virDomainGetSchedulerType(virDomainPtr domain, int *nparams); +/* Set memory tunables for the domain*/ +int virDomainSetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int nparams); + /* * Dynamic control of domains */ diff --git a/src/driver.h b/src/driver.h index e443c1c..01004e3 100644 --- a/src/driver.h +++ b/src/driver.h @@ -128,6 +128,11 @@ typedef int (*virDrvDomainSetMemory) (virDomainPtr domain, unsigned long memory); typedef int + (*virDrvDomainSetMemoryParameters) + (virDomainPtr domain, + virMemoryParameterPtr params, + int nparams); +typedef int (*virDrvDomainGetInfo) (virDomainPtr domain, virDomainInfoPtr info); typedef int @@ -575,6 +580,7 @@ struct _virDriver { virDrvDomainRevertToSnapshot domainRevertToSnapshot; virDrvDomainSnapshotDelete domainSnapshotDelete; virDrvQemuDomainMonitorCommand qemuDomainMonitorCommand; + virDrvDomainSetMemoryParameters domainSetMemoryParameters; }; typedef int diff --git a/src/libvirt.c b/src/libvirt.c index ca383ba..64daaa3 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3000,6 +3000,55 @@ 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; +} + +/** * virDomainGetInfo: * @domain: a domain object * @info: pointer to a virDomainInfo structure allocated by the user

On Mon, Sep 20, 2010 at 02:14:49PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Public api to set memory tunables supported by the hypervisors. RFC: https://www.redhat.com/archives/libvir-list/2010-August/msg00607.html
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- include/libvirt/libvirt.h.in | 5 ++++ src/driver.h | 6 +++++ src/libvirt.c | 49 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index b45f7ec..f546ba6 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -674,6 +674,11 @@ int virDomainGetInfo (virDomainPtr domain, char * virDomainGetSchedulerType(virDomainPtr domain, int *nparams);
+/* Set memory tunables for the domain*/ +int virDomainSetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int nparams); +
How about a virDomainGetMemoryParameters() API too ? I know you can get that via XML, but since we're adding a 'setter' its easy to add a 'getter' at the same time. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Tue, 21 Sep 2010 18:13:33 +0100, "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Mon, Sep 20, 2010 at 02:14:49PM +0530, Nikunj A. Dadhania wrote:
From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
+/* Set memory tunables for the domain*/ +int virDomainSetMemoryParameters(virDomainPtr domain, + virMemoryParameterPtr params, + int nparams); +
How about a virDomainGetMemoryParameters() API too ? I know you can get that via XML, but since we're adding a 'setter' its easy to add a 'getter' at the same time.
That is in the list of my todo [patch 00/12]. As the patch series was getting bigger, I thought of pushing the virDomainSetMemoryParamters first and would send the getter next. Nikunj

This patch adds a structure virMemoryParameter, it contains the name of the parameter and the type of the parameter along with a union. Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- include/libvirt/libvirt.h.in | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 51 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index f546ba6..8beedeb 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -674,6 +674,57 @@ 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 + +/** + * 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,

On Mon, Sep 20, 2010 at 02:15:23PM +0530, Nikunj A. Dadhania wrote:
This patch adds a structure virMemoryParameter, it contains the name of the parameter and the type of the parameter along with a union.
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- include/libvirt/libvirt.h.in | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 51 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index f546ba6..8beedeb 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -674,6 +674,57 @@ 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 + +/** + * 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 */ +};
With the schedular parameters API we gave up and decided that each HV would be different for 'field', so used string parameters. I wonder if we could use an enum for memory parameters, or keep this char[] as extensible for HV specific memory tuning params? Perhaps its worth keeping like this just for consistent usage with _virSchedParameter If we keep strings, then we should probably #define some constants for the well-known tunables. eg #define VIR_DOMAIN_MEMORY_MAX_BALLOON "max-balloon" Oh, BTW this patch should be merged with the previous patch. The idea with a series of patches, is that the code should successfully compile after each individual patch is applied. The previous patch has a compile time dependancy on this patch, thus they need merging, or reversing in order Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Tue, 21 Sep 2010 18:12:29 +0100, "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Mon, Sep 20, 2010 at 02:15:23PM +0530, Nikunj A. Dadhania wrote:
This patch adds a structure virMemoryParameter, it contains the name of the parameter and the type of the parameter along with a union.
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- include/libvirt/libvirt.h.in | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 51 insertions(+), 0 deletions(-)
+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 */ +};
With the schedular parameters API we gave up and decided that each HV would be different for 'field', so used string parameters. I wonder if we could use an enum for memory parameters, or keep this char[] as extensible for HV specific memory tuning params? Perhaps its worth keeping like this just for consistent usage with _virSchedParameter
I agree, keeping the string would not limit any HVs from adding new parameters that are specific to some HV.
If we keep strings, then we should probably #define some constants for the well-known tunables.
eg #define VIR_DOMAIN_MEMORY_MAX_BALLOON "max-balloon" Sure, I will take care of this.
Oh, BTW this patch should be merged with the previous patch. The idea with a series of patches, is that the code should successfully compile after each individual patch is applied. The previous patch has a compile time dependancy on this patch, thus they need merging, or reversing in order
Thanks, did not know this trivia. I will reverse the order. Nikunj

The patch adds xml entries to the domain.rng file. 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..6d123ab 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_gaurantee"> + <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 Mon, Sep 20, 2010 at 02:15:37PM +0530, Nikunj A. Dadhania wrote:
The patch adds xml entries to the domain.rng file.
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..6d123ab 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_gaurantee">
Small typo there, s/gaur/guar/
+ <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>
Also the indentation looks a bit wacky. Tabs in the file perhaps ?
<element name="vcpu"> <optional>
The schema additions look fine to me though. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Tue, 21 Sep 2010 18:14:51 +0100, "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Mon, Sep 20, 2010 at 02:15:37PM +0530, Nikunj A. Dadhania wrote:
The patch adds xml entries to the domain.rng file.
+ <!-- Minimum amount of memory required to start the VM --> + <optional> + <element name="min_gaurantee">
Small typo there, s/gaur/guar/ Sure
+ <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>
Also the indentation looks a bit wacky. Tabs in the file perhaps ?
I am not sure why! I had used emacs and the indentation was automatic.
<element name="vcpu"> <optional>
The schema additions look fine to me though. Cool.
Nikunj

Adding parsing code for memory tunables in the domain xml file 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..0dde079 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_gaurantee[1])", ctxt, + &def->mem.min_gaurantee) < 0) + def->mem.min_gaurantee = 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..64a486d 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_gaurantee; + 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 326fee6..bcd4381 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 1ad93d9..d6621f0 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 25695df..c4aacc9 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 9d22339..729025e 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 9101928..de52db6 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;

On Mon, Sep 20, 2010 at 02:15:52PM +0530, Nikunj A. Dadhania wrote:
Adding parsing code for memory tunables in the domain xml file
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(-)
All looks pretty straightforward & following the schema 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 :|

Adding the python bindings place holders as they could not be autogenerated by the script. Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- python/generator.py | 1 + python/libvirt-override-api.xml | 6 ++++++ python/libvirt-override.c | 7 +++++++ 3 files changed, 14 insertions(+), 0 deletions(-) diff --git a/python/generator.py b/python/generator.py index d876df6..8ae13d9 100755 --- a/python/generator.py +++ b/python/generator.py @@ -306,6 +306,7 @@ skip_impl = ( 'virDomainGetSchedulerType', 'virDomainGetSchedulerParameters', 'virDomainSetSchedulerParameters', + 'virDomainSetMemoryParameters', 'virDomainGetVcpus', 'virDomainPinVcpu', 'virSecretGetValue', diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index ca16993..6bef208 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -162,6 +162,12 @@ <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='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..c6cedcf 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -371,6 +371,13 @@ 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; +} + static PyObject * libvirt_virDomainGetVcpus(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {

Driver interface for setting memory hard_limit, soft_limit and swap hard_limit. This patch also NULLs the other HV driver interface structure. Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/esx/esx_driver.c | 1 src/lxc/lxc_driver.c | 1 src/openvz/openvz_driver.c | 1 src/phyp/phyp_driver.c | 1 src/qemu/qemu_driver.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 1 src/test/test_driver.c | 1 src/uml/uml_driver.c | 1 src/xen/xen_driver.c | 1 9 files changed, 101 insertions(+), 0 deletions(-) diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index e382950..be55796 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -4217,6 +4217,7 @@ static virDriver esxDriver = { esxDomainRevertToSnapshot, /* domainRevertToSnapshot */ esxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ }; diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index bcd4381..9e37906 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2620,6 +2620,7 @@ static virDriver lxcDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ }; static virStateDriver lxcStateDriver = { diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index d6621f0..beee006 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1657,6 +1657,7 @@ static virDriver openvzDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ }; int openvzRegister(void) { diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 8eeba73..fce451c 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -3980,6 +3980,7 @@ static virDriver phypDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuMonitorCommand */ + NULL, /* domainSetMemoryParameters */ }; static virStorageDriver phypStorageDriver = { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c4aacc9..06666e9 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, "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, "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, "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, "min_gaurantee")) { + 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,6 +12802,7 @@ static virDriver qemuDriver = { qemuDomainRevertToSnapshot, /* domainRevertToSnapshot */ qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ + qemuDomainSetMemoryParameters, /* domainSetMemoryParameters */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index a945710..1e9cb6c 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -10358,6 +10358,7 @@ static virDriver remote_driver = { remoteDomainRevertToSnapshot, /* domainRevertToSnapshot */ remoteDomainSnapshotDelete, /* domainSnapshotDelete */ remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ }; static virNetworkDriver network_driver = { diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 729025e..382d5a8 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5327,6 +5327,7 @@ static virDriver testDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ }; static virNetworkDriver testNetworkDriver = { diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index de52db6..9003e9a 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2196,6 +2196,7 @@ static virDriver umlDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParamters */ }; static int diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 56ba41b..e5ed3d7 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -2006,6 +2006,7 @@ static virDriver xenUnifiedDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ }; /**

On Mon, Sep 20, 2010 at 02:16:51PM +0530, Nikunj A. Dadhania wrote:
Driver interface for setting memory hard_limit, soft_limit and swap hard_limit. This patch also NULLs the other HV driver interface structure.
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/esx/esx_driver.c | 1 src/lxc/lxc_driver.c | 1 src/openvz/openvz_driver.c | 1 src/phyp/phyp_driver.c | 1 src/qemu/qemu_driver.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 1 src/test/test_driver.c | 1 src/uml/uml_driver.c | 1 src/xen/xen_driver.c | 1 9 files changed, 101 insertions(+), 0 deletions(-)
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index e382950..be55796 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -4217,6 +4217,7 @@ static virDriver esxDriver = { esxDomainRevertToSnapshot, /* domainRevertToSnapshot */ esxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ };
All these bits should be in the patch which changes 'driver.h', so that the code compiles there. This patch needs just replace the 'NULL' with the real function for QEMU.
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c4aacc9..06666e9 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, "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, "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, "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, "min_gaurantee")) {
Same typo here s/gaur/guar/
+ 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; +}
This looks pretty sane. Just need to swap patches 6 & 7 in order, because this patch requires the cgroups functions before it will compile Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Tue, 21 Sep 2010 18:21:39 +0100, "Daniel P. Berrange" <berrange@redhat.com> wrote:
On Mon, Sep 20, 2010 at 02:16:51PM +0530, Nikunj A. Dadhania wrote:
Driver interface for setting memory hard_limit, soft_limit and swap hard_limit. This patch also NULLs the other HV driver interface structure.
Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/esx/esx_driver.c | 1 src/lxc/lxc_driver.c | 1 src/openvz/openvz_driver.c | 1 src/phyp/phyp_driver.c | 1 src/qemu/qemu_driver.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 1 src/test/test_driver.c | 1 src/uml/uml_driver.c | 1 src/xen/xen_driver.c | 1 9 files changed, 101 insertions(+), 0 deletions(-)
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index e382950..be55796 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -4217,6 +4217,7 @@ static virDriver esxDriver = { esxDomainRevertToSnapshot, /* domainRevertToSnapshot */ esxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ };
All these bits should be in the patch which changes 'driver.h', so that the code compiles there.
This patch needs just replace the 'NULL' with the real function for QEMU.
Sure, will do that.
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c4aacc9..06666e9 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, "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, "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, "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, "min_gaurantee")) {
Same typo here s/gaur/guar/ Will correct it.
+ 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; +}
This looks pretty sane. Just need to swap patches 6 & 7 in order, because this patch requires the cgroups functions before it will compile Ok
Nikunj

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,

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) {

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 06666e9..99ce52f 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;

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) Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- src/libvirt_public.syms | 5 +++ tools/virsh.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 0 deletions(-) diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 849c163..f33f14a 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -405,4 +405,9 @@ LIBVIRT_0.8.2 { virDomainCreateWithFlags; } LIBVIRT_0.8.1; +LIBVIRT_0.8.5 { + global: + virDomainSetMemoryParameters; +} 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..8158f7c 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2614,6 +2614,94 @@ cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd) } /* + * "memtune" command + */ +static const vshCmdInfo info_memtune[] = { + {"help", N_("change memory paramters")}, + {"desc", N_("Change the current memory paramters for the guest domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_memtune[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"hard_limit", VSH_OT_STRING, VSH_OFLAG_NONE, N_("Max memory in kilobytes")}, + {"soft_limit", VSH_OT_STRING, VSH_OFLAG_NONE, N_("Memory during contention in kilobytes")}, + {"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; + unsigned short 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, "hard_limit", &hard_limit); + if (hard_limit) + nparams++; + + soft_limit = vshCommandOptInt(cmd, "soft_limit", &soft_limit); + if (soft_limit) + nparams++; + + swap_hard_limit = vshCommandOptInt(cmd, "swap_hard_limit", &swap_hard_limit); + if (swap_hard_limit) + nparams++; + + if(nparams == 0) { + /* get the memory parameters */ + vshError(ctl, _("virDomainGetMemoryParameters not implemented")); + } 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_SCHED_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, "soft_limit", sizeof(temp->field)); + soft_limit = 0; + } else if (hard_limit) { + temp->value.ul = hard_limit; + strncpy(temp->field, "hard_limit", sizeof(temp->field)); + hard_limit = 0; + } else if (swap_hard_limit) { + temp->value.ul = swap_hard_limit; + strncpy(temp->field, "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; + } + + virDomainFree(dom); + return ret; +} + +/* * "nodeinfo" command */ static const vshCmdInfo info_nodeinfo[] = { @@ -9431,6 +9519,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},

Implements the call for remote configuration Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> --- daemon/remote.c | 66 ++++++++++++++++++++++++++++++++++ daemon/remote_dispatch_prototypes.h | 8 ++++ daemon/remote_dispatch_table.h | 5 +++ src/libvirt.c | 1 - src/remote/remote_driver.c | 67 ++++++++++++++++++++++++++++++++++- src/remote/remote_protocol.c | 62 ++++++++++++++++++++++++++++++++ src/remote/remote_protocol.h | 36 +++++++++++++++++++ 7 files changed, 242 insertions(+), 3 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 118654c..2d4dc5d 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -2332,6 +2332,72 @@ 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_SCHED_FIELD_INT: + params[i].value.i = args->params.params_val[i].value.remote_memory_param_value_u.i; break; + case VIR_DOMAIN_SCHED_FIELD_UINT: + params[i].value.ui = args->params.params_val[i].value.remote_memory_param_value_u.ui; break; + case VIR_DOMAIN_SCHED_FIELD_LLONG: + params[i].value.l = args->params.params_val[i].value.remote_memory_param_value_u.l; break; + case VIR_DOMAIN_SCHED_FIELD_ULLONG: + params[i].value.ul = args->params.params_val[i].value.remote_memory_param_value_u.ul; break; + case VIR_DOMAIN_SCHED_FIELD_DOUBLE: + params[i].value.d = args->params.params_val[i].value.remote_memory_param_value_u.d; break; + case VIR_DOMAIN_SCHED_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 remoteDispatchDomainSetVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, struct qemud_client *client ATTRIBUTE_UNUSED, virConnectPtr conn, diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h index cf1a0f9..f2bc207 100644 --- a/daemon/remote_dispatch_prototypes.h +++ b/daemon/remote_dispatch_prototypes.h @@ -522,6 +522,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_table.h b/daemon/remote_dispatch_table.h index ef00edd..6692e53 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -987,3 +987,8 @@ .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, +}, diff --git a/src/libvirt.c b/src/libvirt.c index 64daaa3..3e83f94 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3040,7 +3040,6 @@ virDomainSetMemoryParameters(virDomainPtr domain, goto error; return ret; } - virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); error: diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 1e9cb6c..7e4427f 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2284,6 +2284,71 @@ 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_SCHED_FIELD_INT: + args.params.params_val[i].value.remote_memory_param_value_u.i = params[i].value.i; break; + case VIR_DOMAIN_SCHED_FIELD_UINT: + args.params.params_val[i].value.remote_memory_param_value_u.ui = params[i].value.ui; break; + case VIR_DOMAIN_SCHED_FIELD_LLONG: + args.params.params_val[i].value.remote_memory_param_value_u.l = params[i].value.l; break; + case VIR_DOMAIN_SCHED_FIELD_ULLONG: + args.params.params_val[i].value.remote_memory_param_value_u.ul = params[i].value.ul; break; + case VIR_DOMAIN_SCHED_FIELD_DOUBLE: + args.params.params_val[i].value.remote_memory_param_value_u.d = params[i].value.d; break; + case VIR_DOMAIN_SCHED_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 remoteDomainGetInfo (virDomainPtr domain, virDomainInfoPtr info) { int rv = -1; @@ -10358,7 +10423,7 @@ static virDriver remote_driver = { remoteDomainRevertToSnapshot, /* domainRevertToSnapshot */ remoteDomainSnapshotDelete, /* domainSnapshotDelete */ remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ - NULL, /* domainSetMemoryParameters */ + remoteDomainSetMemoryParameters, /* domainSetMemoryParameters */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 2483004..72a6e39 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -264,7 +264,7 @@ bool_t xdr_remote_sched_param_value (XDR *xdrs, remote_sched_param_value *objp) { - if (!xdr_int (xdrs, &objp->type)) + if (!xdr_int (xdrs, &objp->type)) return FALSE; switch (objp->type) { case VIR_DOMAIN_SCHED_FIELD_INT: @@ -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) { @@ -964,6 +1011,19 @@ xdr_remote_domain_set_memory_args (XDR *xdrs, remote_domain_set_memory_args *obj } 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_info_args (XDR *xdrs, remote_domain_get_info_args *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index afe9287..b9fa2d3 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; @@ -525,6 +545,15 @@ struct remote_domain_set_memory_args { }; typedef struct remote_domain_set_memory_args remote_domain_set_memory_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_info_args { remote_nonnull_domain dom; }; @@ -2233,6 +2262,7 @@ 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, }; typedef enum remote_procedure remote_procedure; @@ -2288,6 +2318,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*); @@ -2343,6 +2375,7 @@ extern bool_t xdr_remote_domain_get_max_memory_args (XDR *, remote_domain_get_m extern bool_t xdr_remote_domain_get_max_memory_ret (XDR *, remote_domain_get_max_memory_ret*); extern bool_t xdr_remote_domain_set_max_memory_args (XDR *, remote_domain_set_max_memory_args*); extern bool_t xdr_remote_domain_set_memory_args (XDR *, remote_domain_set_memory_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_info_args (XDR *, remote_domain_get_info_args*); extern bool_t xdr_remote_domain_get_info_ret (XDR *, remote_domain_get_info_ret*); extern bool_t xdr_remote_domain_save_args (XDR *, remote_domain_save_args*); @@ -2623,6 +2656,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 (); @@ -2678,6 +2713,7 @@ extern bool_t xdr_remote_domain_get_max_memory_args (); extern bool_t xdr_remote_domain_get_max_memory_ret (); extern bool_t xdr_remote_domain_set_max_memory_args (); extern bool_t xdr_remote_domain_set_memory_args (); +extern bool_t xdr_remote_domain_set_memory_parameters_args (); extern bool_t xdr_remote_domain_get_info_args (); extern bool_t xdr_remote_domain_get_info_ret (); extern bool_t xdr_remote_domain_save_args ();

Add support in the lxc driver for various memory controllable parameters 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 9e37906..182cc71 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, "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, "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, "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, "min_gaurantee")) { + 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 */ }; static virStateDriver lxcStateDriver = {
participants (2)
-
Daniel P. Berrange
-
Nikunj A. Dadhania