]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: add a new setting DefaultOOMScoreAdjust= and set it to 100 above service manage...
authorLennart Poettering <lennart@poettering.net>
Thu, 30 Sep 2021 09:21:18 +0000 (11:21 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 4 Oct 2021 14:27:10 +0000 (16:27 +0200)
Let's make our service managers slightly less likely to be killed by the
OOM killer by adjusting our services' OOM score adjustment to 100 above
ours. Do this conservatively, i.e. only for regular user sessions.

man/org.freedesktop.systemd1.xml
src/core/dbus-manager.c
src/core/main.c
src/core/manager.h
src/core/unit.c

index dd6f17519d7ac599fe2e09d390ec557698f08f7d..bede2226704444fcfad190caacc193da08f8e9d5 100644 (file)
@@ -493,6 +493,8 @@ node /org/freedesktop/systemd1 {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s DefaultOOMPolicy = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly i DefaultOOMScoreAdjust = ...;
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s CtrlAltDelBurstAction = '...';
   };
   interface org.freedesktop.DBus.Peer { ... };
@@ -735,6 +737,8 @@ node /org/freedesktop/systemd1 {
 
     <!--property DefaultOOMPolicy is not documented!-->
 
+    <!--property DefaultOOMScoreAdjust is not documented!-->
+
     <!--property CtrlAltDelBurstAction is not documented!-->
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
@@ -1131,6 +1135,8 @@ node /org/freedesktop/systemd1 {
 
     <variablelist class="dbus-property" generated="True" extra-ref="DefaultOOMPolicy"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="DefaultOOMScoreAdjust"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="CtrlAltDelBurstAction"/>
 
     <!--End of Autogenerated section-->
index 1f2ac8152c2f2867d19384d5a5f335837c1a38cf..99b75598b5ac4e456726df9660be492f6f80ba15 100644 (file)
@@ -31,6 +31,7 @@
 #include "os-util.h"
 #include "parse-util.h"
 #include "path-util.h"
+#include "process-util.h"
 #include "selinux-access.h"
 #include "stat-util.h"
 #include "string-util.h"
@@ -358,6 +359,34 @@ static int property_set_kexec_watchdog(
         return property_set_watchdog(userdata, WATCHDOG_KEXEC, value);
 }
 
+static int property_get_oom_score_adjust(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Manager *m = userdata;
+        int r, n;
+
+        assert(m);
+        assert(bus);
+        assert(reply);
+
+        if (m->default_oom_score_adjust_set)
+                n = m->default_oom_score_adjust;
+        else {
+                n = 0;
+                r = get_oom_score_adjust(&n);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to read current OOM score adjustment value, ignoring: %m");
+        }
+
+        return sd_bus_message_append(reply, "i", n);
+}
+
 static int bus_get_unit_by_name(Manager *m, sd_bus_message *message, const char *name, Unit **ret_unit, sd_bus_error *error) {
         Unit *u;
         int r;
@@ -2722,6 +2751,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_PROPERTY("DefaultTasksMax", "t", bus_property_get_tasks_max, offsetof(Manager, default_tasks_max), 0),
         SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultOOMPolicy", "s", bus_property_get_oom_policy, offsetof(Manager, default_oom_policy), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultOOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("CtrlAltDelBurstAction", "s", bus_property_get_emergency_action, offsetof(Manager, cad_burst_action), SD_BUS_VTABLE_PROPERTY_CONST),
 
         SD_BUS_METHOD_WITH_NAMES("GetUnit",
index ff7f189370ded18470c67adce52db1d409f3fcc7..059ba6dd493a5f85701299dd13b7e836359c8da8 100644 (file)
@@ -3,6 +3,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
+#include <linux/oom.h>
 #include <sys/mount.h>
 #include <sys/prctl.h>
 #include <sys/reboot.h>
@@ -160,6 +161,8 @@ static NUMAPolicy arg_numa_policy;
 static usec_t arg_clock_usec;
 static void *arg_random_seed;
 static size_t arg_random_seed_size;
+static int arg_default_oom_score_adjust;
+static bool arg_default_oom_score_adjust_set;
 
 /* A copy of the original environment block */
 static char **saved_env = NULL;
@@ -633,6 +636,37 @@ static int config_parse_default_timeout_abort(
         return 0;
 }
 
+static 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) {
+
+        int oa, r;
+
+        if (isempty(rvalue)) {
+                arg_default_oom_score_adjust_set = false;
+                return 0;
+        }
+
+        r = parse_oom_score_adjust(rvalue, &oa);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse the OOM score adjust value '%s', ignoring: %m", rvalue);
+                return 0;
+        }
+
+        arg_default_oom_score_adjust = oa;
+        arg_default_oom_score_adjust_set = true;
+
+        return 0;
+}
+
 static int parse_config_file(void) {
         const ConfigTableItem items[] = {
                 { "Manager", "LogLevel",                     config_parse_level2,                0, NULL                                   },
@@ -667,7 +701,7 @@ static int parse_config_file(void) {
                 { "Manager", "DefaultStandardError",         config_parse_output_restricted,     0, &arg_default_std_error                 },
                 { "Manager", "DefaultTimeoutStartSec",       config_parse_sec,                   0, &arg_default_timeout_start_usec        },
                 { "Manager", "DefaultTimeoutStopSec",        config_parse_sec,                   0, &arg_default_timeout_stop_usec         },
-                { "Manager", "DefaultTimeoutAbortSec",       config_parse_default_timeout_abort, 0, NULL         },
+                { "Manager", "DefaultTimeoutAbortSec",       config_parse_default_timeout_abort, 0, NULL                                   },
                 { "Manager", "DefaultRestartSec",            config_parse_sec,                   0, &arg_default_restart_usec              },
                 { "Manager", "DefaultStartLimitInterval",    config_parse_sec,                   0, &arg_default_start_limit_interval      }, /* obsolete alias */
                 { "Manager", "DefaultStartLimitIntervalSec", config_parse_sec,                   0, &arg_default_start_limit_interval      },
@@ -699,6 +733,7 @@ static int parse_config_file(void) {
                 { "Manager", "DefaultTasksMax",              config_parse_tasks_max,             0, &arg_default_tasks_max                 },
                 { "Manager", "CtrlAltDelBurstAction",        config_parse_emergency_action,      0, &arg_cad_burst_action                  },
                 { "Manager", "DefaultOOMPolicy",             config_parse_oom_policy,            0, &arg_default_oom_policy                },
+                { "Manager", "DefaultOOMScoreAdjust",        config_parse_oom_score_adjust,      0, NULL                                   },
                 {}
         };
 
@@ -769,6 +804,8 @@ static void set_manager_defaults(Manager *m) {
         m->default_tasks_accounting = arg_default_tasks_accounting;
         m->default_tasks_max = arg_default_tasks_max;
         m->default_oom_policy = arg_default_oom_policy;
+        m->default_oom_score_adjust_set = arg_default_oom_score_adjust_set;
+        m->default_oom_score_adjust = arg_default_oom_score_adjust;
 
         (void) manager_set_default_rlimits(m, arg_default_rlimit);
 
@@ -2426,6 +2463,35 @@ static void reset_arguments(void) {
         arg_random_seed = mfree(arg_random_seed);
         arg_random_seed_size = 0;
         arg_clock_usec = 0;
+
+        arg_default_oom_score_adjust_set = false;
+}
+
+static void determine_default_oom_score_adjust(void) {
+        int r, a, b;
+
+        /* Run our services at slightly higher OOM score than ourselves. But let's be conservative here, and
+         * do this only if we don't run as root (i.e. only if we are run in user mode, for an unprivileged
+         * user). */
+
+        if (arg_default_oom_score_adjust_set)
+                return;
+
+        if (getuid() == 0)
+                return;
+
+        r = get_oom_score_adjust(&a);
+        if (r < 0)
+                return (void) log_warning_errno(r, "Failed to determine current OOM score adjustment value, ignoring: %m");
+
+        assert_cc(100 <= OOM_SCORE_ADJ_MAX);
+        b = a >= OOM_SCORE_ADJ_MAX - 100 ? OOM_SCORE_ADJ_MAX : a + 100;
+
+        if (a == b)
+                return;
+
+        arg_default_oom_score_adjust = b;
+        arg_default_oom_score_adjust_set = true;
 }
 
 static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
@@ -2459,6 +2525,9 @@ static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
         if (arg_show_status == _SHOW_STATUS_INVALID)
                 arg_show_status = SHOW_STATUS_YES;
 
+        /* Slightly raise the OOM score for our services if we are running for unprivileged users. */
+        determine_default_oom_score_adjust();
+
         /* Push variables into the manager environment block */
         setenv_manager_environment();
 
index 67957fdfbeead7388f6817341abf2128c7643596..97c12ce48f16995ca1448798db0ed59d7abe921f 100644 (file)
@@ -370,6 +370,8 @@ struct Manager {
         usec_t default_timer_accuracy_usec;
 
         OOMPolicy default_oom_policy;
+        int default_oom_score_adjust;
+        bool default_oom_score_adjust_set;
 
         int original_log_level;
         LogTarget original_log_target;
index 4fd499a4f1d69776c093603705a68f86e1717b79..304f67dbf111d7eac977265d91c948c69d228f39 100644 (file)
@@ -187,6 +187,11 @@ static void unit_init(Unit *u) {
         if (ec) {
                 exec_context_init(ec);
 
+                if (u->manager->default_oom_score_adjust_set) {
+                        ec->oom_score_adjust = u->manager->default_oom_score_adjust;
+                        ec->oom_score_adjust_set = true;
+                }
+
                 if (MANAGER_IS_SYSTEM(u->manager))
                         ec->keyring_mode = EXEC_KEYRING_SHARED;
                 else {