Merge pull request #1886 from poettering/tasks-max

Enable TasksMax by default for all units
This commit is contained in:
David Herrmann 2015-11-16 15:09:55 +01:00
commit 44690833df
27 changed files with 295 additions and 106 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. Defaults to 4096.</para></listitem>
</varlistentry>
<varlistentry>

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">
@ -317,7 +317,20 @@
<varname>MemoryAccounting=</varname> and
<varname>TasksAccounting=</varname>. See
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details on the per-unit settings.</para></listitem>
for details on the per-unit
settings. <varname>DefaulTasksAccounting=</varname> defaults
to on, the other three settings to off.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultTasksMax=</varname></term>
<listitem><para>Configure the default value for the per-unit
<varname>TasksMax=</varname> setting. See
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details. This setting applies to all unit types that
support resource control settings, with the exception of slice
units. Defaults to 512.</para></listitem>
</varlistentry>
<varlistentry>

View file

@ -241,7 +241,10 @@
see <ulink
url="https://www.kernel.org/doc/Documentation/cgroups/pids.txt">pids.txt</ulink>.</para>
<para>Implies <literal>TasksAccounting=true</literal>.</para>
<para>Implies <literal>TasksAccounting=true</literal>. The
system default for this setting may be controlled with
<varname>DefaultTasksMax=</varname> in
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>

View file

@ -82,8 +82,8 @@
<listitem><para>hours, hour, hr, h</para></listitem>
<listitem><para>days, day, d</para></listitem>
<listitem><para>weeks, week, w</para></listitem>
<listitem><para>months, month</para></listitem>
<listitem><para>years, year, y</para></listitem>
<listitem><para>months, month, M (defined as 30.44 days)</para></listitem>
<listitem><para>years, year, y (define as 365.25 days)</para></listitem>
</itemizedlist>
<para>If no time unit is specified, generally seconds are assumed,

View file

@ -1423,12 +1423,16 @@ static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_sub
return n_old_qgroups;
r = btrfs_subvol_get_parent(fd, old_subvol_id, &old_parent_id);
if (r < 0)
if (r == -ENXIO)
/* We have no parent, hence nothing to copy. */
n_old_parent_qgroups = 0;
else if (r < 0)
return r;
n_old_parent_qgroups = btrfs_qgroup_find_parents(fd, old_parent_id, &old_parent_qgroups);
if (n_old_parent_qgroups < 0)
return n_old_parent_qgroups;
else {
n_old_parent_qgroups = btrfs_qgroup_find_parents(fd, old_parent_id, &old_parent_qgroups);
if (n_old_parent_qgroups < 0)
return n_old_parent_qgroups;
}
for (i = 0; i < n_old_qgroups; i++) {
uint64_t id;
@ -1885,14 +1889,19 @@ int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermed
if (n > 0) /* already parent qgroups set up, let's bail */
return 0;
r = btrfs_subvol_get_parent(fd, subvol_id, &parent_subvol);
if (r < 0)
return r;
qgroups = mfree(qgroups);
n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups);
if (n < 0)
return n;
r = btrfs_subvol_get_parent(fd, subvol_id, &parent_subvol);
if (r == -ENXIO)
/* No parent, hence no qgroup memberships */
n = 0;
else if (r < 0)
return r;
else {
n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups);
if (n < 0)
return n;
}
if (insert_intermediary_qgroup) {
uint64_t lowest = 256, new_qgroupid;

View file

@ -323,15 +323,15 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
const char *suffix;
usec_t usec;
} table[] = {
{ "y", USEC_PER_YEAR },
{ "month", USEC_PER_MONTH },
{ "w", USEC_PER_WEEK },
{ "d", USEC_PER_DAY },
{ "h", USEC_PER_HOUR },
{ "min", USEC_PER_MINUTE },
{ "s", USEC_PER_SEC },
{ "ms", USEC_PER_MSEC },
{ "us", 1 },
{ "y", USEC_PER_YEAR },
{ "month", USEC_PER_MONTH },
{ "w", USEC_PER_WEEK },
{ "d", USEC_PER_DAY },
{ "h", USEC_PER_HOUR },
{ "min", USEC_PER_MINUTE },
{ "s", USEC_PER_SEC },
{ "ms", USEC_PER_MSEC },
{ "us", 1 },
};
unsigned i;
@ -711,33 +711,34 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
const char *suffix;
usec_t usec;
} table[] = {
{ "seconds", USEC_PER_SEC },
{ "second", USEC_PER_SEC },
{ "sec", USEC_PER_SEC },
{ "s", USEC_PER_SEC },
{ "seconds", USEC_PER_SEC },
{ "second", USEC_PER_SEC },
{ "sec", USEC_PER_SEC },
{ "s", USEC_PER_SEC },
{ "minutes", USEC_PER_MINUTE },
{ "minute", USEC_PER_MINUTE },
{ "min", USEC_PER_MINUTE },
{ "months", USEC_PER_MONTH },
{ "month", USEC_PER_MONTH },
{ "msec", USEC_PER_MSEC },
{ "ms", USEC_PER_MSEC },
{ "m", USEC_PER_MINUTE },
{ "hours", USEC_PER_HOUR },
{ "hour", USEC_PER_HOUR },
{ "hr", USEC_PER_HOUR },
{ "h", USEC_PER_HOUR },
{ "days", USEC_PER_DAY },
{ "day", USEC_PER_DAY },
{ "d", USEC_PER_DAY },
{ "weeks", USEC_PER_WEEK },
{ "week", USEC_PER_WEEK },
{ "w", USEC_PER_WEEK },
{ "years", USEC_PER_YEAR },
{ "year", USEC_PER_YEAR },
{ "y", USEC_PER_YEAR },
{ "usec", 1ULL },
{ "us", 1ULL },
{ "minute", USEC_PER_MINUTE },
{ "min", USEC_PER_MINUTE },
{ "months", USEC_PER_MONTH },
{ "month", USEC_PER_MONTH },
{ "M", USEC_PER_MONTH },
{ "msec", USEC_PER_MSEC },
{ "ms", USEC_PER_MSEC },
{ "m", USEC_PER_MINUTE },
{ "hours", USEC_PER_HOUR },
{ "hour", USEC_PER_HOUR },
{ "hr", USEC_PER_HOUR },
{ "h", USEC_PER_HOUR },
{ "days", USEC_PER_DAY },
{ "day", USEC_PER_DAY },
{ "d", USEC_PER_DAY },
{ "weeks", USEC_PER_WEEK },
{ "week", USEC_PER_WEEK },
{ "w", USEC_PER_WEEK },
{ "years", USEC_PER_YEAR },
{ "year", USEC_PER_YEAR },
{ "y", USEC_PER_YEAR },
{ "usec", 1ULL },
{ "us", 1ULL },
};
const char *p, *s;

