mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-11 05:17:44 +03:00
Merge pull request #1994 from karelzak/rlimits
core: support <soft:hard> ranges for RLIMIT options
This commit is contained in:
commit
f7b5b034e8
@ -354,13 +354,26 @@
|
||||
<listitem><para>These settings control various default
|
||||
resource limits for units. See
|
||||
<citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
for details. 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. DefaultLimitAS=16G). These
|
||||
settings may be overridden in individual units using the corresponding
|
||||
LimitXXX= directives. Note that these resource limits are only
|
||||
defaults for units, they are not applied to PID 1
|
||||
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. DefaultLimitAS=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. DefaultLimitAS=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>DefaultLimitCPU=</varname> the default unit of seconds is
|
||||
implied, while for <varname>DefaultLimitRTTIME=</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>DefaultLimitCPU=</varname> will be rounded up implicitly to
|
||||
multiples of 1s. These settings may be overridden in individual units
|
||||
using the corresponding LimitXXX= directives. Note that these resource
|
||||
limits are only defaults for units, they are not applied to PID 1
|
||||
itself.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
@ -630,7 +630,10 @@
|
||||
<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. Use the string <varname>infinity</varname> to
|
||||
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
|
||||
|
@ -1089,6 +1089,119 @@ int config_parse_bounding_set(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rlim_parse_u64(const char *val, rlim_t *res) {
|
||||
int r = 0;
|
||||
|
||||
if (streq(val, "infinity"))
|
||||
*res = RLIM_INFINITY;
|
||||
else {
|
||||
uint64_t u;
|
||||
|
||||
/* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
|
||||
assert_cc(sizeof(rlim_t) == sizeof(uint64_t));
|
||||
|
||||
r = safe_atou64(val, &u);
|
||||
if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
|
||||
r = -ERANGE;
|
||||
if (r == 0)
|
||||
*res = (rlim_t) u;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int rlim_parse_size(const char *val, rlim_t *res) {
|
||||
int r = 0;
|
||||
|
||||
if (streq(val, "infinity"))
|
||||
*res = RLIM_INFINITY;
|
||||
else {
|
||||
uint64_t u;
|
||||
|
||||
r = parse_size(val, 1024, &u);
|
||||
if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
|
||||
r = -ERANGE;
|
||||
if (r == 0)
|
||||
*res = (rlim_t) u;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int rlim_parse_sec(const char *val, rlim_t *res) {
|
||||
int r = 0;
|
||||
|
||||
if (streq(val, "infinity"))
|
||||
*res = RLIM_INFINITY;
|
||||
else {
|
||||
usec_t t;
|
||||
|
||||
r = parse_sec(val, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (t == USEC_INFINITY)
|
||||
*res = RLIM_INFINITY;
|
||||
else
|
||||
*res = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC));
|
||||
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int rlim_parse_usec(const char *val, rlim_t *res) {
|
||||
int r = 0;
|
||||
|
||||
if (streq(val, "infinity"))
|
||||
*res = RLIM_INFINITY;
|
||||
else {
|
||||
usec_t t;
|
||||
|
||||
r = parse_time(val, &t, 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (t == USEC_INFINITY)
|
||||
*res = RLIM_INFINITY;
|
||||
else
|
||||
*res = (rlim_t) t;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int parse_rlimit_range(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *value,
|
||||
struct rlimit **rl,
|
||||
int (*rlim_parser)(const char *, rlim_t *)) {
|
||||
|
||||
rlim_t soft, hard;
|
||||
_cleanup_free_ char *sword = NULL, *hword = NULL;
|
||||
int nwords, r;
|
||||
|
||||
assert(value);
|
||||
|
||||
/* <value> or <soft:hard> */
|
||||
nwords = extract_many_words(&value, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &sword, &hword, NULL);
|
||||
r = nwords < 0 ? nwords : nwords == 0 ? -EINVAL : 0;
|
||||
|
||||
if (r == 0)
|
||||
r = rlim_parser(sword, &soft);
|
||||
if (r == 0 && nwords == 2)
|
||||
r = rlim_parser(hword, &hard);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!*rl) {
|
||||
*rl = new(struct rlimit, 1);
|
||||
if (!*rl)
|
||||
return log_oom();
|
||||
}
|
||||
(*rl)->rlim_cur = soft;
|
||||
(*rl)->rlim_max = nwords == 2 ? hard : soft;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_limit(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
@ -1102,8 +1215,6 @@ int config_parse_limit(
|
||||
void *userdata) {
|
||||
|
||||
struct rlimit **rl = data;
|
||||
rlim_t v;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
@ -1111,34 +1222,7 @@ int config_parse_limit(
|
||||
assert(data);
|
||||
|
||||
rl += ltype;
|
||||
|
||||
if (streq(rvalue, "infinity"))
|
||||
v = RLIM_INFINITY;
|
||||
else {
|
||||
uint64_t u;
|
||||
|
||||
/* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
|
||||
assert_cc(sizeof(rlim_t) == sizeof(uint64_t));
|
||||
|
||||
r = safe_atou64(rvalue, &u);
|
||||
if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
|
||||
r = -ERANGE;
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
v = (rlim_t) u;
|
||||
}
|
||||
|
||||
if (!*rl) {
|
||||
*rl = new(struct rlimit, 1);
|
||||
if (!*rl)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
(*rl)->rlim_cur = (*rl)->rlim_max = v;
|
||||
return 0;
|
||||
return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_u64);
|
||||
}
|
||||
|
||||
int config_parse_bytes_limit(
|
||||
@ -1154,8 +1238,6 @@ int config_parse_bytes_limit(
|
||||
void *userdata) {
|
||||
|
||||
struct rlimit **rl = data;
|
||||
rlim_t bytes;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
@ -1163,31 +1245,7 @@ int config_parse_bytes_limit(
|
||||
assert(data);
|
||||
|
||||
rl += ltype;
|
||||
|
||||
if (streq(rvalue, "infinity"))
|
||||
bytes = RLIM_INFINITY;
|
||||
else {
|
||||
uint64_t u;
|
||||
|
||||
r = parse_size(rvalue, 1024, &u);
|
||||
if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
|
||||
r = -ERANGE;
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytes = (rlim_t) u;
|
||||
}
|
||||
|
||||
if (!*rl) {
|
||||
*rl = new(struct rlimit, 1);
|
||||
if (!*rl)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
(*rl)->rlim_cur = (*rl)->rlim_max = bytes;
|
||||
return 0;
|
||||
return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_size);
|
||||
}
|
||||
|
||||
int config_parse_sec_limit(
|
||||
@ -1203,8 +1261,6 @@ int config_parse_sec_limit(
|
||||
void *userdata) {
|
||||
|
||||
struct rlimit **rl = data;
|
||||
rlim_t seconds;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
@ -1212,35 +1268,9 @@ int config_parse_sec_limit(
|
||||
assert(data);
|
||||
|
||||
rl += ltype;
|
||||
|
||||
if (streq(rvalue, "infinity"))
|
||||
seconds = RLIM_INFINITY;
|
||||
else {
|
||||
usec_t t;
|
||||
|
||||
r = parse_sec(rvalue, &t);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (t == USEC_INFINITY)
|
||||
seconds = RLIM_INFINITY;
|
||||
else
|
||||
seconds = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC));
|
||||
}
|
||||
|
||||
if (!*rl) {
|
||||
*rl = new(struct rlimit, 1);
|
||||
if (!*rl)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
(*rl)->rlim_cur = (*rl)->rlim_max = seconds;
|
||||
return 0;
|
||||
return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_sec);
|
||||
}
|
||||
|
||||
|
||||
int config_parse_usec_limit(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
@ -1254,8 +1284,6 @@ int config_parse_usec_limit(
|
||||
void *userdata) {
|
||||
|
||||
struct rlimit **rl = data;
|
||||
rlim_t useconds;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
@ -1263,34 +1291,11 @@ int config_parse_usec_limit(
|
||||
assert(data);
|
||||
|
||||
rl += ltype;
|
||||
|
||||
if (streq(rvalue, "infinity"))
|
||||
useconds = RLIM_INFINITY;
|
||||
else {
|
||||
usec_t t;
|
||||
|
||||
r = parse_time(rvalue, &t, 1);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (t == USEC_INFINITY)
|
||||
useconds = RLIM_INFINITY;
|
||||
else
|
||||
useconds = (rlim_t) t;
|
||||
}
|
||||
|
||||
if (!*rl) {
|
||||
*rl = new(struct rlimit, 1);
|
||||
if (!*rl)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
(*rl)->rlim_cur = (*rl)->rlim_max = useconds;
|
||||
return 0;
|
||||
return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_usec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_SYSV_COMPAT
|
||||
int config_parse_sysv_priority(const char *unit,
|
||||
const char *filename,
|
||||
|
@ -680,11 +680,21 @@ static void test_config_parse_rlimit(void) {
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
|
||||
|
||||
rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]);
|
||||
|
||||
assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
|
||||
@ -697,6 +707,11 @@ static void test_config_parse_rlimit(void) {
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == 57);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
|
||||
|
||||
assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_CPU]);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == 40);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_max == 60);
|
||||
|
||||
assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_CPU]);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY);
|
||||
@ -714,16 +729,31 @@ static void test_config_parse_rlimit(void) {
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC);
|
||||
|
Loading…
Reference in New Issue
Block a user