diff options
author | Andy Wingo <wingo@pobox.com> | 2016-03-06 16:02:31 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2016-03-06 16:02:31 +0100 |
commit | 162255186046fa7a5e82859b7dba5a7909ce6fc4 (patch) | |
tree | 8b81f2e7afac4df45ebca6e662d4d2b1d8635e5a /src/login | |
parent | 6f5035f2db6ab7b4beae46c44b95e6a8b6d956b5 (diff) |
Classify processes from sessions into cgroups
Create a private cgroup tree associated with no controllers, and use it
to map PIDs to sessions. Since we use our own path structure, remove
internal cgroup-related helpers that interpret the cgroup path structure
to pull out users, slices, and scopes.
Diffstat (limited to 'src/login')
-rw-r--r-- | src/login/logind-core.c | 33 | ||||
-rw-r--r-- | src/login/logind-session.c | 69 | ||||
-rw-r--r-- | src/login/logind-user.c | 12 | ||||
-rw-r--r-- | src/login/logind.c | 36 |
4 files changed, 136 insertions, 14 deletions
diff --git a/src/login/logind-core.c b/src/login/logind-core.c index 67b03623ac..041593c5ab 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -311,24 +311,41 @@ int manager_process_button_device(Manager *m, struct udev_device *d) { } int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) { + _cleanup_free_ char *session_name = NULL; + Session *s; + int r; + assert(m); assert(session); - /* Without cgroups, we have no way to map from pid to - session. */ - return 0; + if (pid < 1) + return -EINVAL; + + r = cg_pid_get_session(pid, &session_name); + if (r < 0) + return 0; + + s = hashmap_get(m->sessions, session_name); + if (!s) + return 0; + + *session = s; + return 1; } int manager_get_user_by_pid(Manager *m, pid_t pid, User **user) { + Session *s; + int r; + assert(m); assert(user); - if (pid < 1) - return -EINVAL; + r = manager_get_session_by_pid (m, pid, &s); + if (r <= 0) + return r; - /* Without cgroups, we have no way to map from pid to - user. */ - return 0; + *user = s->user; + return 1; } int manager_get_idle_hint(Manager *m, dual_timestamp *t) { diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 109e3ef133..f03c2e565d 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -36,6 +36,8 @@ #include "audit.h" #include "bus-util.h" #include "bus-error.h" +#include "cgroup-util.h" +#include "def.h" #include "logind-session.h" static void session_remove_fifo(Session *s); @@ -475,6 +477,25 @@ int session_activate(Session *s) { return 0; } +static int session_start_cgroup(Session *s) { + int r; + + assert(s); + assert(s->user); + assert(s->leader > 0); + + /* First, create our own group */ + r = cg_create(SYSTEMD_CGROUP_CONTROLLER, s->id); + if (r < 0) + return log_error_errno(r, "Failed to create cgroup %s: %m", s->id); + + r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, s->id, s->leader); + if (r < 0) + log_warning_errno(r, "Failed to attach PID %d to cgroup %s: %m", s->leader, s->id); + + return 0; +} + int session_start(Session *s) { int r; @@ -490,6 +511,10 @@ int session_start(Session *s) { if (r < 0) return r; + r = session_start_cgroup(s); + if (r < 0) + return r; + log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO, LOG_MESSAGE_ID(SD_MESSAGE_SESSION_START), "SESSION_ID=%s", s->id, @@ -527,8 +552,23 @@ int session_start(Session *s) { return 0; } +static int session_stop_cgroup(Session *s, bool force) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(s); + + if (force || manager_shall_kill(s->manager, s->user->name)) { + r = session_kill(s, KILL_ALL, SIGTERM); + if (r < 0) + return r; + } + + return 0; +} + int session_stop(Session *s, bool force) { - int r = 0; + int r; assert(s); @@ -540,6 +580,9 @@ int session_stop(Session *s, bool force) { /* We are going down, don't care about FIFOs anymore */ session_remove_fifo(s); + /* Kill cgroup */ + r = session_stop_cgroup(s, force); + s->stopping = true; user_elect_display(s->user); @@ -609,7 +652,7 @@ int session_release(Session *s) { /* In systemd, session release is triggered by user jobs dying. In elogind we don't have that so go ahead and stop now. */ - session_stop(s, false); + return session_stop(s, false); } bool session_is_active(Session *s) { @@ -814,6 +857,9 @@ bool session_check_gc(Session *s, bool drop_not_started) { return true; } + if (cg_is_empty_recursive (SYSTEMD_CGROUP_CONTROLLER, s->id, false) > 0) + return true; + return false; } @@ -846,8 +892,23 @@ SessionState session_get_state(Session *s) { int session_kill(Session *s, KillWho who, int signo) { assert(s); - /* No way to kill the session without cgroups. */ - return -ESRCH; + if (who == KILL_LEADER) { + if (s->leader <= 0) + return -ESRCH; + + /* FIXME: verify that leader is in cgroup? */ + + if (kill(s->leader, signo) < 0) { + return log_error_errno(errno, "Failed to kill process leader %d for session %s: %m", s->leader, s->id); + } + return 0; + } else { + bool sigcont = false; + bool ignore_self = true; + bool rem = true; + return cg_kill_recursive (SYSTEMD_CGROUP_CONTROLLER, s->id, signo, + sigcont, ignore_self, rem, NULL); + } } static int session_open_vt(Session *s) { diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 539c316ad6..0aac3bcf52 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -562,10 +562,18 @@ UserState user_get_state(User *u) { } int user_kill(User *u, int signo) { + Session *s; + int res = 0; + assert(u); - /* FIXME: No way to kill a user without systemd. */ - return -ESRCH; + LIST_FOREACH(sessions_by_user, s, u->sessions) { + int r = session_kill(s, KILL_ALL, signo); + if (res == 0 && r < 0) + res = r; + } + + return res; } void user_elect_display(User *u) { diff --git a/src/login/logind.c b/src/login/logind.c index 49dae036c4..8e8fe19157 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -542,6 +542,35 @@ static int manager_dispatch_console(sd_event_source *s, int fd, uint32_t revents return 0; } +static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + Session *s; + const char *cgroup; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &cgroup); + if (r < 0) { + bus_log_parse_error(r); + return 0; + } + + s = hashmap_get(m->sessions, cgroup); + + if (!s) { + log_warning("Session not found: %s", cgroup); + return 0; + } + + session_finalize(s); + session_free(s); + + return 0; +} + static int manager_connect_bus(Manager *m) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int r; @@ -557,6 +586,13 @@ static int manager_connect_bus(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to add manager object vtable: %m"); + r = sd_bus_add_match(m->bus, NULL, + "type='signal'," + "interface='org.freedesktop.systemd1.Agent'," + "member='Released'," + "path='/org/freedesktop/systemd1/agent'", + signal_agent_released, m); + r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/seat", "org.freedesktop.login1.Seat", seat_vtable, seat_object_find, m); if (r < 0) return log_error_errno(r, "Failed to add seat object vtable: %m"); |