diff options
author | David Herrmann <dh.herrmann@googlemail.com> | 2015-11-16 15:09:55 +0100 |
---|---|---|
committer | David Herrmann <dh.herrmann@googlemail.com> | 2015-11-16 15:09:55 +0100 |
commit | 44690833dfadb523c1f9b6a9e6e1dced44f374e1 (patch) | |
tree | 825ddf05390264473ceda190b668f3d501094d5c | |
parent | e25b5a8d7380a86ea717b4038c45a8f882b1a2ae (diff) | |
parent | 541ec33075f9f2461b5286592312d2b50295ad32 (diff) |
Merge pull request #1886 from poettering/tasks-max
Enable TasksMax by default for all units
-rw-r--r-- | man/logind.conf.xml | 15 | ||||
-rw-r--r-- | man/systemd-system.conf.xml | 17 | ||||
-rw-r--r-- | man/systemd.resource-control.xml | 5 | ||||
-rw-r--r-- | man/systemd.time.xml | 4 | ||||
-rw-r--r-- | src/basic/btrfs-util.c | 31 | ||||
-rw-r--r-- | src/basic/time-util.c | 71 | ||||
-rw-r--r-- | src/core/dbus-manager.c | 14 | ||||
-rw-r--r-- | src/core/load-fragment-gperf.gperf.m4 | 2 | ||||
-rw-r--r-- | src/core/load-fragment.c | 7 | ||||
-rw-r--r-- | src/core/main.c | 9 | ||||
-rw-r--r-- | src/core/manager.c | 2 | ||||
-rw-r--r-- | src/core/manager.h | 1 | ||||
-rw-r--r-- | src/core/scope.c | 14 | ||||
-rw-r--r-- | src/core/slice.c | 1 | ||||
-rw-r--r-- | src/core/system.conf | 3 | ||||
-rw-r--r-- | src/core/unit.c | 6 | ||||
-rw-r--r-- | src/core/unit.h | 3 | ||||
-rw-r--r-- | src/login/logind-dbus.c | 94 | ||||
-rw-r--r-- | src/login/logind-gperf.gperf | 1 | ||||
-rw-r--r-- | src/login/logind-session.c | 26 | ||||
-rw-r--r-- | src/login/logind-user.c | 54 | ||||
-rw-r--r-- | src/login/logind.c | 1 | ||||
-rw-r--r-- | src/login/logind.conf | 1 | ||||
-rw-r--r-- | src/login/logind.h | 4 | ||||
-rw-r--r-- | src/nspawn/nspawn-register.c | 4 | ||||
-rw-r--r-- | src/test/test-cgroup-mask.c | 10 | ||||
-rw-r--r-- | units/systemd-nspawn@.service.in | 1 |
27 files changed, 295 insertions, 106 deletions
diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 43d1ffbd3c..94376656d5 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -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> diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml index 54ce992b85..ead52951da 100644 --- a/man/systemd-system.conf.xml +++ b/man/systemd-system.conf.xml @@ -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> diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 0497f60546..b1106c759d 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -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> diff --git a/man/systemd.time.xml b/man/systemd.time.xml index 135eb35f1b..a6fcc95e4c 100644 --- a/man/systemd.time.xml +++ b/man/systemd.time.xml @@ -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, diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index 290fabdeff..8c2d76b8aa 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -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; + qgroups = mfree(qgroups); + r = btrfs_subvol_get_parent(fd, subvol_id, &parent_subvol); - if (r < 0) + if (r == -ENXIO) + /* No parent, hence no qgroup memberships */ + n = 0; + else if (r < 0) return r; - - qgroups = mfree(qgroups); - n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups); - if (n < 0) - return n; + 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; diff --git a/src/basic/time-util.c b/src/basic/time-util.c index b36fbe4f09..647763a230 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -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; diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index d3bcc795ae..67e4e8b218 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -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), diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 4c5376d601..799418033d 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -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 diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 62cad0a0c0..5d013de2e8 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -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; } diff --git a/src/core/main.c b/src/core/main.c index 33529c3e76..a09ce0f083 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -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); diff --git a/src/core/manager.c b/src/core/manager.c index f695b8a66c..edff6758c5 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -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]; diff --git a/src/core/manager.h b/src/core/manager.h index bc3f02f872..b5b258f909 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -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]; diff --git a/src/core/scope.c b/src/core/scope.c index 5f6527c155..1953af1f88 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -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, }; diff --git a/src/core/slice.c b/src/core/slice.c index 39dabae055..9c488f0fd7 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -305,6 +305,7 @@ const UnitVTable slice_vtable = { .no_alias = true, .no_instances = true, + .can_transient = true, .load = slice_load, diff --git a/src/core/system.conf b/src/core/system.conf index 50668e12c4..e2ded27333 100644 --- a/src/core/system.conf +++ b/src/core/system.conf @@ -40,7 +40,8 @@ #DefaultCPUAccounting=no #DefaultBlockIOAccounting=no #DefaultMemoryAccounting=no -#DefaultTasksAccounting=no +#DefaultTasksAccounting=yes +#DefaultTasksMax=512 #DefaultLimitCPU= #DefaultLimitFSIZE= #DefaultLimitDATA= diff --git a/src/core/unit.c b/src/core/unit.c index f553f24829..d199d87bf8 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -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; diff --git a/src/core/unit.h b/src/core/unit.h index 14e3072146..bcf41d2348 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -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; }; diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 5cc90c6e24..7cc0044bab 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -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; diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf index 9218d098e0..8552c464cc 100644 --- a/src/login/logind-gperf.gperf +++ b/src/login/logind-gperf.gperf @@ -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) diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 1d561a6f8a..6c4ada29fb 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -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; } diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 56bc5a010c..7bdbe6583c 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -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; - - r = manager_start_unit(u->manager, slice, &error, &job); + return log_error_errno(r, "Failed to build slice name: %m"); + + 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; } diff --git a/src/login/logind.c b/src/login/logind.c index be6bbe5b5c..7b41174c64 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -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); diff --git a/src/login/logind.conf b/src/login/logind.conf index 6df6f04c77..81f6695434 100644 --- a/src/login/logind.conf +++ b/src/login/logind.conf @@ -32,3 +32,4 @@ #IdleActionSec=30min #RuntimeDirectorySize=10% #RemoveIPC=yes +#UserTasksMax=4096 diff --git a/src/login/logind.h b/src/login/logind.h index 44e05d8b01..f34544e64c 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -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); diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c index 374f958c20..50871464c5 100644 --- a/src/nspawn/nspawn-register.c +++ b/src/nspawn/nspawn-register.c @@ -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); diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index de6c421b82..85b0d607d6 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -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); diff --git a/units/systemd-nspawn@.service.in b/units/systemd-nspawn@.service.in index 2e79adff44..eb10343ac6 100644 --- a/units/systemd-nspawn@.service.in +++ b/units/systemd-nspawn@.service.in @@ -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 |