--- docs/formatdomain.html.in | 49 +++++++++++++++++++++++ docs/schemas/domaincommon.rng | 89 +++++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.c | 92 +++++++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 33 ++++++++++++++++ src/libvirt_private.syms | 1 + src/lxc/lxc_controller.c | 32 +++++++++++++++ src/util/virprocess.c | 4 +- src/util/virprocess.h | 2 + 8 files changed, 300 insertions(+), 2 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index f8d5f89..5aec51c 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -348,6 +348,55 @@ </pre> + <p> + If you want to set an rlimit of the containter init process instead of + inheriting from the host init, set the <code>rlimits</code> element. You + are able to set any of the rlimits that setrlimits is able to set using + any of the following sub-elements: + </p> + + <dl> + <dt><code>as</code></dt> + <dd>Used to set RLIMIT_AS.</dd> + <dt><code>core</code></dt> + <dd>Used to set RLIMIT_CORE.</dd> + <dt><code>cpu</code></dt> + <dd>Used to set RLIMIT_CPU.</dd> + <dt><code>data</code></dt> + <dd>Used to set RLIMIT_DATA.</dd> + <dt><code>fsize</code></dt> + <dd>Used to set RLIMIT_FSIZE.</dd> + <dt><code>locks</code></dt> + <dd>Used to set RLIMIT_LOCKS.</dd> + <dt><code>memlock</code></dt> + <dd>Used to set RLIMIT_MEMLOCK.</dd> + <dt><code>msgqueue</code></dt> + <dd>Used to set RLIMIT_MSGQUEUE.</dd> + <dt><code>nice</code></dt> + <dd>Used to set RLIMIT_NICE.</dd> + <dt><code>nofile</code></dt> + <dd>Used to set RLIMIT_NOFILE.</dd> + <dt><code>nproc</code></dt> + <dd>Used to set RLIMIT_NPROC.</dd> + <dt><code>rss</code></dt> + <dd>Used to set RLIMIT_RSS.</dd> + <dt><code>rtprio</code></dt> + <dd>Used to set RLIMIT_RTPRIO.</dd> + <dt><code>rttime</code></dt> + <dd>Used to set RLIMIT_RTTIME.</dd> + <dt><code>sigpending</code></dt> + <dd>Used to set RLIMIT_SIGPENDING.</dd> + <dt><code>stack</code></dt> + <dd>Used to set RLIMIT_STACK.</dd> + </dl> + + <pre> + <rlimits> + <nofile>10240</nofile> + </rlimits> + </pre> + + <h3><a name="elementsSysinfo">SMBIOS System Information</a></h3> <p> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index d467dce..b98f8d5 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -59,6 +59,9 @@ <ref name="idmap"/> </optional> <optional> + <ref name="rlimits"/> + </optional> + <optional> <ref name="devices"/> </optional> <zeroOrMore> @@ -570,6 +573,92 @@ </interleave> </element> </define> + <define name="rlimits"> + <element name="rlimits"> + <interleave> + <optional> + <element name="cpu"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="fsize"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="data"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="stack"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="core"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="rss"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="nproc"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="nofile"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="memlock"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="as"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="locks"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="sigpending"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="msgqueue"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="nice"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="rtprio"> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name="rttime"> + <ref name='scaledInteger'/> + </element> + </optional> + </interleave> + </element> + </define> <!-- Resources usage defines the amount of memory (maximum and possibly current usage) and number of virtual CPUs used by that domain. diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index d562e1a..399976e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -772,6 +772,24 @@ VIR_ENUM_IMPL(virDomainLoader, "rom", "pflash") +VIR_ENUM_IMPL(virDomainRLimit, VIR_DOMAIN_RLIMIT_LAST, + "cpu", + "fsize", + "data", + "stack", + "core", + "rss", + "nproc", + "nofile", + "memlock", + "as", + "locks", + "sigpending", + "msgqueue", + "nice", + "rtprio", + "rttime") + /* Internal mapping: subset of block job types that can be present in * <mirror> XML (remaining types are not two-phase). */ VIR_ENUM_DECL(virDomainBlockJob) @@ -979,7 +997,40 @@ virDomainBlkioDeviceParseXML(xmlNodePtr root, return -1; } +static virDomainRLimitsPtr +virDomainRLimitParseXML(xmlNodePtr node) +{ + char *c = NULL; + long long val; + virDomainRLimitsPtr def; + + if (VIR_ALLOC(def) < 0) + return NULL; + if (node->type == XML_ELEMENT_NODE) { + c = (char *)xmlNodeGetContent(node); + if (virStrToLong_ll(c, NULL, 10, &val) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("could not parse rlimit value of %s"), + c); + goto error; + } + VIR_FREE(c); + + def->limit = val; + if ((def->resource = virDomainRLimitTypeFromString((const char *)node->name)) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("could not determine resource type of '%s'"), + node->name); + goto error; + } + } + return def; + error: + VIR_FREE(c); + VIR_FREE(def); + return NULL; +} static void virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED) @@ -14423,6 +14474,34 @@ virDomainDefParseXML(xmlDocPtr xml, virHashFree(bootHash); + if ((node = virXPathNode("./rlimits[1]", ctxt)) != NULL && (n = virXMLChildElementCount(node)) > 0) { + xmlNodePtr cur = node->children; + if (n && VIR_ALLOC_N(def->rlimits, n) < 0) + goto error; + + for (i = 0; i < n; i++) { + if (!(def->rlimits[i] = virDomainRLimitParseXML(cur))) { + for (j = 0; j < i; j++) + VIR_FREE(def->rlimits[j]); + VIR_FREE(def->rlimits); + goto error; + } + def->nrlimits++; + for (j = 0; j < i; j++) { + if (def->rlimits[j]->resource == def->rlimits[i]->resource) { + virReportError(VIR_ERR_XML_ERROR, + _("duplicate rlimit resources '%s'"), + virDomainRLimitTypeToString(def->rlimits[j]->resource)); + for (int k = 0; k < i; k++) + VIR_FREE(def->rlimits[k]); + VIR_FREE(def->rlimits); + goto error; + } + } + cur = cur->next; + } + } + return def; error: @@ -20048,6 +20127,19 @@ virDomainDefFormatInternal(virDomainDefPtr def, goto error; } + if (def->nrlimits > 0) { + virBufferAddLit(buf, "<rlimits>\n"); + virBufferAdjustIndent(buf, 2); + for (n = 0; n < def->nrlimits; n++) { + virBufferAsprintf(buf, "<%s>%lld</%s>\n", + virDomainRLimitTypeToString(def->rlimits[n]->resource), + def->rlimits[n]->limit, + virDomainRLimitTypeToString(def->rlimits[n]->resource)); + } + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</rlimits>\n"); + } + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</domain>\n"); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 93f2314..b032202 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1851,6 +1851,27 @@ typedef enum { VIR_DOMAIN_CLOCK_BASIS_LAST } virDomainClockBasis; +typedef enum { + VIR_DOMAIN_RLIMIT_CPU, + VIR_DOMAIN_RLIMIT_FSIZE, + VIR_DOMAIN_RLIMIT_DATA, + VIR_DOMAIN_RLIMIT_STACK, + VIR_DOMAIN_RLIMIT_CORE, + VIR_DOMAIN_RLIMIT_RSS, + VIR_DOMAIN_RLIMIT_NPROC, + VIR_DOMAIN_RLIMIT_NOFILE, + VIR_DOMAIN_RLIMIT_MEMLOCK, + VIR_DOMAIN_RLIMIT_AS, + VIR_DOMAIN_RLIMIT_LOCKS, + VIR_DOMAIN_RLIMIT_SIGPENDING, + VIR_DOMAIN_RLIMIT_MSGQUEUE, + VIR_DOMAIN_RLIMIT_NICE, + VIR_DOMAIN_RLIMIT_RTPRIO, + VIR_DOMAIN_RLIMIT_RTTIME, + + VIR_DOMAIN_RLIMIT_LAST +} virDomainRLimit; + typedef struct _virDomainClockDef virDomainClockDef; typedef virDomainClockDef *virDomainClockDefPtr; struct _virDomainClockDef { @@ -2039,6 +2060,14 @@ struct _virDomainPowerManagement { int s4; }; +typedef struct _virDomainRLimits virDomainRLimits; +typedef virDomainRLimits *virDomainRLimitsPtr; + +struct _virDomainRLimits { + int resource; + long long limit; +}; + /* * Guest VM main configuration * @@ -2156,6 +2185,9 @@ struct _virDomainDef { size_t nshmems; virDomainShmemDefPtr *shmems; + size_t nrlimits; + virDomainRLimitsPtr *rlimits; + /* Only 1 */ virDomainWatchdogDefPtr watchdog; virDomainMemballoonDefPtr memballoon; @@ -2844,6 +2876,7 @@ VIR_ENUM_DECL(virDomainRNGModel) VIR_ENUM_DECL(virDomainRNGBackend) VIR_ENUM_DECL(virDomainTPMModel) VIR_ENUM_DECL(virDomainTPMBackend) +VIR_ENUM_DECL(virDomainRLimit) /* from libvirt.h */ VIR_ENUM_DECL(virDomainState) VIR_ENUM_DECL(virDomainNostateReason) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index bd7870f..7b71ff1 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1896,6 +1896,7 @@ virProcessGetNamespaces; virProcessGetStartTime; virProcessKill; virProcessKillPainfully; +virProcessPrLimit; virProcessRunInMountNamespace; virProcessSetAffinity; virProcessSetMaxFiles; diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 8a7c7e8..5c63a1b 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -798,6 +798,35 @@ static int virLXCControllerSetupCgroupLimits(virLXCControllerPtr ctrl) return ret; } +static int virLXCControllerSetupRLimits(virLXCControllerPtr ctrl) +{ + int i, ret = -1; + struct rlimit rlim; + + VIR_DEBUG("Setting up rlimits"); + + VIR_DEBUG("nrlimits = %d", (int)ctrl->def->nrlimits); + VIR_DEBUG("setting limits on process %d", ctrl->initpid); + if (ctrl->def->nrlimits > 0) { + for (i = 0; i < ctrl->def->nrlimits; i++) { + rlim.rlim_max = rlim.rlim_cur = ctrl->def->rlimits[i]->limit; + VIR_DEBUG("Setting rlimit %s(%d) on pid %d to %lld", + virDomainRLimitTypeToString(ctrl->def->rlimits[i]->resource), + ctrl->def->rlimits[i]->resource, + ctrl->initpid, + ctrl->def->rlimits[i]->limit); + if (virProcessPrLimit(ctrl->initpid, ctrl->def->rlimits[i]->resource, &rlim) < 0) { + virReportSystemError(errno, "%s", + _("Unable to set rlimit")); + goto cleanup; + } + } + } + ret = 0; + cleanup: + return ret; +} + static void virLXCControllerClientCloseHook(virNetServerClientPtr client) { @@ -2318,6 +2347,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl) if (virLXCControllerSetupCgroupLimits(ctrl) < 0) goto cleanup; + if (virLXCControllerSetupRLimits(ctrl) < 0) + goto cleanup; + if (virLXCControllerSetupUserns(ctrl) < 0) goto cleanup; diff --git a/src/util/virprocess.c b/src/util/virprocess.c index d0a1500..d83ae28 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -676,13 +676,13 @@ int virProcessSetNamespaces(size_t nfdlist, } #if HAVE_PRLIMIT -static int +int virProcessPrLimit(pid_t pid, int resource, struct rlimit *rlim) { return prlimit(pid, resource, rlim, NULL); } #elif HAVE_SETRLIMIT -static int +int virProcessPrLimit(pid_t pid ATTRIBUTE_UNUSED, int resource ATTRIBUTE_UNUSED, struct rlimit *rlim ATTRIBUTE_UNUSED) diff --git a/src/util/virprocess.h b/src/util/virprocess.h index bcaede5..c40b41a 100644 --- a/src/util/virprocess.h +++ b/src/util/virprocess.h @@ -22,6 +22,7 @@ #ifndef __VIR_PROCESS_H__ # define __VIR_PROCESS_H__ +# include <sys/resource.h> # include <sys/types.h> # include "internal.h" @@ -73,4 +74,5 @@ typedef int (*virProcessNamespaceCallback)(pid_t pid, void *opaque); int virProcessRunInMountNamespace(pid_t pid, virProcessNamespaceCallback cb, void *opaque); +int virProcessPrLimit(pid_t pid, int resource, struct rlimit *rlim); #endif /* __VIR_PROCESS_H__ */ -- 1.9.3 (Apple Git-50) -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list