diff options
author | Lennart Poettering <lennart@poettering.net> | 2012-05-31 19:46:42 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2012-05-31 19:46:42 +0200 |
commit | 8c8c43515cee56dfc2298998a9e5958308c46f99 (patch) | |
tree | 3d7f891b8478df86683058b9a0e160c69b5c6c8b | |
parent | 952d817a41dfe207d159f8278f4d7f1f7654c572 (diff) |
logind: properly clean up user cgroups when they run empty
-rw-r--r-- | src/login/logind-session.c | 6 | ||||
-rw-r--r-- | src/login/logind-user.c | 6 | ||||
-rw-r--r-- | src/login/logind.c | 65 | ||||
-rw-r--r-- | src/login/logind.h | 5 |
4 files changed, 70 insertions, 12 deletions
diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 5c8d54931..58514ea0d 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -85,13 +85,13 @@ void session_free(Session *s) { s->seat->active = NULL; LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s); } if (s->cgroup_path) - hashmap_remove(s->manager->cgroups, s->cgroup_path); + hashmap_remove(s->manager->session_cgroups, s->cgroup_path); free(s->cgroup_path); strv_free(s->controllers); free(s->tty); free(s->display); @@ -524,13 +524,13 @@ static int session_create_cgroup(Session *s) { if (r < 0) log_warning("Failed to reset controller %s: %s", *k, strerror(-r)); } } - hashmap_put(s->manager->cgroups, s->cgroup_path, s); + hashmap_put(s->manager->session_cgroups, s->cgroup_path, s); return 0; } int session_start(Session *s) { int r; @@ -643,13 +643,13 @@ static int session_terminate_cgroup(Session *s) { } } STRV_FOREACH(k, s->user->manager->controllers) cg_trim(*k, s->cgroup_path, true); - hashmap_remove(s->manager->cgroups, s->cgroup_path); + hashmap_remove(s->manager->session_cgroups, s->cgroup_path); free(s->cgroup_path); s->cgroup_path = NULL; return 0; } diff --git a/src/login/logind-user.c b/src/login/logind-user.c index b971845e1..8bd773086 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -72,12 +72,14 @@ void user_free(User *u) { if (u->in_gc_queue) LIST_REMOVE(User, gc_queue, u->manager->user_gc_queue, u); while (u->sessions) session_free(u->sessions); + if (u->cgroup_path) + hashmap_remove(u->manager->user_cgroups, u->cgroup_path); free(u->cgroup_path); free(u->service); free(u->runtime_path); hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid)); @@ -310,12 +312,14 @@ static int user_create_cgroup(User *u) { r = cg_create(*k, p); if (r < 0) log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r)); } + hashmap_put(u->manager->user_cgroups, u->cgroup_path, u); + return 0; } static int user_start_service(User *u) { assert(u); @@ -414,12 +418,14 @@ static int user_terminate_cgroup(User *u) { r = -EBUSY; } STRV_FOREACH(k, u->manager->controllers) cg_trim(*k, u->cgroup_path, true); + hashmap_remove(u->manager->user_cgroups, u->cgroup_path); + free(u->cgroup_path); u->cgroup_path = NULL; return r; } diff --git a/src/login/logind.c b/src/login/logind.c index 632987c8b..62f7914fe 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -61,19 +61,22 @@ Manager *manager_new(void) { m->seats = hashmap_new(string_hash_func, string_compare_func); m->sessions = hashmap_new(string_hash_func, string_compare_func); m->users = hashmap_new(trivial_hash_func, trivial_compare_func); m->inhibitors = hashmap_new(string_hash_func, string_compare_func); m->buttons = hashmap_new(string_hash_func, string_compare_func); - m->cgroups = hashmap_new(string_hash_func, string_compare_func); + m->user_cgroups = hashmap_new(string_hash_func, string_compare_func); + m->session_cgroups = hashmap_new(string_hash_func, string_compare_func); + m->session_fds = hashmap_new(trivial_hash_func, trivial_compare_func); m->inhibitor_fds = hashmap_new(trivial_hash_func, trivial_compare_func); m->button_fds = hashmap_new(trivial_hash_func, trivial_compare_func); if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || - !m->cgroups || !m->session_fds || !m->inhibitor_fds || !m->button_fds) { + !m->user_cgroups || !m->session_cgroups || + !m->session_fds || !m->inhibitor_fds || !m->button_fds) { manager_free(m); return NULL; } m->reset_controllers = strv_new("cpu", NULL); m->kill_exclude_users = strv_new("root", NULL); @@ -128,13 +131,15 @@ void manager_free(Manager *m) { hashmap_free(m->seats); hashmap_free(m->sessions); hashmap_free(m->users); hashmap_free(m->inhibitors); hashmap_free(m->buttons); - hashmap_free(m->cgroups); + hashmap_free(m->user_cgroups); + hashmap_free(m->session_cgroups); + hashmap_free(m->session_fds); hashmap_free(m->inhibitor_fds); hashmap_free(m->button_fds); if (m->console_active_fd >= 0) close_nointr_nofail(m->console_active_fd); @@ -1005,13 +1010,13 @@ int manager_get_session_by_cgroup(Manager *m, const char *cgroup, Session **sess char *p; assert(m); assert(cgroup); assert(session); - s = hashmap_get(m->cgroups, cgroup); + s = hashmap_get(m->session_cgroups, cgroup); if (s) { *session = s; return 1; } p = strdup(cgroup); @@ -1029,21 +1034,62 @@ int manager_get_session_by_cgroup(Manager *m, const char *cgroup, Session **sess *session = NULL; return 0; } *e = 0; - s = hashmap_get(m->cgroups, p); + s = hashmap_get(m->session_cgroups, p); if (s) { free(p); *session = s; return 1; } } } +int manager_get_user_by_cgroup(Manager *m, const char *cgroup, User **user) { + User *u; + char *p; + + assert(m); + assert(cgroup); + assert(user); + + u = hashmap_get(m->user_cgroups, cgroup); + if (u) { + *user = u; + return 1; + } + + p = strdup(cgroup); + if (!p) { + log_error("Out of memory."); + return -ENOMEM; + } + + for (;;) { + char *e; + + e = strrchr(p, '/'); + if (!e || e == p) { + free(p); + *user = NULL; + return 0; + } + + *e = 0; + + u = hashmap_get(m->user_cgroups, p); + if (u) { + free(p); + *user = u; + return 1; + } + } +} + int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) { char *p; int r; assert(m); assert(pid >= 1); @@ -1058,19 +1104,22 @@ int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) { return r; } void manager_cgroup_notify_empty(Manager *m, const char *cgroup) { Session *s; + User *u; int r; r = manager_get_session_by_cgroup(m, cgroup, &s); - if (r <= 0) - return; + if (r > 0) + session_add_to_gc_queue(s); - session_add_to_gc_queue(s); + r = manager_get_user_by_cgroup(m, cgroup, &u); + if (r > 0) + user_add_to_gc_queue(u); } static void manager_dispatch_other(Manager *m, int fd) { Session *s; Inhibitor *i; Button *b; diff --git a/src/login/logind.h b/src/login/logind.h index 6fcef6f31..5e828bf01 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -78,13 +78,15 @@ struct Manager { bool kill_user_processes; unsigned long session_counter; unsigned long inhibit_counter; - Hashmap *cgroups; + Hashmap *session_cgroups; + Hashmap *user_cgroups; + Hashmap *session_fds; Hashmap *inhibitor_fds; Hashmap *button_fds; /* If a shutdown was delayed due to a inhibitor this contains the unit name we are supposed to start after the delay is @@ -143,12 +145,13 @@ int manager_spawn_autovt(Manager *m, int vtnr); void manager_cgroup_notify_empty(Manager *m, const char *cgroup); void manager_gc(Manager *m, bool drop_not_started); int manager_get_idle_hint(Manager *m, dual_timestamp *t); +int manager_get_user_by_cgroup(Manager *m, const char *cgroup, User **user); int manager_get_session_by_cgroup(Manager *m, const char *cgroup, Session **session); int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session); extern const DBusObjectPathVTable bus_manager_vtable; DBusHandlerResult bus_message_filter(DBusConnection *c, DBusMessage *message, void *userdata); |