View file

@ -655,7 +655,18 @@ static int transient_unit_from_message(
if (r < 0)
return r;
if (u->load_state != UNIT_NOT_FOUND ||
/* Check if the unit already exists or is already referenced,
* in a number of different ways. Note that to cater for unit
* types such as slice, we are generally fine with units that
* are marked UNIT_LOADED even even though nothing was
* actually loaded, as those unit types don't require a file
* on disk to validly load. */
if (!IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_LOADED) ||
u->fragment_path ||
u->source_path ||
!strv_isempty(u->dropin_paths) ||
u->refs ||
set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0)
return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
@ -1960,6 +1971,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultLimitRTPRIO", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTasksMax", "t", NULL, offsetof(Manager, default_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),

View file

@ -126,7 +126,7 @@ $1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0,
$1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
$1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting)
$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context)
$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context.tasks_max)
$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)
$1.NetClass, config_parse_netclass, 0, offsetof($1, cgroup_context)'
)m4_dnl

View file

@ -2991,12 +2991,11 @@ int config_parse_tasks_max(
void *data,
void *userdata) {
CGroupContext *c = data;
uint64_t u;
uint64_t *tasks_max = data, u;
int r;
if (isempty(rvalue) || streq(rvalue, "infinity")) {
c->tasks_max = (uint64_t) -1;
*tasks_max = (uint64_t) -1;
return 0;
}
@ -3006,7 +3005,7 @@ int config_parse_tasks_max(
return 0;
}
c->tasks_max = u;
*tasks_max = u;
return 0;
}

View file

