chiark / gitweb /
core: general cgroup rework
[elogind.git] / src / login / logind-user.c
index b692b533e25f0341dd7f8fc0c02a1c51b9dc31b1..9f7b924a243a9720f1d605af4c7d0d46487a445c 100644 (file)
@@ -29,6 +29,8 @@
 #include "cgroup-util.h"
 #include "hashmap.h"
 #include "strv.h"
+#include "fileio.h"
+#include "special.h"
 
 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
         User *u;
@@ -41,29 +43,27 @@ User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
                 return NULL;
 
         u->name = strdup(name);
-        if (!u->name) {
-                free(u);
-                return NULL;
-        }
+        if (!u->name)
+                goto fail;
 
-        if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0) {
-                free(u->name);
-                free(u);
-                return NULL;
-        }
+        if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
+                goto fail;
 
-        if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0) {
-                free(u->state_file);
-                free(u->name);
-                free(u);
-                return NULL;
-        }
+        if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0)
+                goto fail;
 
         u->manager = m;
         u->uid = uid;
         u->gid = gid;
 
         return u;
+
+fail:
+        free(u->state_file);
+        free(u->name);
+        free(u);
+
+        return NULL;
 }
 
 void user_free(User *u) {
@@ -75,9 +75,10 @@ void user_free(User *u) {
         while (u->sessions)
                 session_free(u->sessions);
 
-        if (u->cgroup_path)
+        if (u->cgroup_path) {
                 hashmap_remove(u->manager->user_cgroups, u->cgroup_path);
-        free(u->cgroup_path);
+                free(u->cgroup_path);
+        }
 
         free(u->service);
         free(u->runtime_path);
@@ -86,13 +87,14 @@ void user_free(User *u) {
 
         free(u->name);
         free(u->state_file);
+        free(u->slice);
         free(u);
 }
 
 int user_save(User *u) {
-        FILE *f;
+        _cleanup_free_ char *temp_path = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
         int r;
-        char *temp_path;
 
         assert(u);
         assert(u->state_file);
@@ -118,24 +120,26 @@ int user_save(User *u) {
                 user_state_to_string(user_get_state(u)));
 
         if (u->cgroup_path)
-                fprintf(f,
-                        "CGROUP=%s\n",
-                        u->cgroup_path);
+                fprintf(f, "CGROUP=%s\n", u->cgroup_path);
 
         if (u->runtime_path)
-                fprintf(f,
-                        "RUNTIME=%s\n",
-                        u->runtime_path);
+                fprintf(f, "RUNTIME=%s\n", u->runtime_path);
 
         if (u->service)
-                fprintf(f,
-                        "SERVICE=%s\n",
-                        u->service);
+                fprintf(f, "SERVICE=%s\n", u->service);
+
+        if (u->slice)
+                fprintf(f, "SLICE=%s\n", u->slice);
 
         if (u->display)
+                fprintf(f, "DISPLAY=%s\n", u->display->id);
+
+        if (dual_timestamp_is_set(&u->timestamp))
                 fprintf(f,
-                        "DISPLAY=%s\n",
-                        u->display->id);
+                        "REALTIME=%llu\n"
+                        "MONOTONIC=%llu\n",
+                        (unsigned long long) u->timestamp.realtime,
+                        (unsigned long long) u->timestamp.monotonic);
 
         if (u->sessions) {
                 Session *i;
@@ -232,9 +236,6 @@ int user_save(User *u) {
                 unlink(temp_path);
         }
 
-        fclose(f);
-        free(temp_path);
-
 finish:
         if (r < 0)
                 log_error("Failed to save user data for %s: %s", u->name, strerror(-r));
@@ -243,21 +244,22 @@ finish:
 }
 
 int user_load(User *u) {
-        int r;
-        char *display = NULL;
+        _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
         Session *s = NULL;
+        int r;
 
         assert(u);
 
         r = parse_env_file(u->state_file, NEWLINE,
-                           "CGROUP", &u->cgroup_path,
-                           "RUNTIME", &u->runtime_path,
-                           "SERVICE", &u->service,
-                           "DISPLAY", &display,
+                           "CGROUP",    &u->cgroup_path,
+                           "RUNTIME",   &u->runtime_path,
+                           "SERVICE",   &u->service,
+                           "DISPLAY",   &display,
+                           "SLICE",     &u->slice,
+                           "REALTIME",  &realtime,
+                           "MONOTONIC", &monotonic,
                            NULL);
         if (r < 0) {
-                free(display);
-
                 if (r == -ENOENT)
                         return 0;
 
@@ -265,14 +267,24 @@ int user_load(User *u) {
                 return r;
         }
 
-        if (display) {
+        if (display)
                 s = hashmap_get(u->manager->sessions, display);
-                free(display);
-        }
 
         if (s && s->display && display_is_local(s->display))
                 u->display = s;
 
+        if (realtime) {
+                unsigned long long l;
+                if (sscanf(realtime, "%llu", &l) > 0)
+                        u->timestamp.realtime = l;
+        }
+
+        if (monotonic) {
+                unsigned long long l;
+                if (sscanf(monotonic, "%llu", &l) > 0)
+                        u->timestamp.monotonic = l;
+        }
+
         return r;
 }
 
@@ -308,35 +320,49 @@ static int user_mkdir_runtime_path(User *u) {
 
 static int user_create_cgroup(User *u) {
         char **k;
-        char *p;
         int r;
 
         assert(u);
 
+        if (!u->slice) {
+                u->slice = strdup(SPECIAL_USER_SLICE);
+                if (!u->slice)
+                        return log_oom();
+        }
+
         if (!u->cgroup_path) {
-                if (asprintf(&p, "%s/%s", u->manager->cgroup_path, u->name) < 0)
+                _cleanup_free_ char *name = NULL, *escaped = NULL, *slice = NULL;
+
+                if (asprintf(&name, "%lu.user", (unsigned long) u->uid) < 0)
                         return log_oom();
-        } else
-                p = u->cgroup_path;
 
-        r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p);
+                escaped = cg_escape(name);
+                if (!escaped)
+                        return log_oom();
+
+                r = cg_slice_to_path(u->slice, &slice);
+                if (r < 0)
+                        return r;
+
+                u->cgroup_path = strjoin(u->manager->cgroup_root, "/", slice, "/", escaped, NULL);
+                if (!u->cgroup_path)
+                        return log_oom();
+        }
+
+        r = cg_create(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
         if (r < 0) {
-                log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
-                free(p);
-                u->cgroup_path = NULL;
+                log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", u->cgroup_path, strerror(-r));
                 return r;
         }
 
-        u->cgroup_path = p;
-
         STRV_FOREACH(k, u->manager->controllers) {
 
                 if (strv_contains(u->manager->reset_controllers, *k))
                         continue;
 
-                r = cg_create(*k, p);
+                r = cg_create(*k, u->cgroup_path);
                 if (r < 0)
-                        log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r));
+                        log_warning("Failed to create cgroup %s:%s: %s", *k, u->cgroup_path, strerror(-r));
         }
 
         r = hashmap_put(u->manager->user_cgroups, u->cgroup_path, u);
@@ -379,7 +405,8 @@ int user_start(User *u) {
         if (r < 0)
                 return r;
 
-        dual_timestamp_get(&u->timestamp);
+        if (!dual_timestamp_is_set(&u->timestamp))
+                dual_timestamp_get(&u->timestamp);
 
         u->started = true;
 
@@ -622,8 +649,8 @@ UserState user_get_state(User *u) {
 }
 
 int user_kill(User *u, int signo) {
-        int r = 0, q;
-        Set *pid_set = NULL;
+        _cleanup_set_free_ Set *pid_set = NULL;
+        int r;
 
         assert(u);
 
@@ -634,15 +661,11 @@ int user_kill(User *u, int signo) {
         if (!pid_set)
                 return -ENOMEM;
 
-        q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
-        if (q < 0)
-                if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
-                        r = q;
-
-        if (pid_set)
-                set_free(pid_set);
+        r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
+        if (r < 0 && (r != -EAGAIN && r != -ESRCH && r != -ENOENT))
+                return r;
 
-        return r;
+        return 0;
 }
 
 static const char* const user_state_table[_USER_STATE_MAX] = {