core: make IOSchedulingClass= and IOSchedulingPriority= settable for transient units
authorLennart Poettering <lennart@poettering.net>
Mon, 26 Jun 2017 15:40:08 +0000 (17:40 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 26 Jun 2017 15:43:18 +0000 (17:43 +0200)
This patch is a bit more complex thant I hoped. In particular the single
IOScheduling= property exposed on the bus is split up into
IOSchedulingClass= and IOSchedulingPriority= (though compat is
retained). Otherwise the asymmetry between setting props and getting
them is a bit too nasty.

Fixes #5613

src/basic/process-util.c
src/basic/process-util.h
src/core/dbus-execute.c
src/core/execute.c
src/core/execute.h
src/core/load-fragment.c
src/shared/bus-unit-util.c

index a21dc35..b80caca 100644 (file)
@@ -905,6 +905,23 @@ int pid_compare_func(const void *a, const void *b) {
         return 0;
 }
 
+int ioprio_parse_priority(const char *s, int *ret) {
+        int i, r;
+
+        assert(s);
+        assert(ret);
+
+        r = safe_atoi(s, &i);
+        if (r < 0)
+                return r;
+
+        if (!ioprio_priority_is_valid(i))
+                return -EINVAL;
+
+        *ret = i;
+        return 0;
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",
index d378901..28d8d74 100644 (file)
 #include <stddef.h>
 #include <stdio.h>
 #include <string.h>
-#include <sys/types.h>
 #include <sys/resource.h>
+#include <sys/types.h>
 
 #include "format-util.h"
+#include "ioprio.h"
 #include "macro.h"
 
 #define procfs_file_alloca(pid, field)                                  \
@@ -108,3 +109,13 @@ int pid_compare_func(const void *a, const void *b);
 static inline bool nice_is_valid(int n) {
         return n >= PRIO_MIN && n < PRIO_MAX;
 }
+
+static inline bool ioprio_class_is_valid(int i) {
+        return IN_SET(i, IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE);
+}
+
+static inline bool ioprio_priority_is_valid(int i) {
+        return i >= 0 && i < IOPRIO_BE_NR;
+}
+
+int ioprio_parse_priority(const char *s, int *ret);
index 7e165be..8f9d717 100644 (file)
@@ -160,21 +160,51 @@ static int property_get_ioprio(
 
 
         ExecContext *c = userdata;
-        int32_t n;
 
         assert(bus);
         assert(reply);
         assert(c);
 
-        if (c->ioprio_set)
-                n = c->ioprio;
-        else {
-                n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
-                if (n < 0)
-                        n = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4);
-        }
+        return sd_bus_message_append(reply, "i", exec_context_get_effective_ioprio(c));
+}
 
-        return sd_bus_message_append(reply, "i", n);
+static int property_get_ioprio_class(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+
+        ExecContext *c = userdata;
+
+        assert(bus);
+        assert(reply);
+        assert(c);
+
+        return sd_bus_message_append(reply, "i", IOPRIO_PRIO_CLASS(exec_context_get_effective_ioprio(c)));
+}
+
+
+static int property_get_ioprio_priority(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+
+        ExecContext *c = userdata;
+
+        assert(bus);
+        assert(reply);
+        assert(c);
+
+        return sd_bus_message_append(reply, "i", IOPRIO_PRIO_DATA(exec_context_get_effective_ioprio(c)));
 }
 
 static int property_get_cpu_sched_policy(
@@ -762,7 +792,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("IOSchedulingClass", "i", property_get_ioprio_class, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("IOSchedulingPriority", "i", property_get_ioprio_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -784,7 +815,6 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
         SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("AmbientCapabilities", "t", property_get_ambient_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -794,9 +824,6 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(ExecContext, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
-        SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
-        SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
         SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ReadOnlyPaths", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("InaccessiblePaths", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -831,6 +858,14 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("BindPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("BindReadOnlyPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("MountAPIVFS", "b", bus_property_get_bool, offsetof(ExecContext, mount_apivfs), SD_BUS_VTABLE_PROPERTY_CONST),
+
+        /* Obsolete/redundant properties: */
+        SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
+        SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
+        SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
+        SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
+        SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
+
         SD_BUS_VTABLE_END
 };
 
@@ -1050,6 +1085,50 @@ int bus_exec_context_set_transient_property(
 
                 return 1;
 
+        } else if (streq(name, "IOSchedulingClass")) {
+                int32_t q;
+
+                r = sd_bus_message_read(message, "i", &q);
+                if (r < 0)
+                        return r;
+
+                if (!ioprio_class_is_valid(q))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid IO scheduling class: %i", q);
+
+                if (mode != UNIT_CHECK) {
+                        _cleanup_free_ char *s = NULL;
+
+                        r = ioprio_class_to_string_alloc(q, &s);
+                        if (r < 0)
+                                return r;
+
+                        c->ioprio = IOPRIO_PRIO_VALUE(q, IOPRIO_PRIO_DATA(c->ioprio));
+                        c->ioprio_set = true;
+
+                        unit_write_drop_in_private_format(u, mode, name, "IOSchedulingClass=%s", s);
+                }
+
+                return 1;
+
+        } else if (streq(name, "IOSchedulingPriority")) {
+                int32_t p;
+
+                r = sd_bus_message_read(message, "i", &p);
+                if (r < 0)
+                        return r;
+
+                if (!ioprio_priority_is_valid(p))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid IO scheduling priority: %i", p);
+
+                if (mode != UNIT_CHECK) {
+                        c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), p);
+                        c->ioprio_set = true;
+
+                        unit_write_drop_in_private_format(u, mode, name, "IOSchedulingPriority=%i", p);
+                }
+
+                return 1;
+
         } else if (STR_IN_SET(name, "TTYPath", "RootDirectory", "RootImage")) {
                 const char *s;
 
index 340939d..d72e5bf 100644 (file)
@@ -3701,6 +3701,21 @@ bool exec_context_maintains_privileges(ExecContext *c) {
         return false;
 }
 
+int exec_context_get_effective_ioprio(ExecContext *c) {
+        int p;
+
+        assert(c);
+
+        if (c->ioprio_set)
+                return c->ioprio;
+
+        p = ioprio_get(IOPRIO_WHO_PROCESS, 0);
+        if (p < 0)
+                return IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4);
+
+        return p;
+}
+
 void exec_status_start(ExecStatus *s, pid_t pid) {
         assert(s);
 
index 1363193..9f07aa4 100644 (file)
@@ -307,6 +307,8 @@ const char* exec_context_fdname(const ExecContext *c, int fd_index);
 bool exec_context_may_touch_console(ExecContext *c);
 bool exec_context_maintains_privileges(ExecContext *c);
 
+int exec_context_get_effective_ioprio(ExecContext *c);
+
 void exec_status_start(ExecStatus *s, pid_t pid);
 void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status);
 void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);
index af3c6a4..8d7153f 100644 (file)
@@ -940,8 +940,8 @@ int config_parse_exec_io_priority(const char *unit,
         assert(rvalue);
         assert(data);
 
-        r = safe_atoi(rvalue, &i);
-        if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
+        r = ioprio_parse_priority(rvalue, &i);
+        if (r < 0) {
                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
                 return 0;
         }
index 7b0bc82..e4204fd 100644 (file)
@@ -389,6 +389,24 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
 
                 r = sd_bus_message_append(m, "v", "i", (int32_t) n);
 
+        } else if (streq(field, "IOSchedulingClass")) {
+                int c;
+
+                c = ioprio_class_from_string(eq);
+                if (c < 0)
+                        return log_error_errno(r, "Failed to parse IO scheduling class: %s", eq);
+
+                r = sd_bus_message_append(m, "v", "i", (int32_t) c);
+
+        } else if (streq(field, "IOSchedulingPriority")) {
+                int q;
+
+                r = ioprio_parse_priority(eq, &q);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse IO scheduling priority: %s", eq);
+
+                r = sd_bus_message_append(m, "v", "i", (int32_t) q);
+
         } else if (STR_IN_SET(field, "Environment", "PassEnvironment")) {
                 const char *p;