From 1713813de365486617ab87899f950e9b6ec928ef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2011 20:41:56 +0200 Subject: [PATCH] logind: remove a session when its cgroup is gone --- src/logind-dbus.c | 30 ++++++++++++++++++++++++++++++ src/logind-session.c | 7 +++++++ src/logind.c | 38 ++++++++++++++++++++++++++++++++------ src/logind.h | 8 +++++++- 4 files changed, 76 insertions(+), 7 deletions(-) diff --git a/src/logind-dbus.c b/src/logind-dbus.c index 2a857494..0f3de41f 100644 --- a/src/logind-dbus.c +++ b/src/logind-dbus.c @@ -896,6 +896,36 @@ const DBusObjectPathVTable bus_manager_vtable = { .message_function = manager_message_handler }; +DBusHandlerResult bus_message_filter( + DBusConnection *connection, + DBusMessage *message, + void *userdata) { + + Manager *m = userdata; + DBusError error; + + assert(m); + assert(connection); + assert(message); + + dbus_error_init(&error); + + if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) { + const char *cgroup; + + if (!dbus_message_get_args(message, &error, + DBUS_TYPE_STRING, &cgroup, + DBUS_TYPE_INVALID)) + log_error("Failed to parse Released message: %s", bus_error_message(&error)); + else + manager_cgroup_notify_empty(m, cgroup); + } + + dbus_error_free(&error); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + int manager_send_changed(Manager *manager, const char *properties) { DBusMessage *m; int r = -ENOMEM; diff --git a/src/logind-session.c b/src/logind-session.c index 74f8ad1b..9278f307 100644 --- a/src/logind-session.c +++ b/src/logind-session.c @@ -83,6 +83,9 @@ void session_free(Session *s) { LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s); } + if (s->cgroup_path) + hashmap_remove(s->manager->cgroups, s->cgroup_path); + free(s->cgroup_path); strv_free(s->controllers); @@ -468,6 +471,8 @@ static int session_create_cgroup(Session *s) { } } + hashmap_put(s->manager->cgroups, s->cgroup_path, s); + return 0; } @@ -562,6 +567,8 @@ static int session_kill_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); + free(s->cgroup_path); s->cgroup_path = NULL; diff --git a/src/logind.c b/src/logind.c index cdb4da7f..2665ab91 100644 --- a/src/logind.c +++ b/src/logind.c @@ -56,6 +56,7 @@ 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->cgroups = hashmap_new(string_hash_func, string_compare_func); if (!m->devices || !m->seats || !m->sessions || !m->users) { manager_free(m); @@ -100,6 +101,7 @@ void manager_free(Manager *m) { hashmap_free(m->users); hashmap_free(m->devices); hashmap_free(m->seats); + hashmap_free(m->cgroups); if (m->console_active_fd >= 0) close_nointr_nofail(m->console_active_fd); @@ -682,12 +684,34 @@ int manager_spawn_autovt(Manager *m, int vtnr) { return 0; } -static DBusHandlerResult login_message_filter( - DBusConnection *connection, - DBusMessage *message, - void *userdata) { +void manager_cgroup_notify_empty(Manager *m, const char *cgroup) { + Session *s; + char *p; + + assert(m); + assert(cgroup); + + p = strdup(cgroup); + if (!p) { + log_error("Out of memory."); + return; + } + + for (;;) { + char *e; - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + if (isempty(p) || streq(p, "/")) + break; + + s = hashmap_get(m->cgroups, p); + if (s) + session_add_to_gc_queue(s); + + assert_se(e = strrchr(p, '/')); + *e = 0; + } + + free(p); } static int manager_connect_bus(Manager *m) { @@ -712,7 +736,7 @@ static int manager_connect_bus(Manager *m) { !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/seat", &bus_seat_vtable, m) || !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) || !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) || - !dbus_connection_add_filter(m->bus, login_message_filter, m, NULL)) { + !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) { log_error("Not enough memory"); r = -ENOMEM; goto fail; @@ -958,6 +982,8 @@ int manager_run(Manager *m) { if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE) continue; + manager_gc(m); + n = epoll_wait(m->epoll_fd, &event, 1, -1); if (n < 0) { if (errno == EINTR || errno == EAGAIN) diff --git a/src/logind.h b/src/logind.h index 22eab556..d8674e75 100644 --- a/src/logind.h +++ b/src/logind.h @@ -37,7 +37,7 @@ * recreate VTs when disallocated * spawn user systemd * direct client API - * subscribe to cgroup changes, fd HUP + * subscribe to fd HUP * D-Bus method: AttachDevice(seat, device); * D-Bus method: PermitLinger(user, bool b); * @@ -84,6 +84,8 @@ struct Manager { bool kill_user_processes; unsigned long session_counter; + + Hashmap *cgroups; }; Manager *manager_new(void); @@ -109,6 +111,8 @@ int manager_startup(Manager *m); int manager_run(Manager *m); int manager_spawn_autovt(Manager *m, int vtnr); +void manager_cgroup_notify_empty(Manager *m, const char *cgroup); + void manager_gc(Manager *m); int manager_get_idle_hint(Manager *m, dual_timestamp *t); @@ -117,6 +121,8 @@ bool x11_display_is_local(const char *display); extern const DBusObjectPathVTable bus_manager_vtable; +DBusHandlerResult bus_message_filter(DBusConnection *c, DBusMessage *message, void *userdata); + int manager_send_changed(Manager *manager, const char *properties); #endif -- 2.39.5