]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: make parsing of RLIMIT_NICE aware of actual nice levels
authorLennart Poettering <lennart@poettering.net>
Thu, 28 Apr 2016 19:00:28 +0000 (21:00 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 29 Apr 2016 14:27:49 +0000 (16:27 +0200)
man/systemd.exec.xml
src/basic/rlimit-util.c
src/test/test-rlimit-util.c

index 2d0fb63f1da1657623388874a474eb4f1183459c..2a937604288c9ac88efd8ab34e0c7b20dc1d485d 100644 (file)
         <term><varname>LimitNICE=</varname></term>
         <term><varname>LimitRTPRIO=</varname></term>
         <term><varname>LimitRTTIME=</varname></term>
-        <listitem><para>These settings set both soft and hard limits
-        of various resources for executed processes. See
-        <citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry>
-        for details. The resource limit is possible to specify in two formats,
-        <option>value</option> to set soft and hard limits to the same value,
-        or <option>soft:hard</option> to set both limits individually (e.g. LimitAS=4G:16G).
-        Use the string <varname>infinity</varname> to
-        configure no limit on a specific resource. The multiplicative
-        suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E
-        may be used for resource limits measured in bytes
-        (e.g. LimitAS=16G). For the limits referring to time values,
-        the usual time units ms, s, min, h and so on may be used (see
-        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>
-        for details). Note that if no time unit is specified for
-        <varname>LimitCPU=</varname> the default unit of seconds is
-        implied, while for <varname>LimitRTTIME=</varname> the default
-        unit of microseconds is implied. Also, note that the effective
-        granularity of the limits might influence their
-        enforcement. For example, time limits specified for
-        <varname>LimitCPU=</varname> will be rounded up implicitly to
-        multiples of 1s.</para>
+        <listitem><para>Set soft and hard limits on various resources for executed processes. See
+        <citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details on
+        the resource limit concept. Resource limits may be specified in two formats: either as single value to set a
+        specific soft and hard limit to the same value, or as colon-separated pair <option>soft:hard</option> to set
+        both limits individually (e.g. <literal>LimitAS=4G:16G</literal>).  Use the string <varname>infinity</varname>
+        to configure no limit on a specific resource. The multiplicative suffixes K, M, G, T, P and E (to the base
+        1024) may be used for resource limits measured in bytes (e.g. LimitAS=16G). For the limits referring to time
+        values, the usual time units ms, s, min, h and so on may be used (see
+        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
+        details). Note that if no time unit is specified for <varname>LimitCPU=</varname> the default unit of seconds
+        is implied, while for <varname>LimitRTTIME=</varname> the default unit of microseconds is implied. Also, note
+        that the effective granularity of the limits might influence their enforcement. For example, time limits
+        specified for <varname>LimitCPU=</varname> will be rounded up implicitly to multiples of 1s. For
+        <varname>LimitNICE=</varname> the value may be specified in two syntaxes: if prefixed with <literal>+</literal>
+        or <literal>-</literal>, the value is understood as regular Linux nice value in the range -20..19. If not
+        prefixed like this the value is understood as raw resource limit parameter in the range 0..40 (with 0 being
+        equivalent to 1).</para>
 
         <para>Note that most process resource limits configured with
         these options are per-process, and processes may fork in order
index 7540b43215a567e22514764e47d58d7430c0cbed..ee063720edb15abc9c9694ea247f3b0c8515e1a8 100644 (file)
@@ -153,6 +153,56 @@ static int rlimit_parse_usec(const char *val, rlim_t *ret) {
         return 0;
 }
 
+static int rlimit_parse_nice(const char *val, rlim_t *ret) {
+        uint64_t rl;
+        int r;
+
+        /* So, Linux is weird. The range for RLIMIT_NICE is 40..1, mapping to the nice levels -20..19. However, the
+         * RLIMIT_NICE limit defaults to 0 by the kernel, i.e. a value that maps to nice level 20, which of course is
+         * bogus and does not exist. In order to permit parsing the RLIMIT_NICE of 0 here we hence implement a slight
+         * asymmetry: when parsing as positive nice level we permit 0..19. When parsing as negative nice level, we
+         * permit -20..0. But when parsing as raw resource limit value then we also allow the special value 0.
+         *
+         * Yeah, Linux is quality engineering sometimes... */
+
+        if (val[0] == '+') {
+
+                /* Prefixed with "+": Parse as positive user-friendly nice value */
+                r = safe_atou64(val + 1, &rl);
+                if (r < 0)
+                        return r;
+
+                if (rl >= PRIO_MAX)
+                        return -ERANGE;
+
+                rl = 20 - rl;
+
+        } else if (val[0] == '-') {
+
+                /* Prefixed with "-": Parse as negative user-friendly nice value */
+                r = safe_atou64(val + 1, &rl);
+                if (r < 0)
+                        return r;
+
+                if (rl > (uint64_t) (-PRIO_MIN))
+                        return -ERANGE;
+
+                rl = 20 + rl;
+        } else {
+
+                /* Not prefixed: parse as raw resource limit value */
+                r = safe_atou64(val, &rl);
+                if (r < 0)
+                        return r;
+
+                if (rl > (uint64_t) (20 - PRIO_MIN))
+                        return -ERANGE;
+        }
+
+        *ret = (rlim_t) rl;
+        return 0;
+}
+
 static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret) = {
         [RLIMIT_CPU] = rlimit_parse_sec,
         [RLIMIT_FSIZE] = rlimit_parse_size,
@@ -167,7 +217,7 @@ static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret
         [RLIMIT_LOCKS] = rlimit_parse_u64,
         [RLIMIT_SIGPENDING] = rlimit_parse_u64,
         [RLIMIT_MSGQUEUE] = rlimit_parse_size,
-        [RLIMIT_NICE] = rlimit_parse_u64,
+        [RLIMIT_NICE] = rlimit_parse_nice,
         [RLIMIT_RTPRIO] = rlimit_parse_u64,
         [RLIMIT_RTTIME] = rlimit_parse_usec,
 };
