572a44
From 553a962a570cade5c44953593209d25e28ec5145 Mon Sep 17 00:00:00 2001
572a44
From: Michal Sekletar <msekleta@redhat.com>
572a44
Date: Mon, 3 Mar 2014 15:37:49 +0100
572a44
Subject: [PATCH] logind: rework session shutdown logic
572a44
572a44
Simplify the shutdown logic a bit:
572a44
572a44
- Keep the session FIFO around in the PAM module, even after the session
572a44
  shutdown hook has been finished. This allows logind to track precisely
572a44
  when the PAM handler goes away.
572a44
572a44
- In the ReleaseSession() call start a timer, that will stop terminate
572a44
  the session when elapsed.
572a44
572a44
- Never fiddle with the KillMode of scopes to configure whether user
572a44
  processes should be killed or not. Instead, simply leave the scope
572a44
  units around when we terminate a session whose processes should not be
572a44
  killed.
572a44
572a44
- When killing is enabled, stop the session scope on FIFO EOF or after
572a44
  the ReleaseSession() timeout. When killing is disabled, simply tell
572a44
  PID 1 to abandon the scope.
572a44
572a44
Because the scopes stay around and hence all processes are always member
572a44
of a scope, the system shutdown logic should be more robust, as the
572a44
scopes can be shutdown as part of the usual shutdown logic.
572a44
572a44
Based-on: 5f41d1f10fd97e93517b6a762b1bec247f4d1171
572a44
---
572a44
 src/login/logind-dbus.c    |  51 +++++++++++-------
572a44
 src/login/logind-session.c | 130 +++++++++++++++++++++++++++++++++++----------
572a44
 src/login/logind-session.h |   4 ++
572a44
 src/login/logind-user.c    |  23 +++++---
572a44
 src/login/logind-user.h    |   1 +
572a44
 src/login/logind.c         |  23 ++++++--
572a44
 src/login/logind.h         |   4 +-
572a44
 src/login/pam-module.c     |  11 ++--
572a44
 8 files changed, 182 insertions(+), 65 deletions(-)
