diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
index 7f2b755eab..22bb3b705b 100644
--- a/man/systemd-nspawn.xml
+++ b/man/systemd-nspawn.xml
@@ -786,6 +786,16 @@
--rlimit=RLIMIT_NOFILE=8192:16384.
+
+
+
+ Changes the OOM ("Out Of Memory") score adjustment value for the container payload. This controls
+ /proc/self/oom_score_adj which influences the preference with which this container is
+ terminated when memory becomes scarce. For details see proc5. Takes an
+ integer in the range -1000…1000.
+
+
diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml
index 436f8cd0e9..748a633a33 100644
--- a/man/systemd.nspawn.xml
+++ b/man/systemd.nspawn.xml
@@ -313,6 +313,15 @@
details.
+
+ OOMScoreAdjust=
+
+ Configures the OOM score adjustment value. This is equivalent to the
+ command line switch, and takes the same argument. See
+ systemd-nspawn1 for
+ details.
+
+
Hostname=
diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf
index a3759674ef..de00dbc243 100644
--- a/src/nspawn/nspawn-gperf.gperf
+++ b/src/nspawn/nspawn-gperf.gperf
@@ -51,6 +51,7 @@ Exec.LimitRTPRIO, config_parse_rlimit, RLIMIT_RTPRIO, of
Exec.LimitRTTIME, config_parse_rlimit, RLIMIT_RTTIME, offsetof(Settings, rlimit)
Exec.Hostname, config_parse_hostname, 0, offsetof(Settings, hostname)
Exec.NoNewPrivileges, config_parse_tristate, 0, offsetof(Settings, no_new_privileges)
+Exec.OOMScoreAdjust, config_parse_oom_score_adjust, 0, 0
Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
Files.Bind, config_parse_bind, 0, 0
diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c
index 11a2f41b96..c91ac73e2e 100644
--- a/src/nspawn/nspawn-settings.c
+++ b/src/nspawn/nspawn-settings.c
@@ -634,3 +634,42 @@ int config_parse_hostname(
return 0;
}
+
+int config_parse_oom_score_adjust(
+ 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) {
+
+ Settings *settings = data;
+ int oa, r;
+
+ assert(rvalue);
+ assert(settings);
+
+ if (isempty(rvalue)) {
+ settings->oom_score_adjust_set = false;
+ return 0;
+ }
+
+ r = parse_oom_score_adjust(rvalue, &oa);
+ if (r == -ERANGE) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ settings->oom_score_adjust = oa;
+ settings->oom_score_adjust_set = true;
+
+ return 0;
+}
diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h
index 130331ee18..7cf5be625b 100644
--- a/src/nspawn/nspawn-settings.h
+++ b/src/nspawn/nspawn-settings.h
@@ -51,9 +51,10 @@ typedef enum SettingsMask {
SETTING_SYSCALL_FILTER = UINT64_C(1) << 16,
SETTING_HOSTNAME = UINT64_C(1) << 17,
SETTING_NO_NEW_PRIVILEGES = UINT64_C(1) << 18,
- SETTING_RLIMIT_FIRST = UINT64_C(1) << 19, /* we define one bit per resource limit here */
- SETTING_RLIMIT_LAST = UINT64_C(1) << (19 + _RLIMIT_MAX - 1),
- _SETTINGS_MASK_ALL = (UINT64_C(1) << (19 + _RLIMIT_MAX)) - 1
+ SETTING_OOM_SCORE_ADJUST = UINT64_C(1) << 19,
+ SETTING_RLIMIT_FIRST = UINT64_C(1) << 20, /* we define one bit per resource limit here */
+ SETTING_RLIMIT_LAST = UINT64_C(1) << (20 + _RLIMIT_MAX - 1),
+ _SETTINGS_MASK_ALL = (UINT64_C(1) << (20 + _RLIMIT_MAX)) - 1
} SettingsMask;
typedef struct Settings {
@@ -78,6 +79,8 @@ typedef struct Settings {
struct rlimit *rlimit[_RLIMIT_MAX];
char *hostname;
int no_new_privileges;
+ int oom_score_adjust;
+ bool oom_score_adjust_set;
/* [Image] */
int read_only;
@@ -123,3 +126,4 @@ int config_parse_pid2(const char *unit, const char *filename, unsigned line, con
int config_parse_private_users(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);
int config_parse_syscall_filter(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);
int config_parse_hostname(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);
+int config_parse_oom_score_adjust(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);
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index a7b35abd6b..21d63987ec 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -204,6 +204,8 @@ static char **arg_syscall_whitelist = NULL;
static char **arg_syscall_blacklist = NULL;
static struct rlimit *arg_rlimit[_RLIMIT_MAX] = {};
static bool arg_no_new_privileges = false;
+static int arg_oom_score_adjust = 0;
+static bool arg_oom_score_adjust_set = false;
static void help(void) {
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
@@ -270,6 +272,8 @@ static void help(void) {
" --system-call-filter=LIST|~LIST\n"
" Permit/prohibit specific system calls\n"
" --rlimit=NAME=LIMIT Set a resource limit for the payload\n"
+ " --oom-score-adjust=VALUE\n"
+ " Adjust the OOM score value for the payload\n"
" --kill-signal=SIGNAL Select signal to use for shutting down PID 1\n"
" --link-journal=MODE Link up guest journal, one of no, auto, guest, \n"
" host, try-guest, try-host\n"
@@ -448,6 +452,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_RLIMIT,
ARG_HOSTNAME,
ARG_NO_NEW_PRIVILEGES,
+ ARG_OOM_SCORE_ADJUST,
};
static const struct option options[] = {
@@ -504,6 +509,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
{ "system-call-filter", required_argument, NULL, ARG_SYSTEM_CALL_FILTER },
{ "rlimit", required_argument, NULL, ARG_RLIMIT },
+ { "oom-score-adjust", required_argument, NULL, ARG_OOM_SCORE_ADJUST },
{}
};
@@ -1167,6 +1173,15 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
+ case ARG_OOM_SCORE_ADJUST:
+ r = parse_oom_score_adjust(optarg, &arg_oom_score_adjust);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --oom-score-adjust= parameter: %s", optarg);
+
+ arg_oom_score_adjust_set = true;
+ arg_settings_mask |= SETTING_OOM_SCORE_ADJUST;
+ break;
+
case '?':
return -EINVAL;
@@ -2451,6 +2466,12 @@ static int inner_child(
rtnl_socket = safe_close(rtnl_socket);
}
+ if (arg_oom_score_adjust_set) {
+ r = set_oom_score_adjust(arg_oom_score_adjust);
+ if (r < 0)
+ return log_error_errno(r, "Failed to adjust OOM score: %m");
+ }
+
r = drop_capabilities();
if (r < 0)
return log_error_errno(r, "drop_capabilities() failed: %m");
@@ -3361,6 +3382,17 @@ static int load_settings(void) {
settings->no_new_privileges >= 0)
arg_no_new_privileges = settings->no_new_privileges;
+ if ((arg_settings_mask & SETTING_OOM_SCORE_ADJUST) == 0 &&
+ settings->oom_score_adjust_set) {
+
+ if (!arg_settings_trusted)
+ log_warning("Ignoring OOMScoreAdjust= setting, file '%s' is not trusted.", p);
+ else {
+ arg_oom_score_adjust = settings->oom_score_adjust;
+ arg_oom_score_adjust_set = true;
+ }
+ }
+
return 0;
}