From 29c189ac8a12aa1c78e4bfd37b6c5984a9f033da Mon Sep 17 00:00:00 2001 From: q66 Date: Sun, 20 Oct 2024 04:44:34 +0200 Subject: [PATCH] Add support for nice, ioprio, oom-score-adj --- build/Makefile | 2 + build/mconfig.mesontemplate | 2 + build/tools/mconfig-gen.cc | 6 ++ configs/mconfig.Linux | 2 + configs/mconfig.Linux.sh | 2 + configure | 12 ++++ doc/manpages/dinit-service.5.m4 | 23 ++++++++ meson.build | 4 ++ meson_options.txt | 12 ++++ src/baseproc-service.cc | 9 +++ src/includes/load-service.h | 99 +++++++++++++++++++++++++++++++- src/includes/proc-service.h | 42 ++++++++++++++ src/includes/service-constants.h | 4 +- src/load-service.cc | 21 +++++++ src/proc-service.cc | 9 +++ src/run-child-proc.cc | 62 +++++++++++++++++++- src/settings.cc | 10 ++++ 17 files changed, 316 insertions(+), 5 deletions(-) diff --git a/build/Makefile b/build/Makefile index 62e5d0c9..d44f7a5f 100644 --- a/build/Makefile +++ b/build/Makefile @@ -16,6 +16,8 @@ includes/mconfig.h: ../mconfig tools/mconfig-gen.cc version.conf DEFAULT_STOP_TIMEOUT=$(DEFAULT_STOP_TIMEOUT) \ $(if $(SUPPORT_CGROUPS),SUPPORT_CGROUPS=$(SUPPORT_CGROUPS),) \ $(if $(SUPPORT_CAPABILITIES),SUPPORT_CAPABILITIES=$(SUPPORT_CAPABILITIES),) \ + $(if $(SUPPORT_IOPRIO),SUPPORT_IOPRIO=$(SUPPORT_IOPRIO),) \ + $(if $(SUPPORT_OOM_ADJ),SUPPORT_OOM_ADJ=$(SUPPORT_OOM_ADJ),) \ $(if $(USE_UTMPX),USE_UTMPX=$(USE_UTMPX),) \ $(if $(USE_INITGROUPS),USE_INITGROUPS=$(USE_INITGROUPS),) > includes/mconfig.h diff --git a/build/mconfig.mesontemplate b/build/mconfig.mesontemplate index 4e218125..268363ab 100644 --- a/build/mconfig.mesontemplate +++ b/build/mconfig.mesontemplate @@ -9,6 +9,8 @@ #mesondefine USE_INITGROUPS #mesondefine SUPPORT_CGROUPS #mesondefine SUPPORT_CAPABILITIES +#mesondefine SUPPORT_IOPRIO +#mesondefine SUPPORT_OOM_ADJ #mesondefine DEFAULT_AUTO_RESTART #mesondefine DEFAULT_START_TIMEOUT #mesondefine DEFAULT_STOP_TIMEOUT diff --git a/build/tools/mconfig-gen.cc b/build/tools/mconfig-gen.cc index 1a786445..5397f418 100644 --- a/build/tools/mconfig-gen.cc +++ b/build/tools/mconfig-gen.cc @@ -80,6 +80,12 @@ int main(int argc, char **argv) if (vars.find("SUPPORT_CAPABILITIES") != vars.end()) { cout << "#define SUPPORT_CAPABILITIES " << vars["SUPPORT_CAPABILITIES"] << "\n"; } + if (vars.find("SUPPORT_IOPRIO") != vars.end()) { + cout << "#define SUPPORT_IOPRIO " << vars["SUPPORT_IOPRIO"] << "\n"; + } + if (vars.find("SUPPORT_OOM_ADJ") != vars.end()) { + cout << "#define SUPPORT_OOM_ADJ " << vars["SUPPORT_OOM_ADJ"] << "\n"; + } if (vars.find("DEFAULT_AUTO_RESTART") != vars.end()) { cout << "#define DEFAULT_AUTO_RESTART " << vars["DEFAULT_AUTO_RESTART"] << "\n"; } diff --git a/configs/mconfig.Linux b/configs/mconfig.Linux index b5546577..e434903d 100644 --- a/configs/mconfig.Linux +++ b/configs/mconfig.Linux @@ -39,6 +39,8 @@ TEST_LDFLAGS=$(TEST_LDFLAGS_BASE) $(TEST_CXXFLAGS) SUPPORT_CGROUPS=1 SUPPORT_CAPABILITIES=0 +SUPPORT_IOPRIO=1 +SUPPORT_OOM_ADJ=1 # Service defaults. diff --git a/configs/mconfig.Linux.sh b/configs/mconfig.Linux.sh index 7ec55330..3ee04306 100644 --- a/configs/mconfig.Linux.sh +++ b/configs/mconfig.Linux.sh @@ -112,6 +112,8 @@ FEATURE_SETTINGS=$( echo "" echo "SUPPORT_CGROUPS=1" echo "SUPPORT_CAPABILITIES=0" + echo "SUPPORT_IOPRIO=1" + echo "SUPPORT_OOM_ADJ=1" ) SERVICE_DEFAULTS=$( diff --git a/configure b/configure index 196584ad..5e21f93b 100755 --- a/configure +++ b/configure @@ -209,6 +209,8 @@ for var in PREFIX \ BUILD_SHUTDOWN \ SUPPORT_CGROUPS \ SUPPORT_CAPABILITIES \ + SUPPORT_IOPRIO \ + SUPPORT_OOM_ADJ \ USE_UTMPX \ USE_INITGROUPS \ SYSCONTROLSOCKET \ @@ -242,6 +244,10 @@ for arg in "$@"; do --disable-cgroups|--enable-cgroups=no) SUPPORT_CGROUPS=0 ;; --enable-capabilities|--enable-capabilities=yes) SUPPORT_CAPABILITIES=1 ;; --disable-capabilities|--enable-capabilities=no) SUPPORT_CAPABILITIES=0 ;; + --enable-ioprio|--enable-ioprio=yes) SUPPORT_IOPRIO=1 ;; + --disable-ioprio|--enable-ioprio=no) SUPPORT_IOPRIO=0 ;; + --enable-oom-adj|--enable-oom-adj=yes) SUPPORT_OOM_ADJ=1 ;; + --disable-oom-adj|--enable-oom-adj=no) SUPPORT_OOM_ADJ=0 ;; --enable-utmpx|--enable-utmpx=yes) USE_UTMPX=1 ;; --disable-utmpx|--enable-utmpx=no) USE_UTMPX=0 ;; --enable-initgroups|--enable-initgroups=yes) USE_INITGROUPS=1 ;; @@ -282,11 +288,15 @@ if [ "$PLATFORM" = "Linux" ]; then : "${BUILD_SHUTDOWN:="yes"}" : "${SUPPORT_CGROUPS:="1"}" : "${SUPPORT_CAPABILITIES:="1"}" + : "${SUPPORT_IOPRIO:="1"}" + : "${SUPPORT_OOM_ADJ:="1"}" : "${SYSCONTROLSOCKET:="/run/dinitctl"}" else : "${BUILD_SHUTDOWN:="no"}" : "${SUPPORT_CGROUPS:="0"}" : "${SUPPORT_CAPABILITIES:="0"}" + : "${SUPPORT_IOPRIO:="0"}" + : "${SUPPORT_OOM_ADJ:="0"}" : "${SYSCONTROLSOCKET:="/var/run/dinitctl"}" fi @@ -476,6 +486,8 @@ STRIPOPTS=$STRIPOPTS SUPPORT_CGROUPS=$SUPPORT_CGROUPS USE_INITGROUPS=$USE_INITGROUPS SUPPORT_CAPABILITIES=$SUPPORT_CAPABILITIES +SUPPORT_IOPRIO=$SUPPORT_IOPRIO +SUPPORT_OOM_ADJ=$SUPPORT_OOM_ADJ # Optional settings SHUTDOWN_PREFIX=${SHUTDOWN_PREFIX:-} diff --git a/doc/manpages/dinit-service.5.m4 b/doc/manpages/dinit-service.5.m4 index 8a6d7fb6..0ecde3f0 100644 --- a/doc/manpages/dinit-service.5.m4 +++ b/doc/manpages/dinit-service.5.m4 @@ -541,6 +541,12 @@ See the \fBRESOURCE LIMITS\fR section. Note that some operating systems (notably, OpenBSD) do not support this limit; the setting will be ignored on such systems. .TP +\fBnice\fR = \fInice-value\fR +Specifies the CPU priority of the process. +When the given value is out of range for the operating system, it will be clamped to +supported range, but no error will be issued. +On Linux, this also sets the autogroup priority, assuming procfs is mounted. +.TP \fBrun\-in\-cgroup\fR = \fIcgroup-path\fR Run the service process(es) in the specified cgroup (see \fBcgroups\fR(7)). The cgroup is specified as a path; if it has a leading slash, the remainder of the path is @@ -580,6 +586,23 @@ The append form can be used to add more secure bits, with everything being ORed at the end and used as an integer. .IP This setting is only available if \fBdinit\fR was built with capabilities support. +.TP +\fBioprio\fR = \fIioprio-value\fR +Specifies the I/O priority class and value for the process. +The permitted values are \fInone\fR, \fIidle\fR, \fIrealtime:PRIO\fR, and +\fIbest-effort:PRIO\fR, where \fIPRIO\fR is an integer value no less than 0 +and no more than 7. +.IP +This setting is only available if \fBdinit\fR was built with ioprio support. +.TP +\fBoom-score-adj\fR = \fIadj-value\fR +Specifies the OOM killer score adjustment for the service. +The value is an integer no less than -1000 and no more than 1000. +.IP +This setting is only available if \fBdinit\fR was built with OOM score adjustment support. +.IP +This setting requires the proc filesystem to be mounted, and will result in a +service startup failure if that is not the case. .\" .SS OPTIONS .\" diff --git a/meson.build b/meson.build index f6ecd693..21e7c58e 100644 --- a/meson.build +++ b/meson.build @@ -32,6 +32,8 @@ fuzzer = get_option('fuzzer') man_pages = get_option('man-pages') support_cgroups = get_option('support-cgroups') support_capabilities = get_option('support-capabilities') +support_ioprio = get_option('support-ioprio') +support_oom_adj = get_option('support-oom-adj') use_utmpx = get_option('use-utmpx') use_initgroups = get_option('use-initgroups') default_auto_restart = get_option('default-auto-restart') @@ -71,6 +73,8 @@ mconfig_data.set('DEFAULT_STOP_TIMEOUT', default_stop_timeout) mconfig_data.set10('USE_INITGROUPS', use_initgroups) mconfig_data.set10('SUPPORT_CGROUPS', support_cgroups.auto() and platform == 'linux' or support_cgroups.enabled()) mconfig_data.set10('SUPPORT_CAPABILITIES', libcap_dep.found() and not support_capabilities.disabled()) +mconfig_data.set10('SUPPORT_IOPRIO', support_ioprio.auto() and platform == 'linux' or support_ioprio.enabled()) +mconfig_data.set10('SUPPORT_OOM_ADJ', support_oom_adj.auto() and platform == 'linux' or support_oom_adj.enabled()) if use_utmpx.enabled() or (use_utmpx.auto() and compiler.has_header_symbol('utmpx.h', '_PATH_UTMPX') and compiler.has_header_symbol('utmpx.h', '_PATH_WTMPX')) mconfig_data.set('USE_UTMPX', '1') diff --git a/meson_options.txt b/meson_options.txt index 460d1d4e..af92b7eb 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -91,6 +91,18 @@ option( value : 'auto', description : 'Enable capabilities support.' ) +option( + 'support-ioprio', + type : 'feature', + value : 'auto', + description : 'Enable ioprio support.' +) +option( + 'support-oom-adj', + type : 'feature', + value : 'auto', + description : 'Enable OOM score adjustment support.' +) option( 'build-shutdown', type : 'feature', diff --git a/src/baseproc-service.cc b/src/baseproc-service.cc index 81d228b1..4bb3c684 100644 --- a/src/baseproc-service.cc +++ b/src/baseproc-service.cc @@ -257,6 +257,8 @@ bool base_process_service::start_ps_process(const std::vector &cmd run_params.env_file = env_file.c_str(); run_params.output_fd = log_output_fd; run_params.input_fd = input_fd; + run_params.nice_is_set = nice_is_set; + run_params.nice = nice; #if SUPPORT_CGROUPS run_params.run_in_cgroup = run_in_cgroup.c_str(); #endif @@ -265,6 +267,13 @@ bool base_process_service::start_ps_process(const std::vector &cmd run_params.secbits = secbits; run_params.no_new_privs = onstart_flags.no_new_privs; #endif + #if SUPPORT_IOPRIO + run_params.ioprio = ioprio; + #endif + #if SUPPORT_OOM_ADJ + run_params.oom_adj_is_set = oom_adj_is_set; + run_params.oom_adj = oom_adj; + #endif run_child_proc(run_params); } else { diff --git a/src/includes/load-service.h b/src/includes/load-service.h index ab7acb65..fcaa5892 100644 --- a/src/includes/load-service.h +++ b/src/includes/load-service.h @@ -266,7 +266,7 @@ enum class setting_id_t { LOGFILE_GID, LOG_TYPE, LOG_BUFFER_SIZE, CONSUMER_OF, RESTART, SMOOTH_RECOVERY, OPTIONS, LOAD_OPTIONS, TERM_SIGNAL, TERMSIGNAL /* deprecated */, RESTART_LIMIT_INTERVAL, RESTART_DELAY, RESTART_LIMIT_COUNT, STOP_TIMEOUT, START_TIMEOUT, RUN_AS, CHAIN_TO, READY_NOTIFICATION, - INITTAB_ID, INITTAB_LINE, + INITTAB_ID, INITTAB_LINE, NICE, // Prefixed with SETTING_ to avoid name collision with system macros: SETTING_RLIMIT_NOFILE, SETTING_RLIMIT_CORE, SETTING_RLIMIT_DATA, SETTING_RLIMIT_ADDRSPACE, // Possibly unsupported depending on platform/build options: @@ -277,6 +277,12 @@ enum class setting_id_t { CAPABILITIES, SECURE_BITS, #endif +#if SUPPORT_IOPRIO + IOPRIO, +#endif +#if SUPPORT_OOM_ADJ + OOM_SCORE_ADJ, +#endif }; struct setting_details { @@ -840,6 +846,30 @@ inline unsigned long long parse_unum_param(file_pos_ref input_pos, const std::st } } +// Parse a signed numeric parameter value +inline long long parse_snum_param(file_pos_ref input_pos, const std::string ¶m, + const std::string &service_name, long long min = std::numeric_limits::min(), + long long max = std::numeric_limits::max()) +{ + const char * num_err_msg = "specified value contains invalid numeric characters or is outside " + "allowed range."; + + std::size_t ind = 0; + try { + long long v = std::stoll(param, &ind, 0); + if (v < min || v > max || ind != param.length()) { + throw service_description_exc(service_name, num_err_msg, input_pos); + } + return v; + } + catch (std::out_of_range &exc) { + throw service_description_exc(service_name, num_err_msg, input_pos); + } + catch (std::invalid_argument &exc) { + throw service_description_exc(service_name, num_err_msg, input_pos); + } +} + // In a vector, find or create rlimits for a particular resource type. inline service_rlimits &find_rlimits(std::vector &all_rlimits, int resource_id) { @@ -1373,6 +1403,9 @@ class service_settings_wrapper gid_t run_as_uid_gid = -1; // primary group of "run as" uid if known gid_t run_as_gid = -1; + bool nice_is_set = false; + int nice; + string chain_to_name; string consumer_of_name; @@ -1385,6 +1418,15 @@ class service_settings_wrapper secure_bits_t secbits; #endif + #if SUPPORT_IOPRIO + int ioprio = -1; + #endif + + #if SUPPORT_OOM_ADJ + bool oom_adj_is_set = false; + short oom_adj = 0; + #endif + #if USE_UTMPX char inittab_id[sizeof(utmpx().ut_id)] = {0}; char inittab_line[sizeof(utmpx().ut_line)] = {0}; @@ -1467,6 +1509,19 @@ class service_settings_wrapper if (log_type != log_type_id::NONE) { report_lint("option 'log_type' was specified, but ignored for the specified (or default) service type."); } + if (nice_is_set) { + report_lint("option 'nice' was specified, but ignored for the specified (or default) service type."); + } + #if SUPPORT_IOPRIO + if (ioprio >= 0) { + report_lint("option 'ioprio' was specified, but ignored for the specified (or default) service type."); + } + #endif + #if SUPPORT_OOM_ADJ + if (oom_adj_is_set) { + report_lint("option 'oom-score-adj' was specified, but ignored for the specified (or default) service type."); + } + #endif } if (do_report_lint) { @@ -1650,6 +1705,48 @@ void process_service_line(settings_wrapper &settings, const char *name, const ch break; } #endif + case setting_id_t::NICE: + { + string nice_str = read_setting_value(input_pos, i, end); + settings.nice_is_set = true; + settings.nice = (int)parse_snum_param(input_pos, nice_str, name, + std::numeric_limits::min() / 2, std::numeric_limits::max() / 2); + break; + } + #if SUPPORT_IOPRIO + case setting_id_t::IOPRIO: + { + string ioprio_str = read_setting_value(input_pos, i, end); + if (ioprio_str == "none") { + settings.ioprio = 0; + } + else if (starts_with(ioprio_str, "realtime:")) { + auto nval = parse_unum_param(input_pos, ioprio_str.substr(9 /* len 'realtime:' */), name, 7); + settings.ioprio = (1 << 13) | nval; + } + else if (starts_with(ioprio_str, "best-effort:")) { + auto nval = parse_unum_param(input_pos, ioprio_str.substr(12 /* len 'best-effort:' */), name, 7); + settings.ioprio = (2 << 13) | nval; + } + else if (ioprio_str == "idle") { + settings.ioprio = 3 << 13; + } + else { + throw service_description_exc(name, "invalid value for ioprio: " + ioprio_str, + name, input_pos); + } + break; + } + #endif + #if SUPPORT_OOM_ADJ + case setting_id_t::OOM_SCORE_ADJ: + { + string oom_adj_str = read_setting_value(input_pos, i, end); + settings.oom_adj_is_set = true; + settings.oom_adj = (int)parse_snum_param(input_pos, oom_adj_str, name, -1000, 1000); + break; + } + #endif case setting_id_t::SOCKET_LISTEN: settings.socket_path = read_setting_value(input_pos, i, end, nullptr); break; diff --git a/src/includes/proc-service.h b/src/includes/proc-service.h index dc86ac6b..a516bb04 100644 --- a/src/includes/proc-service.h +++ b/src/includes/proc-service.h @@ -80,6 +80,15 @@ struct run_proc_params bool on_console; // whether to run on console bool in_foreground; // if on console: whether to run in foreground bool unmask_sigint = false; // if in foreground: whether to unmask SIGINT + bool nice_is_set = false; + int nice = 0; // the process nice value + #if SUPPORT_IOPRIO + int ioprio = -1; // scheduling class and priority for the process + #endif + #if SUPPORT_OOM_ADJ + bool oom_adj_is_set = false; + short oom_adj = 0; // oom score adjustment value + #endif int wpipefd; // pipe to which error status will be sent (if error occurs) int csfd; // control socket fd (or -1); may be moved int socket_fd; // pre-opened socket fd (or -1); may be moved @@ -232,6 +241,18 @@ class base_process_service : public service_record unsigned log_buf_size = 0; // log buffer current size std::vector> log_buffer; + bool nice_is_set = false; + int nice; + +#if SUPPORT_IOPRIO + int ioprio = -1; +#endif + +#if SUPPORT_OOM_ADJ + bool oom_adj_is_set = false; + short oom_adj = 0; +#endif + std::vector rlimits; // resource limits #if SUPPORT_CAPABILITIES @@ -519,6 +540,27 @@ class base_process_service : public service_record } #endif + void set_nice(int nice_v, bool is_set) noexcept + { + nice_is_set = is_set; + nice = nice_v; + } + + #if SUPPORT_IOPRIO + void set_ioprio(int ioprio_v) noexcept + { + ioprio = ioprio_v; + } + #endif + + #if SUPPORT_OOM_ADJ + void set_oom_adj(short oom_adj_v, bool is_set) noexcept + { + oom_adj_is_set = is_set; + oom_adj = oom_adj_v; + } + #endif + void set_rlimits(std::vector &&rlimits_p) { rlimits = std::move(rlimits_p); diff --git a/src/includes/service-constants.h b/src/includes/service-constants.h index 9e1b5627..d7ac8c7d 100644 --- a/src/includes/service-constants.h +++ b/src/includes/service-constants.h @@ -71,10 +71,10 @@ enum class exec_stage { ARRANGE_FDS, READ_ENV_FILE, SET_NOTIFYFD_VAR, SETUP_ACTIVATION_SOCKET, SETUP_CONTROL_SOCKET, CHDIR, SETUP_STDINOUTERR, ENTER_CGROUP, SET_RLIMITS, SET_UIDGID, OPEN_LOGFILE, // this is used instead of SETUP_STDINOUTERR if output is to logfile - SET_CAPS, + SET_CAPS, SET_PRIO, /* values for future expansion: */ - SPARE3, SPARE4, SPARE5, SPARE6, SPARE7, SPARE8, + SPARE4, SPARE5, SPARE6, SPARE7, SPARE8, /* must be last: */ DO_EXEC }; diff --git a/src/load-service.cc b/src/load-service.cc index 030075e4..3c87c2ec 100644 --- a/src/load-service.cc +++ b/src/load-service.cc @@ -744,6 +744,13 @@ service_record * dirload_service_set::load_reload_service(const char *fullname, #if SUPPORT_CAPABILITIES rvalps->set_cap(std::move(cap_iab), settings.secbits.get()); #endif + rvalps->set_nice(settings.nice, settings.nice_is_set); + #if SUPPORT_IOPRIO + rvalps->set_ioprio(settings.ioprio); + #endif + #if SUPPORT_OOM_ADJ + rvalps->set_oom_adj(settings.oom_adj, settings.oom_adj_is_set); + #endif rvalps->set_rlimits(std::move(settings.rlimits)); rvalps->set_restart_interval(settings.restart_interval, settings.max_restarts); rvalps->set_restart_delay(settings.restart_delay); @@ -790,6 +797,13 @@ service_record * dirload_service_set::load_reload_service(const char *fullname, #if SUPPORT_CAPABILITIES rvalps->set_cap(std::move(cap_iab), settings.secbits.get()); #endif + rvalps->set_nice(settings.nice, settings.nice_is_set); + #if SUPPORT_IOPRIO + rvalps->set_ioprio(settings.ioprio); + #endif + #if SUPPORT_OOM_ADJ + rvalps->set_oom_adj(settings.oom_adj, settings.oom_adj_is_set); + #endif rvalps->set_rlimits(std::move(settings.rlimits)); rvalps->set_pid_file(std::move(settings.pid_file)); rvalps->set_restart_interval(settings.restart_interval, settings.max_restarts); @@ -832,6 +846,13 @@ service_record * dirload_service_set::load_reload_service(const char *fullname, #if SUPPORT_CAPABILITIES rvalps->set_cap(std::move(cap_iab), settings.secbits.get()); #endif + rvalps->set_nice(settings.nice, settings.nice_is_set); + #if SUPPORT_IOPRIO + rvalps->set_ioprio(settings.ioprio); + #endif + #if SUPPORT_OOM_ADJ + rvalps->set_oom_adj(settings.oom_adj, settings.oom_adj_is_set); + #endif rvalps->set_rlimits(std::move(settings.rlimits)); rvalps->set_stop_timeout(settings.stop_timeout); rvalps->set_start_timeout(settings.start_timeout); diff --git a/src/proc-service.cc b/src/proc-service.cc index 08889225..a0bb69b0 100644 --- a/src/proc-service.cc +++ b/src/proc-service.cc @@ -932,6 +932,8 @@ bool process_service::start_stop_process(const std::vector &cmd) n run_params.force_notify_fd = -1; run_params.notify_var = nullptr; run_params.env_file = env_file.c_str(); + run_params.nice_is_set = nice_is_set; + run_params.nice = nice; #if SUPPORT_CGROUPS run_params.run_in_cgroup = run_in_cgroup.c_str(); #endif @@ -940,6 +942,13 @@ bool process_service::start_stop_process(const std::vector &cmd) n run_params.secbits = secbits; run_params.no_new_privs = onstart_flags.no_new_privs; #endif + #if SUPPORT_IOPRIO + run_params.ioprio = ioprio; + #endif + #if SUPPORT_OOM_ADJ + run_params.oom_adj_is_set = oom_adj_is_set; + run_params.oom_adj = oom_adj; + #endif run_child_proc(run_params); } else { diff --git a/src/run-child-proc.cc b/src/run-child-proc.cc index 7727fea5..0cc43bab 100644 --- a/src/run-child-proc.cc +++ b/src/run-child-proc.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,8 @@ void base_process_service::run_child_proc(run_proc_params params) noexcept const char *working_dir = params.working_dir; const char *logfile = params.logfile; bool on_console = params.on_console; + bool nice_is_set = params.nice_is_set; + int nice = params.nice; int wpipefd = params.wpipefd; int csfd = params.csfd; int notify_fd = params.notify_fd; @@ -79,6 +82,13 @@ void base_process_service::run_child_proc(run_proc_params params) noexcept unsigned int secbits = params.secbits; bool no_new_privs = params.no_new_privs; #endif + #if SUPPORT_IOPRIO + int ioprio = params.ioprio; + #endif + #if SUPPORT_OOM_ADJ + bool oom_adj_is_set = params.oom_adj_is_set; + short oom_adj = params.oom_adj; + #endif // If the console already has a session leader, presumably it is us. On the other hand // if it has no session leader, and we don't create one, then control inputs such as @@ -301,6 +311,56 @@ void base_process_service::run_child_proc(run_proc_params params) noexcept if (setrlimit(limit.resource_id, &setlimits) != 0) goto failure_out; } + // nice + if (nice_is_set) { + err.stage = exec_stage::SET_PRIO; + #ifdef __linux__ + // clamp the values to known range so the autogroup hack below works + if (nice > 19) nice = 19; + if (nice < -20) nice = -20; + #endif + if (setpriority(PRIO_PROCESS, getpid(), nice) != 0) goto failure_out; + #ifdef __linux__ + // we usually create a new session leader; that makes nice not very + // useful as the Linux kernel will autogroup processes by session id + // except when disabled - so also work around this where enabled + // the r+ is used in order to avoid creating it where already disabled + errno = 0; + FILE *ag = std::fopen("/proc/self/autogroup", "r+"); + if (ag) { + std::fprintf(ag, "%d\n", nice); + std::fclose(ag); + } + else if (errno != ENOENT) goto failure_out; + #endif + } + + #if SUPPORT_IOPRIO + // ioprio + if (ioprio >= 0) { + err.stage = exec_stage::SET_PRIO; + if (syscall(__NR_ioprio_set, 1, (int)getpid(), ioprio) != 0) goto failure_out; + } + #endif + + #if SUPPORT_OOM_ADJ + // oom score adjustment + if (oom_adj_is_set) { + err.stage = exec_stage::SET_PRIO; + errno = 0; + int fd = open("/proc/self/oom_score_adj", O_WRONLY); + if (fd < 0) goto failure_out; + // +4: round up, minus sign, newline, nul terminator + char val_str[std::numeric_limits::digits10 + 4]; + int num_chars = snprintf(val_str, sizeof(val_str), "%hd\n", oom_adj); + if (write(fd, val_str, num_chars) < 0) { + close(fd); + goto failure_out; + } + close(fd); + } + #endif + #if SUPPORT_CGROUPS if (params.run_in_cgroup != nullptr && *params.run_in_cgroup != 0) { err.stage = exec_stage::ENTER_CGROUP; @@ -405,9 +465,7 @@ void base_process_service::run_child_proc(run_proc_params params) noexcept } if (no_new_privs) { err.stage = exec_stage::SET_CAPS; -#ifdef PR_SET_NO_NEW_PRIVS if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) goto failure_out; -#endif } #endif diff --git a/src/settings.cc b/src/settings.cc index d14189d7..8b62a0b9 100644 --- a/src/settings.cc +++ b/src/settings.cc @@ -57,6 +57,8 @@ setting_details all_settings[] = { {"rlimit-data", setting_id_t::SETTING_RLIMIT_DATA, false, true, false}, {"rlimit-addrspace", setting_id_t::SETTING_RLIMIT_ADDRSPACE, false, true, false}, + {"nice", setting_id_t::NICE, false, true, false}, + #if SUPPORT_CGROUPS {"run-in-cgroup", setting_id_t::RUN_IN_CGROUP, false, true, false}, #endif @@ -66,6 +68,14 @@ setting_details all_settings[] = { {"secure-bits", setting_id_t::SECURE_BITS, false, true, true}, #endif +#if SUPPORT_IOPRIO + {"ioprio", setting_id_t::IOPRIO, false, true, false}, +#endif + +#if SUPPORT_OOM_ADJ + {"oom-score-adj", setting_id_t::OOM_SCORE_ADJ, false, true, false}, +#endif + {nullptr, setting_id_t::LAST, false, false, false} };