572a44
572a44
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
572a44
index 69e94aa..8de301e 100644
572a44
--- a/src/login/logind-dbus.c
572a44
+++ b/src/login/logind-dbus.c
572a44
@@ -1747,13 +1747,7 @@ static DBusHandlerResult manager_message_handler(
572a44
                 if (!session)
572a44
                         return bus_send_error_reply(connection, message, &error, -ENOENT);
572a44
 
572a44
-                /* We use the FIFO to detect stray sessions where the
572a44
-                process invoking PAM dies abnormally. We need to make
572a44
-                sure that that process is not killed if at the clean
572a44
-                end of the session it closes the FIFO. Hence, with
572a44
-                this call explicitly turn off the FIFO logic, so that
572a44
-                the PAM code can finish clean up on its own */
572a44
-                session_remove_fifo(session);
572a44
+                session_release(session);
572a44
 
572a44
                 reply = dbus_message_new_method_return(message);
572a44
                 if (!reply)
572a44
@@ -2551,7 +2545,6 @@ int manager_start_scope(
572a44
                 const char *slice,
572a44
                 const char *description,
572a44
                 const char *after,
572a44
-                const char *kill_mode,
572a44
                 DBusError *error,
572a44
                 char **job) {
572a44
 
572a44
@@ -2623,18 +2616,6 @@ int manager_start_scope(
572a44
                         return log_oom();
572a44
         }
572a44
 
572a44
-        if (!isempty(kill_mode)) {
572a44
-                const char *kill_mode_property = "KillMode";
572a44
-
572a44
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
572a44
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &kill_mode_property) ||
572a44
-                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
572a44
-                    !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &kill_mode) ||
572a44
-                    !dbus_message_iter_close_container(&sub2, &sub3) ||
572a44
-                    !dbus_message_iter_close_container(&sub, &sub2))
572a44
-                        return log_oom();
572a44
-        }
572a44
-
572a44
         /* cgroup empty notification is not available in containers
572a44
          * currently. To make this less problematic, let's shorten the
572a44
          * stop timeout for sessions, so that we don't wait
572a44
@@ -2793,6 +2774,36 @@ int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char
572a44
         return 1;
572a44
 }
572a44
 
572a44
+int manager_abandon_scope(Manager *manager, const char *scope, DBusError *error) {
572a44
+        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
572a44
+        _cleanup_free_ char *path = NULL;
572a44
+        int r;
572a44
+
572a44
+        assert(manager);
572a44
+        assert(scope);
572a44
+
572a44
+        path = unit_dbus_path_from_name(scope);
572a44
+        if (!path)
572a44
+                return -ENOMEM;
572a44
+
572a44
+        r = bus_method_call_with_reply(
572a44
+                manager->bus,
572a44
+                "org.freedesktop.systemd1",
572a44
+                path,
572a44
+                "org.freedesktop.systemd1.Scope",
572a44
+                "Abandon",
572a44
+                &reply,
572a44
+                error,
572a44
+                DBUS_TYPE_INVALID);
572a44
+
572a44
+        if (r < 0) {
572a44
+                log_error("Failed to abandon scope %s", scope);
572a44
+                return r;
572a44
+        }
572a44
+
572a44
+        return 1;
572a44
+}
572a44
+
572a44
 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
572a44
         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
572a44
         const char *w;
572a44
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
572a44
index 27aa335..78e6d74 100644
572a44
--- a/src/login/logind-session.c
572a44
+++ b/src/login/logind-session.c
572a44
@@ -24,6 +24,7 @@
572a44
 #include <unistd.h>
572a44
 #include <sys/epoll.h>
572a44
 #include <fcntl.h>
572a44
+#include <sys/timerfd.h>
572a44
 
572a44
 #include <systemd/sd-id128.h>
572a44
 #include <systemd/sd-messages.h>
572a44
@@ -36,6 +37,8 @@
572a44
 #include "dbus-common.h"
572a44
 #include "logind-session.h"
572a44
 
572a44
+#define RELEASE_SEC 20
572a44
+
572a44
 static unsigned devt_hash_func(const void *p) {
572a44
         uint64_t u = *(const dev_t*)p;
572a44
 
572a44
@@ -505,7 +508,6 @@ static int session_start_scope(Session *s) {
572a44
 
572a44
         if (!s->scope) {
572a44
                 _cleanup_free_ char *description = NULL;
572a44
-                const char *kill_mode;
572a44
                 char *scope, *job;
572a44
 
572a44
                 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
572a44
@@ -516,9 +518,7 @@ static int session_start_scope(Session *s) {
572a44
                 if (!scope)
572a44
                         return log_oom();
572a44
 
572a44
-                kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
572a44
-
572a44
-                r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job;;
572a44
+                r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", &error, &job;;
572a44
                 if (r < 0) {
572a44
                         log_error("Failed to start session scope %s: %s %s",
572a44
                                   scope, bus_error(&error, r), error.name);
572a44
@@ -579,23 +579,22 @@ int session_start(Session *s) {
572a44
 
572a44
         s->started = true;
572a44
 
572a44
-        /* Save session data */
572a44
+        /* Save data */
572a44
         session_save(s);
572a44
         user_save(s->user);
572a44
+        if (s->seat)
572a44
+                seat_save(s->seat);
572a44
 
572a44
+        /* Send signals */
572a44
         session_send_signal(s, true);
572a44
 
572a44
         if (s->seat) {
572a44
-                seat_save(s->seat);
572a44
-
572a44
                 if (s->seat->active == s)
572a44
                         seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
572a44
                 else
572a44
                         seat_send_changed(s->seat, "Sessions\0");
572a44
         }
572a44
 
572a44
-        user_send_changed(s->user, "Sessions\0");
572a44
-
572a44
         return 0;
572a44
 }
572a44
 
