logind: add a new UserTasksMax= setting to logind.conf

This new setting configures the TasksMax= field for the slice objects we
create for each user.

This alters logind to create the slice unit as transient unit explicitly
instead of relying on implicit generation of slice units by simply
starting them. This also enables us to set a friendly description for
slice units that way.
This commit is contained in:
Lennart Poettering 2015-11-13 18:25:02 +01:00
parent 38599489e4
commit 90558f3158
8 changed files with 166 additions and 27 deletions

View file

@ -1,4 +1,4 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
@ -277,7 +277,18 @@
limit relative to the amount of physical RAM. Defaults to 10%.
Note that this size is a safety limit only. As each runtime
directory is a tmpfs file system, it will only consume as much
memory as is needed. </para></listitem>
memory as is needed.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>UserTasksMax=</varname></term>
<listitem><para>Sets the maximum number of OS tasks each user
may run concurrently. This controls the
<varname>TasksMax=</varname> setting of the per-user slice
unit, see
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
<varlistentry>

View file

@ -2740,13 +2740,101 @@ int manager_send_changed(Manager *manager, const char *property, ...) {
l);
}
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) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
int r;
assert(manager);
assert(slice);
r = sd_bus_message_new_method_call(
manager->bus,
&m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StartTransientUnit");
if (r < 0)
return r;
r = sd_bus_message_append(m, "ss", strempty(slice), "fail");
if (r < 0)
return r;
r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0)
return r;
if (!isempty(description)) {
r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
if (r < 0)
return r;
}
if (!isempty(after)) {
r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after);
if (r < 0)
return r;
}
if (!isempty(after2)) {
r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2);
if (r < 0)
return r;
}
r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
if (r < 0)
return r;
r = sd_bus_message_close_container(m);
if (r < 0)
return r;
r = sd_bus_message_append(m, "a(sa(sv))", 0);
if (r < 0)
return r;
r = sd_bus_call(manager->bus, m, 0, error, &reply);
if (r < 0)
return r;
if (job) {
const char *j;
char *copy;
r = sd_bus_message_read(reply, "o", &j);
if (r < 0)
return r;
copy = strdup(j);
if (!copy)
return -ENOMEM;
*job = copy;
}
return 1;
}
int manager_start_scope(
Manager *manager,
const char *scope,
pid_t pid,
const char *slice,
const char *description,
const char *after, const char *after2,
const char *after,
const char *after2,
uint64_t tasks_max,
sd_bus_error *error,
char **job) {
@ -2814,6 +2902,10 @@ int manager_start_scope(
if (r < 0)
return r;
r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
if (r < 0)
return r;
r = sd_bus_message_close_container(m);
if (r < 0)
return r;

View file

@ -34,3 +34,4 @@ Login.IdleAction, config_parse_handle_action, 0, offsetof(Manag
Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec)
Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size)
Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc)
Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max)

View file

@ -516,21 +516,28 @@ static int session_start_scope(Session *s) {
if (!s->scope) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *description = NULL;
char *scope, *job = NULL;
description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
if (!description)
return log_oom();
const char *description;
scope = strjoin("session-", s->id, ".scope", NULL);
if (!scope)
return log_oom();
r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
description = strjoina("Session ", s->id, " of user ", s->user->name, NULL);
r = manager_start_scope(
s->manager,
scope,
s->leader,
s->user->slice,
description,
"systemd-logind.service",
"systemd-user-sessions.service",
(uint64_t) -1, /* disable TasksMax= for the scope, rely on the slice setting for it */
&error,
&job);
if (r < 0) {
log_error("Failed to start session scope %s: %s %s",
scope, bus_error_message(&error, r), error.name);
log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(&error, r));
free(scope);
return r;
} else {
@ -542,7 +549,7 @@ static int session_start_scope(Session *s) {
}
if (s->scope)
hashmap_put(s->manager->session_units, s->scope, s);
(void) hashmap_put(s->manager->session_units, s->scope, s);
return 0;
}

View file

@ -25,6 +25,7 @@
#include <unistd.h>
#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-util.h"
#include "clean-ipc.h"
@ -44,6 +45,7 @@
#include "rm-rf.h"
#include "smack-util.h"
#include "special.h"
#include "stdio-util.h"
#include "string-table.h"
#include "unit-name.h"
#include "user-util.h"
@ -392,34 +394,51 @@ fail:
}
static int user_start_slice(User *u) {
char *job;
int r;
assert(u);
if (!u->slice) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
sprintf(lu, UID_FMT, u->uid);
char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice, *job;
const char *description;
u->slice_job = mfree(u->slice_job);
xsprintf(lu, UID_FMT, u->uid);
r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &slice);
if (r < 0)
return r;
return log_error_errno(r, "Failed to build slice name: %m");
r = manager_start_unit(u->manager, slice, &error, &job);
description = strjoina("User Slice of ", u->name);
r = manager_start_slice(
u->manager,
slice,
description,
"systemd-logind.service",
"systemd-user-sessions.service",
u->manager->user_tasks_max,
&error,
&job);
if (r < 0) {
log_error("Failed to start user slice: %s", bus_error_message(&error, r));
free(slice);
if (sd_bus_error_has_name(&error, BUS_ERROR_UNIT_EXISTS))
/* The slice already exists? If so, that's fine, let's just reuse it */
u->slice = slice;
else {
log_error_errno(r, "Failed to start user slice %s, ignoring: %s (%s)", slice, bus_error_message(&error, r), error.name);
free(slice);
/* we don't fail due to this, let's try to continue */
}
} else {
u->slice = slice;
free(u->slice_job);
u->slice_job = job;
}
}
if (u->slice)
hashmap_put(u->manager->user_units, u->slice, u);
(void) hashmap_put(u->manager->user_units, u->slice, u);
return 0;
}
@ -433,16 +452,21 @@ static int user_start_service(User *u) {
if (!u->service) {
char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
sprintf(lu, UID_FMT, u->uid);
xsprintf(lu, UID_FMT, u->uid);
r = unit_name_build("user", lu, ".service", &service);
if (r < 0)
return log_error_errno(r, "Failed to build service name: %m");
r = manager_start_unit(u->manager, service, &error, &job);
r = manager_start_unit(
u->manager,
service,
&error,
&job);
if (r < 0) {
log_error("Failed to start user service: %s", bus_error_message(&error, r));
log_error_errno(r, "Failed to start user service, ignoring: %s", bus_error_message(&error, r));
free(service);
/* we don't fail due to this, let's try to continue */
} else {
u->service = service;
@ -452,7 +476,7 @@ static int user_start_service(User *u) {
}
if (u->service)
hashmap_put(u->manager->user_units, u->service, u);
(void) hashmap_put(u->manager->user_units, u->service, u);
return 0;
}

View file

@ -70,6 +70,7 @@ static Manager *manager_new(void) {
m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
m->user_tasks_max = (uint64_t) -1;
m->devices = hashmap_new(&string_hash_ops);
m->seats = hashmap_new(&string_hash_ops);

View file

@ -32,3 +32,4 @@
#IdleActionSec=30min
#RuntimeDirectorySize=10%
#RemoveIPC=yes
#UserTasksMax=

View file

@ -134,6 +134,7 @@ struct Manager {
sd_event_source *lid_switch_ignore_event_source;
size_t runtime_dir_size;
uint64_t user_tasks_max;
};
int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device);
@ -171,7 +172,8 @@ int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name
int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_;
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);
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);
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);
int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error);