index d9ac9368cdb284a8c6fedacad2fbc78afedc7870..62afd2de5edd6009b0eade08c3bce333cf6a110a 100644 (file)
@@ -99,6 +99,18 @@ int main(int argc, char *argv[]) {
         test_rlimit_parse_format(RLIMIT_NOFILE, "", 0, 0, -EINVAL, NULL);
         test_rlimit_parse_format(RLIMIT_NOFILE, "5:4", 0, 0, -EILSEQ, NULL);
         test_rlimit_parse_format(RLIMIT_NOFILE, "5:4:3", 0, 0, -EINVAL, NULL);
+        test_rlimit_parse_format(RLIMIT_NICE, "20", 20, 20, 0, "20");
+        test_rlimit_parse_format(RLIMIT_NICE, "40", 40, 40, 0, "40");
+        test_rlimit_parse_format(RLIMIT_NICE, "41", 41, 41, -ERANGE, "41");
+        test_rlimit_parse_format(RLIMIT_NICE, "0", 0, 0, 0, "0");
+        test_rlimit_parse_format(RLIMIT_NICE, "-7", 27, 27, 0, "27");
+        test_rlimit_parse_format(RLIMIT_NICE, "-20", 40, 40, 0, "40");
+        test_rlimit_parse_format(RLIMIT_NICE, "-21", 41, 41, -ERANGE, "41");
+        test_rlimit_parse_format(RLIMIT_NICE, "-0", 20, 20, 0, "20");
+        test_rlimit_parse_format(RLIMIT_NICE, "+7", 13, 13, 0, "13");
+        test_rlimit_parse_format(RLIMIT_NICE, "+19", 1, 1, 0, "1");
+        test_rlimit_parse_format(RLIMIT_NICE, "+20", 0, 0, -ERANGE, "0");
+        test_rlimit_parse_format(RLIMIT_NICE, "+0", 20, 20, 0, "20");
 
         return 0;
 }