|
|
a19bc6 |
From c56c1f6c2b683d6f20a7e8caeecec6c3cb76798f Mon Sep 17 00:00:00 2001
|
|
|
a19bc6 |
From: Lukas Nykryn <lnykryn@redhat.com>
|
|
|
a19bc6 |
Date: Tue, 3 Jan 2017 14:21:25 +0100
|
|
|
a19bc6 |
Subject: [PATCH] core: make parsing of RLIMIT_NICE aware of actual nice levels
|
|
|
a19bc6 |
|
|
|
a19bc6 |
RHEL-only
|
|
|
a19bc6 |
(most of code taken from 29857001854a02c292f1f3b324e7a66831e859c8)
|
|
|
a19bc6 |
|
|
|
a19bc6 |
Resolves: #1409588
|
|
|
a19bc6 |
---
|
|
|
a19bc6 |
man/systemd.exec.xml | 7 +++-
|
|
|
a19bc6 |
src/core/load-fragment-gperf.gperf.m4 | 2 +-
|
|
|
a19bc6 |
src/core/load-fragment.c | 72 +++++++++++++++++++++++++++++++++++
|
|
|
a19bc6 |
src/core/load-fragment.h | 1 +
|
|
|
a19bc6 |
src/core/main.c | 2 +-
|
|
|
a19bc6 |
5 files changed, 81 insertions(+), 3 deletions(-)
|
|
|
a19bc6 |
|
|
|
a19bc6 |
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
|
|
|
a19bc6 |
index 0cd469c..c5199d3 100644
|
|
|
a19bc6 |
--- a/man/systemd.exec.xml
|
|
|
a19bc6 |
+++ b/man/systemd.exec.xml
|
|
|
a19bc6 |
@@ -575,7 +575,12 @@
|
|
|
a19bc6 |
granularity of the limits might influence their
|
|
|
a19bc6 |
enforcement. For example, time limits specified for
|
|
|
a19bc6 |
<varname>LimitCPU=</varname> will be rounded up implicitly to
|
|
|
a19bc6 |
- multiples of 1s.</para>
|
|
|
a19bc6 |
+ multiples of 1s. For <varname>LimitNICE=</varname> the value
|
|
|
a19bc6 |
+ may be specified in two syntaxes: if prefixed with <literal>+</literal>
|
|
|
a19bc6 |
+ or <literal>-</literal>, the value is understood as regular Linux
|
|
|
a19bc6 |
+ nice value in the range -20..19. If not prefixed like this the value
|
|
|
a19bc6 |
+ is understood as raw resource limit parameter in the range 0..40 (with 0 being
|
|
|
a19bc6 |
+ equivalent to 1).</para>
|
|
|
a19bc6 |
|
|
|
a19bc6 |
<para>Note that most process resource limits configured with
|
|
|
a19bc6 |
these options are per-process, and processes may fork in order
|
|
|
a19bc6 |
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
|
|
|
a19bc6 |
index 45d1ead..f3a6e13 100644
|
|
|
a19bc6 |
--- a/src/core/load-fragment-gperf.gperf.m4
|
|
|
a19bc6 |
+++ b/src/core/load-fragment-gperf.gperf.m4
|
|
|
a19bc6 |
@@ -71,7 +71,7 @@ $1.LimitMEMLOCK, config_parse_bytes_limit, RLIMIT_MEML
|
|
|
a19bc6 |
$1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit)
|
|
|
a19bc6 |
$1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit)
|
|
|
a19bc6 |
$1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
|
|
|
a19bc6 |
-$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit)
|
|
|
a19bc6 |
+$1.LimitNICE, config_parse_nice_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit)
|
|
|
a19bc6 |
$1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit)
|
|
|
a19bc6 |
$1.LimitRTTIME, config_parse_usec_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
|
|
|
a19bc6 |
$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs)
|
|
|
a19bc6 |
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
|
|
|
a19bc6 |
index 7056419..3a3c456 100644
|
|
|
a19bc6 |
--- a/src/core/load-fragment.c
|
|
|
a19bc6 |
+++ b/src/core/load-fragment.c
|
|
|
a19bc6 |
@@ -1154,6 +1154,56 @@ static int rlim_parse_usec(const char *val, rlim_t *res) {
|
|
|
a19bc6 |
return r;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
+static int rlim_parse_nice(const char *val, rlim_t *ret) {
|
|
|
a19bc6 |
+ uint64_t rl;
|
|
|
a19bc6 |
+ int r;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ /* So, Linux is weird. The range for RLIMIT_NICE is 40..1, mapping to the nice levels -20..19. However, the
|
|
|
a19bc6 |
+ * RLIMIT_NICE limit defaults to 0 by the kernel, i.e. a value that maps to nice level 20, which of course is
|
|
|
a19bc6 |
+ * bogus and does not exist. In order to permit parsing the RLIMIT_NICE of 0 here we hence implement a slight
|
|
|
a19bc6 |
+ * asymmetry: when parsing as positive nice level we permit 0..19. When parsing as negative nice level, we
|
|
|
a19bc6 |
+ * permit -20..0. But when parsing as raw resource limit value then we also allow the special value 0.
|
|
|
a19bc6 |
+ *
|
|
|
a19bc6 |
+ * Yeah, Linux is quality engineering sometimes... */
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (val[0] == '+') {
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ /* Prefixed with "+": Parse as positive user-friendly nice value */
|
|
|
a19bc6 |
+ r = safe_atou64(val + 1, &rl);
|
|
|
a19bc6 |
+ if (r < 0)
|
|
|
a19bc6 |
+ return r;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (rl >= PRIO_MAX)
|
|
|
a19bc6 |
+ return -ERANGE;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ rl = 20 - rl;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ } else if (val[0] == '-') {
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ /* Prefixed with "-": Parse as negative user-friendly nice value */
|
|
|
a19bc6 |
+ r = safe_atou64(val + 1, &rl);
|
|
|
a19bc6 |
+ if (r < 0)
|
|
|
a19bc6 |
+ return r;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (rl > (uint64_t) (-PRIO_MIN))
|
|
|
a19bc6 |
+ return -ERANGE;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ rl = 20 + rl;
|
|
|
a19bc6 |
+ } else {
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ /* Not prefixed: parse as raw resource limit value */
|
|
|
a19bc6 |
+ r = safe_atou64(val, &rl);
|
|
|
a19bc6 |
+ if (r < 0)
|
|
|
a19bc6 |
+ return r;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (rl > (uint64_t) (20 - PRIO_MIN))
|
|
|
a19bc6 |
+ return -ERANGE;
|
|
|
a19bc6 |
+ }
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ *ret = (rlim_t) rl;
|
|
|
a19bc6 |
+ return 0;
|
|
|
a19bc6 |
+}
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
static int parse_rlimit_range(
|
|
|
a19bc6 |
const char *unit,
|
|
|
a19bc6 |
const char *filename,
|
|
|
a19bc6 |
@@ -1286,6 +1336,28 @@ int config_parse_usec_limit(
|
|
|
a19bc6 |
return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_usec);
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
+int config_parse_nice_limit(
|
|
|
a19bc6 |
+ const char *unit,
|
|
|
a19bc6 |
+ const char *filename,
|
|
|
a19bc6 |
+ unsigned line,
|
|
|
a19bc6 |
+ const char *section,
|
|
|
a19bc6 |
+ unsigned section_line,
|
|
|
a19bc6 |
+ const char *lvalue,
|
|
|
a19bc6 |
+ int ltype,
|
|
|
a19bc6 |
+ const char *rvalue,
|
|
|
a19bc6 |
+ void *data,
|
|
|
a19bc6 |
+ void *userdata) {
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ struct rlimit **rl = data;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ assert(filename);
|
|
|
a19bc6 |
+ assert(lvalue);
|
|
|
a19bc6 |
+ assert(rvalue);
|
|
|
a19bc6 |
+ assert(data);
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ rl += ltype;
|
|
|
a19bc6 |
+ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_nice);
|
|
|
a19bc6 |
+}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
#ifdef HAVE_SYSV_COMPAT
|
|
|
a19bc6 |
int config_parse_sysv_priority(const char *unit,
|
|
|
a19bc6 |
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
|
|
|
a19bc6 |
index 6114796..7c69e53 100644
|
|
|
a19bc6 |
--- a/src/core/load-fragment.h
|
|
|
a19bc6 |
+++ b/src/core/load-fragment.h
|
|
|
a19bc6 |
@@ -59,6 +59,7 @@ int config_parse_limit(const char *unit, const char *filename, unsigned line, co
|
|
|
a19bc6 |
int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
int config_parse_usec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
+int config_parse_nice_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
|
|
a19bc6 |
diff --git a/src/core/main.c b/src/core/main.c
|
|
|
a19bc6 |
index 6f83676..820cbc3 100644
|
|
|
a19bc6 |
--- a/src/core/main.c
|
|
|
a19bc6 |
+++ b/src/core/main.c
|
|
|
a19bc6 |
@@ -669,7 +669,7 @@ static int parse_config_file(void) {
|
|
|
a19bc6 |
{ "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS] },
|
|
|
a19bc6 |
{ "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] },
|
|
|
a19bc6 |
{ "Manager", "DefaultLimitMSGQUEUE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] },
|
|
|
a19bc6 |
- { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] },
|
|
|
a19bc6 |
+ { "Manager", "DefaultLimitNICE", config_parse_nice_limit, 0, &arg_default_rlimit[RLIMIT_NICE] },
|
|
|
a19bc6 |
{ "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] },
|
|
|
a19bc6 |
{ "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] },
|
|
|
a19bc6 |
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
|