[libvirt] [PATCH v2 00/11] Implement memory control api

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 * 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 (11): Adding structure and defines for virDomainSetMemoryParameter Adding virDomainSetMemoryParameters API Adds xml entries for memory tunables XML parsing for memory tunables Implement cgroup memory controller tunables Implement driver interface domainSetMemoryParamters for QEmu 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 | 60 +++++++++++++++ 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, 959 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. 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 | 60 +++++++++++++++++++++++++++++++++++++++ python/generator.py | 1 + python/libvirt-override-api.xml | 6 ++++ python/libvirt-override.c | 7 +++++ 4 files changed, 74 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index b45f7ec..8f5d75d 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -674,6 +674,66 @@ 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); + /* * Dynamic control of domains */ 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) {

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 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 | 6 +++++ src/esx/esx_driver.c | 1 + src/libvirt.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 1 + src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/xen/xen_driver.c | 1 + 11 files changed, 64 insertions(+), 0 deletions(-) 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/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/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 diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 326fee6..9a4843d 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 1ad93d9..edef080 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 25695df..d6dd1da 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12710,6 +12710,7 @@ static virDriver qemuDriver = { qemuDomainRevertToSnapshot, /* domainRevertToSnapshot */ qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ + NULL, /* 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 9d22339..3560a19 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 9101928..50c8152 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 */ }; /**

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>

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 9a4843d..9e37906 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 edef080..beee006 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 d6dd1da..17d4fbe 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 3560a19..382d5a8 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 50c8152..9003e9a 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;

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,

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 17d4fbe..adf5f16 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 */ };

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

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 adf5f16..714ff21 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;

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) v2: + Use #define string constants for "hard_limit", etc 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..585e278 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")}, + {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; + 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, 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 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, 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; + } + + 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},

From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> 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 ();

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 9e37906..6ffcd39 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 */ }; static virStateDriver lxcStateDriver = {
participants (1)
-
Nikunj A. Dadhania