@ -125,7 +125,8 @@ static FILE* arg_serialization = NULL;
static bool arg_default_cpu_accounting = false;
static bool arg_default_blockio_accounting = false;
static bool arg_default_memory_accounting = false;
static bool arg_default_tasks_accounting = false;
static bool arg_default_tasks_accounting = true;
static uint64_t arg_default_tasks_max = UINT64_C(512);
static void pager_open_if_enabled(void) {
@ -657,7 +658,7 @@ static int parse_config_file(void) {
{ "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval },
{ "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
{ "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment },
{ "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU] },
{ "Manager", "DefaultLimitCPU", config_parse_sec_limit, 0, &arg_default_rlimit[RLIMIT_CPU] },
{ "Manager", "DefaultLimitFSIZE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] },
{ "Manager", "DefaultLimitDATA", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_DATA] },
{ "Manager", "DefaultLimitSTACK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_STACK] },
@ -672,11 +673,12 @@ static int parse_config_file(void) {
{ "Manager", "DefaultLimitMSGQUEUE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] },
{ "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] },
{ "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] },
{ "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] },
{ "Manager", "DefaultLimitRTTIME", config_parse_usec_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] },
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
{ "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting },
{ "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting },
{ "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting },
{ "Manager", "DefaultTasksMax", config_parse_tasks_max, 0, &arg_default_tasks_max },
{}
};
@ -712,6 +714,7 @@ static void manager_set_defaults(Manager *m) {
m->default_blockio_accounting = arg_default_blockio_accounting;
m->default_memory_accounting = arg_default_memory_accounting;
m->default_tasks_accounting = arg_default_tasks_accounting;
m->default_tasks_max = arg_default_tasks_max;
manager_set_default_rlimits(m, arg_default_rlimit);
manager_environment_add(m, NULL, arg_default_environment);

View file

@ -577,6 +577,8 @@ int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
m->running_as = running_as;
m->exit_code = _MANAGER_EXIT_CODE_INVALID;
m->default_timer_accuracy_usec = USEC_PER_MINUTE;
m->default_tasks_accounting = true;
m->default_tasks_max = UINT64_C(512);
/* Prepare log fields we can use for structured logging */
m->unit_log_field = unit_log_fields[running_as];

View file

@ -260,6 +260,7 @@ struct Manager {
bool default_blockio_accounting;
bool default_tasks_accounting;
uint64_t default_tasks_max;
usec_t default_timer_accuracy_usec;
struct rlimit *rlimit[_RLIMIT_MAX];

View file

@ -402,15 +402,10 @@ static bool scope_check_gc(Unit *u) {
/* Never clean up scopes that still have a process around,
* even if the scope is formally dead. */
if (u->cgroup_path) {
int r;
if (!u->cgroup_path)
return false;
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
if (r <= 0)
return true;
}
return false;
return cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path) <= 0;
}
static void scope_notify_cgroup_empty_event(Unit *u) {
@ -577,6 +572,7 @@ const UnitVTable scope_vtable = {
.no_alias = true,
.no_instances = true,
.can_transient = true,
.init = scope_init,
.load = scope_load,
@ -611,7 +607,5 @@ const UnitVTable scope_vtable = {
.bus_set_property = bus_scope_set_property,
.bus_commit_properties = bus_scope_commit_properties,
.can_transient = true,
.enumerate = scope_enumerate,
};

View file

@ -305,6 +305,7 @@ const UnitVTable slice_vtable = {
.no_alias = true,
.no_instances = true,
.can_transient = true,
.load = slice_load,

View file

@ -40,7 +40,8 @@
#DefaultCPUAccounting=no
#DefaultBlockIOAccounting=no
#DefaultMemoryAccounting=no
#DefaultTasksAccounting=no
#DefaultTasksAccounting=yes
#DefaultTasksMax=512
#DefaultLimitCPU=
#DefaultLimitFSIZE=
#DefaultLimitDATA=

View file

@ -132,6 +132,9 @@ static void unit_init(Unit *u) {
cc->blockio_accounting = u->manager->default_blockio_accounting;
cc->memory_accounting = u->manager->default_memory_accounting;
cc->tasks_accounting = u->manager->default_tasks_accounting;
if (u->type != UNIT_SLICE)
cc->tasks_max = u->manager->default_tasks_max;
}
ec = unit_get_exec_context(u);
@ -314,9 +317,6 @@ bool unit_check_gc(Unit *u) {
if (state != UNIT_INACTIVE)
return true;
if (UNIT_VTABLE(u)->no_gc)
return true;
if (u->no_gc)
return true;

View file

@ -403,9 +403,6 @@ struct UnitVTable {
/* Instances make no sense for this type */
bool no_instances:1;
/* Exclude from automatic gc */
bool no_gc:1;
/* True if transient units of this type are OK */
bool can_transient:1;
};

View file

@ -2753,13 +2753,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) {
@ -2827,6 +2915,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

@ -513,25 +513,31 @@ static int session_start_scope(Session *s) {
assert(s);
assert(s->user);
assert(s->user->slice);
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 {
@ -543,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_C(4096);
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=4096

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);

View file

@ -105,6 +105,10 @@ int register_machine(
return bus_log_create_error(r);
}
r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", 8192);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "strict");
if (r < 0)
return bus_log_create_error(r);

View file

@ -40,6 +40,16 @@ static int test_cgroup_mask(void) {
puts("manager_new: Permission denied. Skipping test.");
return EXIT_TEST_SKIP;
}
/* Turn off all kinds of default accouning, so that we can
* verify the masks resulting of our configuration and nothing
* else. */
m->default_cpu_accounting =
m->default_memory_accounting =
m->default_blockio_accounting =
m->default_tasks_accounting = false;
m->default_tasks_max = (uint64_t) -1;
assert_se(r >= 0);
assert_se(manager_startup(m, serial, fdset) >= 0);

View file

@ -20,6 +20,7 @@ RestartForceExitStatus=133
SuccessExitStatus=133
Slice=machine.slice
Delegate=yes
TasksMax=8192
# Enforce a strict device policy, similar to the one nspawn configures
# when it allocates its own scope unit. Make sure to keep these