[libvirt] [PATCH] Add ability to set rlimits at container boot

Ryan Cleere rcleere at gmail.com
Fri Jan 30 14:53:20 UTC 2015


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




More information about the libvir-list mailing list