1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-02-03 13:47:04 +03:00

core: make parsing of RLIMIT_NICE aware of actual nice levels

This commit is contained in:
Lennart Poettering 2016-04-28 21:00:28 +02:00
parent 3e7a1f50e4
commit 2985700185
3 changed files with 80 additions and 22 deletions

View File

@ -629,27 +629,23 @@
<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

View 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,
};

View 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;
}