#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"
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;
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",
#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>
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;
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 },
{ "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 },
{ "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 },
{}
};
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);
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,
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();