803fb7
From ff5349960f1cf7af5404b0f765c57eb386c91216 Mon Sep 17 00:00:00 2001
803fb7
From: Lennart Poettering <lennart@poettering.net>
803fb7
Date: Fri, 13 Nov 2015 18:25:02 +0100
803fb7
Subject: [PATCH] logind: add a new UserTasksMax= setting to logind.conf
803fb7
803fb7
This new setting configures the TasksMax= field for the slice objects we
803fb7
create for each user.
803fb7
803fb7
This alters logind to create the slice unit as transient unit explicitly
803fb7
instead of relying on implicit generation of slice units by simply
803fb7
starting them. This also enables us to set a friendly description for
803fb7
slice units that way.
803fb7
803fb7
Cherry-picked from: 90558f315844ec35e3fd4f1a19ac38c8721c9354
803fb7
Conflicts:
803fb7
	src/login/logind-dbus.c
803fb7
	src/login/logind-user.c
803fb7
	src/login/logind.conf
803fb7
	src/login/logind.h
803fb7
803fb7
Resolves: #1337244
803fb7
---
803fb7
 man/logind.conf.xml          | 15 ++++++-
803fb7
 src/login/logind-dbus.c      | 94 +++++++++++++++++++++++++++++++++++++++++++-
803fb7
 src/login/logind-gperf.gperf |  1 +
803fb7
 src/login/logind-session.c   | 25 +++++++-----
803fb7
 src/login/logind-session.h   |  3 +-
803fb7
 src/login/logind-user.c      | 41 +++++++++++++------
803fb7
 src/login/logind.c           |  1 +
803fb7
 src/login/logind.conf        |  1 +
803fb7
 src/login/logind.h           |  4 +-
803fb7
 9 files changed, 160 insertions(+), 25 deletions(-)
803fb7
803fb7
diff --git a/man/logind.conf.xml b/man/logind.conf.xml
803fb7
index 54651f07d..bcc8ee975 100644
803fb7
--- a/man/logind.conf.xml
803fb7
+++ b/man/logind.conf.xml
803fb7
@@ -1,4 +1,4 @@
803fb7
- 
803fb7
+ 
803fb7
 
803fb7
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
803fb7
 
803fb7
@@ -262,7 +262,18 @@
803fb7
         limit relative to the amount of physical RAM. Defaults to 10%.
803fb7
         Note that this size is a safety limit only. As each runtime
803fb7
         directory is a tmpfs file system, it will only consume as much
803fb7
-        memory as is needed. </para></listitem>
803fb7
+        memory as is needed.</para></listitem>
803fb7
+      </varlistentry>
803fb7
+
803fb7
+      <varlistentry>
803fb7
+        <term><varname>UserTasksMax=</varname></term>
803fb7
+
803fb7
+        <listitem><para>Sets the maximum number of OS tasks each user
803fb7
+        may run concurrently. This controls the
803fb7
+        <varname>TasksMax=</varname> setting of the per-user slice
803fb7
+        unit, see
803fb7
+        <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
803fb7
+        for details.</para></listitem>
803fb7
       </varlistentry>
803fb7
 
803fb7
       <varlistentry>
803fb7
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
803fb7
index fb84e92e5..63b9a0df3 100644
803fb7
--- a/src/login/logind-dbus.c
803fb7
+++ b/src/login/logind-dbus.c
803fb7
@@ -2325,13 +2325,101 @@ int manager_dispatch_delayed(Manager *manager) {
803fb7
         return 1;
803fb7
 }
803fb7
 