572a44
@@ -611,15 +610,24 @@ static int session_stop_scope(Session *s) {
572a44
         if (!s->scope)
572a44
                 return 0;
572a44
 
572a44
-        r = manager_stop_unit(s->manager, s->scope, &error, &job;;
572a44
-        if (r < 0) {
572a44
-                log_error("Failed to stop session scope: %s", bus_error(&error, r));
572a44
-                dbus_error_free(&error);
572a44
-                return r;
572a44
-        }
572a44
+        if (manager_shall_kill(s->manager, s->user->name)) {
572a44
+                r = manager_stop_unit(s->manager, s->scope, &error, &job;;
572a44
+                if (r < 0) {
572a44
+                        log_error("Failed to stop session scope: %s", bus_error(&error, r));
572a44
+                        dbus_error_free(&error);
572a44
+                        return r;
572a44
+                }
572a44
 
572a44
-        free(s->scope_job);
572a44
-        s->scope_job = job;
572a44
+                free(s->scope_job);
572a44
+                s->scope_job = job;
572a44
+        } else {
572a44
+                r = manager_abandon_scope(s->manager, s->scope, &error);
572a44
+                if (r < 0) {
572a44
+                        log_error("Failed to abandon session scope: %s", bus_error(&error, r));
572a44
+                        dbus_error_free(&error);
572a44
+                        return r;
572a44
+                }
572a44
+        }
572a44
 
572a44
         return 0;
572a44
 }
572a44
@@ -644,6 +652,19 @@ static int session_unlink_x11_socket(Session *s) {
572a44
         return r < 0 ? -errno : 0;
572a44
 }
572a44
 
572a44
+static void session_close_timer_fd(Session *s) {
572a44
+        assert(s);
572a44
+
572a44
+        if (s->timer_fd <= 0)
572a44
+                return;
572a44
+
572a44
+        hashmap_remove(s->manager->timer_fds, INT_TO_PTR(s->timer_fd + 1));
572a44
+        epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->timer_fd, NULL);
572a44
+
572a44
+        close_nointr(s->timer_fd);
572a44
+        s->timer_fd = -1;
572a44
+}
572a44
+
572a44
 int session_stop(Session *s) {
572a44
         int r;
572a44
 
572a44
@@ -652,11 +673,18 @@ int session_stop(Session *s) {
572a44
         if (!s->user)
572a44
                 return -ESTALE;
572a44
 
572a44
+        session_close_timer_fd(s);
572a44
+
572a44
+        /* We are going down, don't care about FIFOs anymore */
572a44
+        session_remove_fifo(s);
572a44
+
572a44
         /* Kill cgroup */
572a44
         r = session_stop_scope(s);
572a44
 
572a44
         session_save(s);
572a44
 
572a44
+        s->stopping = true;
572a44
+
572a44
         return r;
572a44
 }
572a44
 
572a44
@@ -678,6 +706,8 @@ int session_finalize(Session *s) {
572a44
                            "MESSAGE=Removed session %s.", s->id,
572a44
                            NULL);
572a44
 
572a44
+        session_close_timer_fd(s);
572a44
+
572a44
         /* Kill session devices */
572a44
         while ((sd = hashmap_first(s->devices)))
572a44
                 session_device_free(sd);
572a44
@@ -698,16 +728,64 @@ int session_finalize(Session *s) {
572a44
                 if (s->seat->active == s)
572a44
                         seat_set_active(s->seat, NULL);
572a44
 
572a44
-                seat_send_changed(s->seat, "Sessions\0");
572a44
                 seat_save(s->seat);
572a44
+                seat_send_changed(s->seat, "Sessions\0");
572a44
         }
572a44
 
572a44
-        user_send_changed(s->user, "Sessions\0");
572a44
         user_save(s->user);
572a44
+        user_send_changed(s->user, "Sessions\0");
572a44
 
572a44
         return r;
572a44
 }
572a44
 
572a44
+void session_release(Session *s) {
572a44
+        int r;
572a44
+
572a44
+        struct itimerspec its = { .it_value.tv_sec = RELEASE_SEC };
572a44
+        struct epoll_event ev = {};
572a44
+
572a44
+        assert(s);
572a44
+
572a44
+        if (!s->started || s->stopping)
572a44
+                return;
572a44
+
572a44
+        if (s->timer_fd >= 0)
572a44
+                return;
572a44
+
572a44
+        s->timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
572a44
+        if (s->timer_fd < 0) {
572a44
+                log_error("Failed to create session release timer fd");
572a44
+                goto out;
572a44
+        }
572a44
+
572a44
+        r = hashmap_put(s->manager->timer_fds, INT_TO_PTR(s->timer_fd + 1), s);
572a44
+        if (r < 0) {
572a44
+                log_error("Failed to store session release timer fd");
572a44
+                goto out;
572a44
+        }
572a44
+
572a44
+        ev.events = EPOLLONESHOT;
572a44
+        ev.data.u32 = FD_OTHER_BASE + s->timer_fd;
572a44
+
572a44
+        r = epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->timer_fd, &ev;;
572a44
+        if (r < 0) {
572a44
+                log_error("Failed to add session release timer fd to epoll instance");
572a44
+                goto out;
572a44
+        }
572a44
+
572a44
+        r = timerfd_settime(s->timer_fd, TFD_TIMER_ABSTIME, &its, NULL);
572a44
+        if (r < 0) {
572a44
+                log_error("Failed to arm timer : %m");
572a44
+                goto out;
572a44
+        }
572a44
+
572a44
+out:
572a44
+        if (s->timer_fd >= 0) {
572a44
+                close_nointr(s->timer_fd);
572a44
+                s->timer_fd = -1;
572a44
+        }
572a44
+}
572a44
+
572a44
 bool session_is_active(Session *s) {
572a44
         assert(s);
572a44
 
572a44
@@ -904,8 +982,6 @@ void session_remove_fifo(Session *s) {
572a44
 }
572a44
 
572a44
 int session_check_gc(Session *s, bool drop_not_started) {
572a44
-        int r;
572a44
-
572a44
         assert(s);
572a44
 
572a44
         if (drop_not_started && !s->started)
572a44
@@ -915,11 +991,7 @@ int session_check_gc(Session *s, bool drop_not_started) {
572a44
                 return 0;
572a44
 
572a44
         if (s->fifo_fd >= 0) {
572a44
-                r = pipe_eof(s->fifo_fd);
572a44
-                if (r < 0)
572a44
-                        return r;
572a44
-
572a44
-                if (r == 0)
572a44
+                if (pipe_eof(s->fifo_fd) <= 0)
572a44
                         return 1;
572a44
         }
572a44
 
572a44
@@ -945,15 +1017,15 @@ void session_add_to_gc_queue(Session *s) {
572a44
 SessionState session_get_state(Session *s) {
572a44
         assert(s);
572a44
 
572a44
+        if (s->stopping || s->timer_fd >= 0)
572a44
+                return SESSION_CLOSING;
572a44
+
572a44
         if (s->closing)
572a44
                 return SESSION_CLOSING;
572a44
 
572a44
         if (s->scope_job)
572a44
                 return SESSION_OPENING;
572a44
 
572a44
-        if (s->fifo_fd < 0)
572a44
-                return SESSION_CLOSING;
572a44
-
572a44
         if (session_is_active(s))
572a44
                 return SESSION_ACTIVE;
572a44
 
572a44
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
572a44
index f175a89..9b76582 100644
572a44
--- a/src/login/logind-session.h
572a44
+++ b/src/login/logind-session.h
572a44
@@ -98,11 +98,14 @@ struct Session {
572a44
         int fifo_fd;
572a44
         char *fifo_path;
572a44
 
572a44
+        int timer_fd;
572a44
+
572a44
         bool idle_hint;
572a44
         dual_timestamp idle_hint_timestamp;
572a44
 
572a44
         bool in_gc_queue:1;
572a44
         bool started:1;
572a44
+        bool stopping:1;
572a44
         bool closing:1;
572a44
 
572a44
         DBusMessage *create_message;
572a44
@@ -130,6 +133,7 @@ void session_remove_fifo(Session *s);
572a44
 int session_start(Session *s);
572a44
 int session_stop(Session *s);
572a44
 int session_finalize(Session *s);
572a44
+void session_release(Session *s);
572a44
 int session_save(Session *s);
572a44
 int session_load(Session *s);
572a44
 int session_kill(Session *s, KillWho who, int signo);
572a44
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
572a44
index 8e7256b..653574e 100644
572a44
--- a/src/login/logind-user.c
572a44
+++ b/src/login/logind-user.c
572a44
@@ -487,6 +487,8 @@ int user_stop(User *u) {
572a44
         if (k < 0)
572a44
                 r = k;
572a44
 
572a44
+        u->stopping = true;
572a44
+
572a44
         user_save(u);
572a44
 
572a44
         return r;
572a44
@@ -602,22 +604,27 @@ void user_add_to_gc_queue(User *u) {
572a44
 
572a44
 UserState user_get_state(User *u) {
572a44
         Session *i;
572a44
-        bool all_closing = true;
572a44
 
572a44
         assert(u);
572a44
 
572a44
+        if (u->stopping)
572a44
+                return USER_CLOSING;
572a44
+
572a44
         if (u->slice_job || u->service_job)
572a44
                 return USER_OPENING;
572a44
 
572a44
-        LIST_FOREACH(sessions_by_user, i, u->sessions) {
572a44
-                if (session_is_active(i))
572a44
-                        return USER_ACTIVE;
572a44
-                if (session_get_state(i) != SESSION_CLOSING)
572a44
-                        all_closing = false;
572a44
-        }
572a44
+        if (u->sessions) {
572a44
+                bool all_closing = true;
572a44
+
572a44
+                LIST_FOREACH(sessions_by_user, i, u->sessions) {
572a44
+                        if (session_is_active(i))
572a44
+                                return USER_ACTIVE;
572a44
+                        if (session_get_state(i) != SESSION_CLOSING)
572a44
+                                all_closing = false;
572a44
+                }
572a44
 
572a44
-        if (u->sessions)
572a44
                 return all_closing ? USER_CLOSING : USER_ONLINE;
572a44
+        }
572a44
 
572a44
         if (user_check_linger_file(u) > 0)
572a44
                 return USER_LINGERING;
572a44
diff --git a/src/login/logind-user.h b/src/login/logind-user.h
572a44
index a36f456..a12532e 100644
572a44
--- a/src/login/logind-user.h
572a44
+++ b/src/login/logind-user.h
572a44
@@ -61,6 +61,7 @@ struct User {
572a44
 
572a44
         bool in_gc_queue:1;
572a44
         bool started:1;
572a44
+        bool stopping:1;
572a44
 
572a44
         LIST_HEAD(Session, sessions);
572a44
         LIST_FIELDS(User, gc_queue);
572a44
diff --git a/src/login/logind.c b/src/login/logind.c
572a44
index 0628032..5180be7 100644
572a44
--- a/src/login/logind.c
572a44
+++ b/src/login/logind.c
572a44
@@ -80,10 +80,11 @@ Manager *manager_new(void) {
572a44
         m->session_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
572a44
         m->inhibitor_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
572a44
         m->button_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
572a44
+        m->timer_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
572a44
 
572a44
         if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->busnames ||
572a44
             !m->user_units || !m->session_units ||
572a44
-            !m->session_fds || !m->inhibitor_fds || !m->button_fds) {
572a44
+            !m->session_fds || !m->inhibitor_fds || !m->button_fds || !m->timer_fds) {
572a44
                 manager_free(m);
572a44
                 return NULL;
572a44
         }
572a44
@@ -149,6 +150,7 @@ void manager_free(Manager *m) {
572a44
         hashmap_free(m->session_fds);
572a44
         hashmap_free(m->inhibitor_fds);
572a44
         hashmap_free(m->button_fds);
572a44
+        hashmap_free(m->timer_fds);
572a44
 
572a44
         if (m->console_active_fd >= 0)
572a44
                 close_nointr_nofail(m->console_active_fd);
572a44
@@ -620,6 +622,13 @@ static void manager_dispatch_other(Manager *m, int fd) {
572a44
                 return;
572a44
         }
572a44
 
572a44
+        s = hashmap_get(m->timer_fds, INT_TO_PTR(fd + 1));
572a44
+        if (s) {
572a44
+                assert(s->timer_fd == fd);
572a44
+                session_stop(s);
572a44
+                return;
572a44
+        }
572a44
+
572a44
         i = hashmap_get(m->inhibitor_fds, INT_TO_PTR(fd + 1));
572a44
         if (i) {
572a44
                 assert(i->fifo_fd == fd);
572a44
@@ -942,8 +951,12 @@ void manager_gc(Manager *m, bool drop_not_started) {
572a44
                 LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
572a44
                 session->in_gc_queue = false;
572a44
 
572a44
-                if (session_check_gc(session, drop_not_started) == 0) {
572a44
+                /* First, if we are not closing yet, initiate stopping */
572a44
+                if (!session_check_gc(session, drop_not_started) &&
572a44
+                    session_get_state(session) != SESSION_CLOSING)
572a44
                         session_stop(session);
572a44
+
572a44
+                if (!session_check_gc(session, drop_not_started)) {
572a44
                         session_finalize(session);
572a44
                         session_free(session);
572a44
                 }
572a44
@@ -953,8 +966,11 @@ void manager_gc(Manager *m, bool drop_not_started) {
572a44
                 LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
572a44
                 user->in_gc_queue = false;
572a44
 
572a44
-                if (user_check_gc(user, drop_not_started) == 0) {
572a44
+                if (!user_check_gc(user, drop_not_started) &&
572a44
+                    user_get_state(user) != USER_CLOSING)
572a44
                         user_stop(user);
572a44
+
572a44
+                if (!user_check_gc(user, drop_not_started)) {
572a44
                         user_finalize(user);
572a44
                         user_free(user);
572a44
                 }
572a44
@@ -1032,6 +1048,7 @@ finish:
572a44
 
572a44
         return r;
572a44
 }
572a44
+
572a44
 int manager_startup(Manager *m) {
572a44
         int r;
572a44
         Seat *seat;
572a44
diff --git a/src/login/logind.h b/src/login/logind.h
572a44
index 9e6296c..0d2248f 100644
572a44
--- a/src/login/logind.h
572a44
+++ b/src/login/logind.h
572a44
@@ -88,6 +88,7 @@ struct Manager {
572a44
         Hashmap *session_fds;
572a44
         Hashmap *inhibitor_fds;
572a44
         Hashmap *button_fds;
572a44
+        Hashmap *timer_fds;
572a44
 
572a44
         usec_t inhibit_delay_max;
572a44
 
572a44
@@ -183,9 +184,10 @@ int manager_send_changed(Manager *manager, const char *properties);
572a44
 
572a44
 int manager_dispatch_delayed(Manager *manager);
572a44
 
572a44
-int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *kill_mode, DBusError *error, char **job);
572a44
+int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, DBusError *error, char **job);
572a44
 int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job);
572a44
 int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job);
572a44
+int manager_abandon_scope(Manager *manager, const char *scope, DBusError *error);
572a44
 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error);
572a44
 int manager_unit_is_active(Manager *manager, const char *unit);
572a44
 
572a44
diff --git a/src/login/pam-module.c b/src/login/pam-module.c
572a44
index 22d9733..7bd4783 100644
572a44
--- a/src/login/pam-module.c
572a44
+++ b/src/login/pam-module.c
572a44
@@ -478,7 +478,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
572a44
                 int flags,
572a44
                 int argc, const char **argv) {
572a44
 
572a44
-        const void *p = NULL, *existing = NULL;
572a44
+        const void *existing = NULL;
572a44
         const char *id;
572a44
         DBusConnection *bus = NULL;
572a44
         DBusMessage *m = NULL, *reply = NULL;
572a44
@@ -535,12 +535,15 @@ _public_ PAM_EXTERN int pam_sm_close_session(
572a44
                 }
572a44
         }
572a44
 
572a44
+
572a44
+        /* Note that we are knowingly leaking the FIFO fd here. This
572a44
+         * way, logind can watch us die. If we closed it here it would
572a44
+         * not have any clue when that is completed. Given that one
572a44
+         * cannot really have multiple PAM sessions open from the same
572a44
+         * process this means we will leak one FD at max. */
572a44
         r = PAM_SUCCESS;
572a44
 
572a44
 finish:
572a44
-        pam_get_data(handle, "systemd.session-fd", &p);
572a44
-        if (p)
572a44
-                close_nointr(PTR_TO_INT(p) - 1);
572a44
 
572a44
         dbus_error_free(&error);
572a44