]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: in execute, Never fail setting Nice priority
authorDimitri John Ledkov <xnox@ubuntu.com>
Tue, 1 Aug 2017 16:38:05 +0000 (17:38 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 2 Jan 2020 19:50:14 +0000 (20:50 +0100)
Instead, push to the closest possible Nice priority setting.

Replaces: #11397

src/basic/process-util.c
src/basic/process-util.h
src/core/execute.c

index 743c7b1dad283dba2e8bc09dc772fa69f0db28d9..5de366f830e81b3c21815591fe6f565d42eea82f 100644 (file)
@@ -22,6 +22,7 @@
 #include "alloc-util.h"
 #include "architecture.h"
 #include "env-util.h"
+#include "errno-util.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -1527,6 +1528,62 @@ int pidfd_get_pid(int fd, pid_t *ret) {
         return parse_pid(p, ret);
 }
 
+static int rlimit_to_nice(rlim_t limit) {
+        if (limit <= 1)
+                return PRIO_MAX-1; /* i.e. 19 */
+
+        if (limit >= -PRIO_MIN + PRIO_MAX)
+                return PRIO_MIN; /* i.e. -20 */
+
+        return PRIO_MAX - (int) limit;
+}
+
+int setpriority_closest(int priority) {
+        int current, limit, saved_errno;
+        struct rlimit highest;
+
+        /* Try to set requested nice level */
+        if (setpriority(PRIO_PROCESS, 0, priority) >= 0)
+                return 1;
+
+        /* Permission failed */
+        saved_errno = -errno;
+        if (!ERRNO_IS_PRIVILEGE(saved_errno))
+                return saved_errno;
+
+        errno = 0;
+        current = getpriority(PRIO_PROCESS, 0);
+        if (errno != 0)
+                return -errno;
+
+        if (priority == current)
+                return 1;
+
+       /* Hmm, we'd expect that raising the nice level from our status quo would always work. If it doesn't,
+        * then the whole setpriority() system call is blocked to us, hence let's propagate the error
+        * right-away */
+        if (priority > current)
+                return saved_errno;
+
+        if (getrlimit(RLIMIT_NICE, &highest) < 0)
+                return -errno;
+
+        limit = rlimit_to_nice(highest.rlim_cur);
+
+        /* We are already less nice than limit allows us */
+        if (current < limit) {
+                log_debug("Cannot raise nice level, permissions and the resource limit do not allow it.");
+                return 0;
+        }
+
+        /* Push to the allowed limit */
+        if (setpriority(PRIO_PROCESS, 0, limit) < 0)
+                return -errno;
+
+        log_debug("Cannot set requested nice level (%i), used next best (%i).", priority, limit);
+        return 0;
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",
index 57582738b3cf9e639e4cc3bbac91f5efa51331dd..a238b25796a2e67510e5ec25bec4912379fda13a 100644 (file)
@@ -200,3 +200,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
         })
 
 int pidfd_get_pid(int fd, pid_t *ret);
+
+int setpriority_closest(int priority);
index 2cb2392d16bc1de107b7daca187f514bb31f2e20..11372958a6ad2a28826718fa99b3e8847b367cf1 100644 (file)
@@ -3236,11 +3236,11 @@ static int exec_child(
                 }
         }
 
-        if (context->nice_set)
-                if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
-                        *exit_status = EXIT_NICE;
-                        return log_unit_error_errno(unit, errno, "Failed to set up process scheduling priority (nice level): %m");
-                }
+        if (context->nice_set) {
+                r = setpriority_closest(context->nice);
+                if (r < 0)
+                        return log_unit_error_errno(unit, r, "Failed to set up process scheduling priority (nice level): %m");
+        }
 
         if (context->cpu_sched_set) {
                 struct sched_param param = {