803fb7
+int manager_start_slice(
803fb7
+                Manager *manager,
803fb7
+                const char *slice,
803fb7
+                const char *description,
803fb7
+                const char *after,
803fb7
+                const char *after2,
803fb7
+                uint64_t tasks_max,
803fb7
+                sd_bus_error *error,
803fb7
+                char **job) {
803fb7
+
803fb7
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
803fb7
+        int r;
803fb7
+
803fb7
+        assert(manager);
803fb7
+        assert(slice);
803fb7
+
803fb7
+        r = sd_bus_message_new_method_call(
803fb7
+                        manager->bus,
803fb7
+                        &m,
803fb7
+                        "org.freedesktop.systemd1",
803fb7
+                        "/org/freedesktop/systemd1",
803fb7
+                        "org.freedesktop.systemd1.Manager",
803fb7
+                        "StartTransientUnit");
803fb7
+        if (r < 0)
803fb7
+                return r;
803fb7
+
803fb7
+        r = sd_bus_message_append(m, "ss", strempty(slice), "fail");
803fb7
+        if (r < 0)
803fb7
+                return r;
803fb7
+
803fb7
+        r = sd_bus_message_open_container(m, 'a', "(sv)");
803fb7
+        if (r < 0)
803fb7
+                return r;
803fb7
+
803fb7
+        if (!isempty(description)) {
803fb7
+                r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
803fb7
+                if (r < 0)
803fb7
+                        return r;
803fb7
+        }
803fb7
+
803fb7
+        if (!isempty(after)) {
803fb7
+                r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after);
803fb7
+                if (r < 0)
803fb7
+                        return r;
803fb7
+        }
803fb7
+
803fb7
+        if (!isempty(after2)) {
803fb7
+                r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2);
803fb7
+                if (r < 0)
803fb7
+                        return r;
803fb7
+        }
803fb7
+
803fb7
+        r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
803fb7
+        if (r < 0)
803fb7
+                return r;
803fb7
+
803fb7
+        r = sd_bus_message_close_container(m);
803fb7
+        if (r < 0)
803fb7
+                return r;
803fb7
+
803fb7
+        r = sd_bus_message_append(m, "a(sa(sv))", 0);
803fb7
+        if (r < 0)
803fb7
+                return r;
803fb7
+
803fb7
+        r = sd_bus_call(manager->bus, m, 0, error, &reply);
803fb7
+        if (r < 0)
803fb7
+                return r;
803fb7
+
803fb7
+        if (job) {
803fb7
+                const char *j;
803fb7
+                char *copy;
803fb7
+
803fb7
+                r = sd_bus_message_read(reply, "o", &j);
803fb7
+                if (r < 0)
803fb7
+                        return r;
803fb7
+
803fb7
+                copy = strdup(j);
803fb7
+                if (!copy)
803fb7
+                        return -ENOMEM;
803fb7
+
803fb7
+                *job = copy;
803fb7
+        }
803fb7
+
803fb7
+        return 1;
803fb7
+}
803fb7
+
803fb7
 int manager_start_scope(
803fb7
                 Manager *manager,
803fb7
                 const char *scope,
803fb7
                 pid_t pid,
803fb7
                 const char *slice,
803fb7
                 const char *description,
803fb7
-                const char *after, const char *after2,
803fb7
+                const char *after,
803fb7
+                const char *after2,
803fb7
+                uint64_t tasks_max,
803fb7
                 sd_bus_error *error,
803fb7
                 char **job) {
803fb7
 
803fb7
@@ -2399,6 +2487,10 @@ int manager_start_scope(
803fb7
         if (r < 0)
803fb7
                 return r;
803fb7
 
803fb7
+        r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
803fb7
+        if (r < 0)
803fb7
+                return r;
803fb7
+
803fb7
         r = sd_bus_message_close_container(m);
803fb7
         if (r < 0)
803fb7
                 return r;
803fb7
diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf
803fb7
index 62460673b..8a064e2a9 100644
803fb7
--- a/src/login/logind-gperf.gperf
803fb7
+++ b/src/login/logind-gperf.gperf
803fb7
@@ -33,3 +33,4 @@ Login.IdleAction,                  config_parse_handle_action, 0, offsetof(Manag
803fb7
 Login.IdleActionSec,               config_parse_sec,           0, offsetof(Manager, idle_action_usec)
803fb7
 Login.RuntimeDirectorySize,        config_parse_tmpfs_size,    0, offsetof(Manager, runtime_dir_size)
803fb7
 Login.RemoveIPC,                   config_parse_bool,          0, offsetof(Manager, remove_ipc)
803fb7
+Login.UserTasksMax,                config_parse_uint64,        0, offsetof(Manager, user_tasks_max)
803fb7
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
803fb7
index 746e50aa5..4575a029f 100644
803fb7
--- a/src/login/logind-session.c
803fb7
+++ b/src/login/logind-session.c
803fb7
@@ -510,21 +510,28 @@ static int session_start_scope(Session *s) {
803fb7
 
803fb7
         if (!s->scope) {
803fb7
                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
803fb7
-                _cleanup_free_ char *description = NULL;
803fb7
                 char *scope, *job = NULL;
803fb7
-
803fb7
-                description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
803fb7
-                if (!description)
803fb7
-                        return log_oom();
803fb7
+                const char *description;
803fb7
 
803fb7
                 scope = strjoin("session-", s->id, ".scope", NULL);
803fb7
                 if (!scope)
803fb7
                         return log_oom();
803fb7
 
803fb7
-                r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job;;
803fb7
+                description = strjoina("Session ", s->id, " of user ", s->user->name, NULL);
803fb7
+
803fb7
+                r = manager_start_scope(
803fb7
+                                s->manager,
803fb7
+                                scope,
803fb7
+                                s->leader,
803fb7
+                                s->user->slice,
803fb7
+                                description,
803fb7
+                                "systemd-logind.service",
803fb7
+                                "systemd-user-sessions.service",
803fb7
+                                (uint64_t) -1, /* disable TasksMax= for the scope, rely on the slice setting for it */
803fb7
+                                &error,
803fb7
+                                &job;;
803fb7
                 if (r < 0) {
803fb7
-                        log_error("Failed to start session scope %s: %s %s",
803fb7
-                                  scope, bus_error_message(&error, r), error.name);
803fb7
+                        log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(&error, r));
803fb7
                         free(scope);
803fb7
                         return r;
803fb7
                 } else {
803fb7
@@ -536,7 +543,7 @@ static int session_start_scope(Session *s) {
803fb7
         }
803fb7
 
803fb7
         if (s->scope)
803fb7
-                hashmap_put(s->manager->session_units, s->scope, s);
803fb7
+                (void) hashmap_put(s->manager->session_units, s->scope, s);
803fb7
 
803fb7
         return 0;
803fb7
 }
803fb7
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
803fb7
index 5002b6868..d662082d8 100644
803fb7
--- a/src/login/logind-session.h
803fb7
+++ b/src/login/logind-session.h
803fb7
@@ -115,7 +115,8 @@ struct Session {
803fb7
 
803fb7
         bool in_gc_queue:1;
803fb7
         bool started:1;
803fb7
-        bool stopping:1;
803fb7
+
803fb7
+        bool stopping;
803fb7
 
803fb7
         sd_bus_message *create_message;
803fb7
 
803fb7
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
803fb7
index 97eb4feca..4298704ce 100644
803fb7
--- a/src/login/logind-user.c
803fb7
+++ b/src/login/logind-user.c
803fb7
@@ -33,6 +33,7 @@
803fb7
 #include "special.h"
803fb7
 #include "unit-name.h"
803fb7
 #include "bus-util.h"
803fb7
+#include "bus-common-errors.h"
803fb7
 #include "bus-error.h"
803fb7
 #include "conf-parser.h"
803fb7
 #include "clean-ipc.h"
803fb7
@@ -367,34 +368,52 @@ fail:
803fb7
 }
803fb7
 
803fb7
 static int user_start_slice(User *u) {
803fb7
-        char *job;
803fb7
         int r;
803fb7
 
803fb7
         assert(u);
803fb7
 
803fb7
         if (!u->slice) {
803fb7
                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
803fb7
-                char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
803fb7
-                sprintf(lu, UID_FMT, u->uid);
803fb7
+                char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice, *job;
803fb7
+                const char *description;
803fb7
+
803fb7
+                free(u->slice_job);
803fb7
+                u->slice_job = NULL;
803fb7
 
803fb7
+                xsprintf(lu, UID_FMT, u->uid);
803fb7
                 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
803fb7
                 if (r < 0)
803fb7
-                        return r;
803fb7
-
803fb7
-                r = manager_start_unit(u->manager, slice, &error, &job;;
803fb7
+                        return log_error_errno(r, "Failed to build slice name: %m");
803fb7
+
803fb7
+                description = strjoina("User Slice of ", u->name);
803fb7
+
803fb7
+                r = manager_start_slice(
803fb7
+                                u->manager,
803fb7
+                                slice,
803fb7
+                                description,
803fb7
+                                "systemd-logind.service",
803fb7
+                                "systemd-user-sessions.service",
803fb7
+                                u->manager->user_tasks_max,
803fb7
+                                &error,
803fb7
+                                &job;;
803fb7
                 if (r < 0) {
803fb7
-                        log_error("Failed to start user slice: %s", bus_error_message(&error, r));
803fb7
-                        free(slice);
803fb7
+
803fb7
+                        if (sd_bus_error_has_name(&error, BUS_ERROR_UNIT_EXISTS))
803fb7
+                                /* The slice already exists? If so, that's fine, let's just reuse it */
803fb7
+                                u->slice = slice;
803fb7
+                        else {
803fb7
+                                log_error_errno(r, "Failed to start user slice %s, ignoring: %s (%s)", slice, bus_error_message(&error, r), error.name);
803fb7
+                                free(slice);
803fb7
+                                /* we don't fail due to this, let's try to continue */
803fb7
+                        }
803fb7
                 } else {
803fb7
                         u->slice = slice;
803fb7
-
803fb7
-                        free(u->slice_job);
803fb7
                         u->slice_job = job;
803fb7
                 }
803fb7
         }
803fb7
 
803fb7
         if (u->slice)
803fb7
-                hashmap_put(u->manager->user_units, u->slice, u);
803fb7
+                (void) hashmap_put(u->manager->user_units, u->slice, u);
803fb7
 
803fb7
         return 0;
803fb7
 }
803fb7
diff --git a/src/login/logind.c b/src/login/logind.c
803fb7
index e8d0669bb..16c931c3e 100644
803fb7
--- a/src/login/logind.c
803fb7
+++ b/src/login/logind.c
803fb7
@@ -63,6 +63,7 @@ Manager *manager_new(void) {
803fb7
         m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
803fb7
 
803fb7
         m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
803fb7
+        m->user_tasks_max = (uint64_t) -1;
803fb7
 
803fb7
         m->devices = hashmap_new(&string_hash_ops);
803fb7
         m->seats = hashmap_new(&string_hash_ops);
803fb7
diff --git a/src/login/logind.conf b/src/login/logind.conf
803fb7
index be8d7dff2..d33e0b34d 100644
803fb7
--- a/src/login/logind.conf
803fb7
+++ b/src/login/logind.conf
803fb7
@@ -31,3 +31,4 @@
803fb7
 #IdleActionSec=30min
803fb7
 #RuntimeDirectorySize=10%
803fb7
 #RemoveIPC=no
803fb7
+#UserTasksMax=
803fb7
diff --git a/src/login/logind.h b/src/login/logind.h
803fb7
index e0cb7d023..8503eb24d 100644
803fb7
--- a/src/login/logind.h
803fb7
+++ b/src/login/logind.h
803fb7
@@ -128,6 +128,7 @@ struct Manager {
803fb7
         sd_event_source *lid_switch_ignore_event_source;
803fb7
 
803fb7
         size_t runtime_dir_size;
803fb7
+        uint64_t user_tasks_max;
803fb7
 };
803fb7
 
803fb7
 Manager *manager_new(void);
803fb7
@@ -176,7 +177,8 @@ int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_
803fb7
 
803fb7
 int manager_dispatch_delayed(Manager *manager);
803fb7
 
803fb7
-int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_error *error, char **job);
803fb7
+int manager_start_slice(Manager *manager, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job);
803fb7
+int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job);
803fb7
 int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
803fb7
 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
803fb7
 int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error);