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