summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/basic/btrfs-util.c49
-rw-r--r--src/basic/btrfs-util.h4
-rw-r--r--src/basic/time-util.c71
-rw-r--r--src/core/dbus-manager.c14
-rw-r--r--src/core/load-fragment-gperf.gperf.m42
-rw-r--r--src/core/load-fragment.c7
-rw-r--r--src/core/main.c9
-rw-r--r--src/core/manager.c2
-rw-r--r--src/core/manager.h1
-rw-r--r--src/core/scope.c14
-rw-r--r--src/core/slice.c1
-rw-r--r--src/core/system.conf3
-rw-r--r--src/core/unit.c6
-rw-r--r--src/core/unit.h3
-rw-r--r--src/login/logind-dbus.c94
-rw-r--r--src/login/logind-gperf.gperf1
-rw-r--r--src/login/logind-session.c26
-rw-r--r--src/login/logind-user.c54
-rw-r--r--src/login/logind.c1
-rw-r--r--src/login/logind.conf1
-rw-r--r--src/login/logind.h4
-rw-r--r--src/nspawn/nspawn-register.c4
-rw-r--r--src/test/test-cgroup-mask.c10
-rw-r--r--src/tmpfiles/tmpfiles.c24
24 files changed, 300 insertions, 105 deletions
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index 290fabdeff..be40dc5702 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -105,7 +105,7 @@ int btrfs_is_filesystem(int fd) {
return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
}
-int btrfs_is_subvol(int fd) {
+int btrfs_is_subvol_fd(int fd) {
struct stat st;
assert(fd >= 0);
@@ -121,6 +121,18 @@ int btrfs_is_subvol(int fd) {
return btrfs_is_filesystem(fd);
}
+int btrfs_is_subvol(const char *path) {
+ _cleanup_close_ int fd = -1;
+
+ assert(path);
+
+ fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (fd < 0)
+ return -errno;
+
+ return btrfs_is_subvol_fd(fd);
+}
+
int btrfs_subvol_make(const char *path) {
struct btrfs_ioctl_vol_args args = {};
_cleanup_close_ int fd = -1;
@@ -1423,12 +1435,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;
@@ -1682,7 +1698,7 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag
assert(old_fd >= 0);
assert(new_path);
- r = btrfs_is_subvol(old_fd);
+ r = btrfs_is_subvol_fd(old_fd);
if (r < 0)
return r;
if (r == 0) {
@@ -1868,7 +1884,7 @@ int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermed
*/
if (subvol_id == 0) {
- r = btrfs_is_subvol(fd);
+ r = btrfs_is_subvol_fd(fd);
if (r < 0)
return r;
if (!r)
@@ -1885,14 +1901,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/btrfs-util.h b/src/basic/btrfs-util.h
index fc9efd72d5..8c11ce35d2 100644
--- a/src/basic/btrfs-util.h
+++ b/src/basic/btrfs-util.h
@@ -56,7 +56,9 @@ typedef enum BtrfsRemoveFlags {
} BtrfsRemoveFlags;
int btrfs_is_filesystem(int fd);
-int btrfs_is_subvol(int fd);
+
+int btrfs_is_subvol_fd(int fd);
+int btrfs_is_subvol(const char *path);
int btrfs_reflink(int infd, int outfd);
int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz);
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/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 74b6b91593..f9a759e223 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -1226,8 +1226,28 @@ static int create_item(Item *i) {
mkdir_parents_label(i->path, 0755);
if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) {
- RUN_WITH_UMASK((~i->mode) & 0777)
- r = btrfs_subvol_make(i->path);
+
+ if (btrfs_is_subvol(isempty(arg_root) ? "/" : arg_root) <= 0)
+
+ /* Don't create a subvolume unless the
+ * root directory is one, too. We do
+ * this under the assumption that if
+ * the root directory is just a plain
+ * directory (i.e. very light-weight),
+ * we shouldn't try to split it up
+ * into subvolumes (i.e. more
+ * heavy-weight). Thus, chroot()
+ * environments and suchlike will get
+ * a full brtfs subvolume set up below
+ * their tree only if they
+ * specifically set up a btrfs
+ * subvolume for the root dir too. */
+
+ r = -ENOTTY;
+ else {
+ RUN_WITH_UMASK((~i->mode) & 0777)
+ r = btrfs_subvol_make(i->path);
+ }
} else
r = 0;