Zbigniew Jędrzejewski-Szmek 708deb
From 2ec3ff668ff03410e94cfef8e3ee9384a8222211 Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek 708deb
From: David Herrmann <dh.herrmann@gmail.com>
Zbigniew Jędrzejewski-Szmek 708deb
Date: Fri, 19 Sep 2014 13:26:39 +0200
Zbigniew Jędrzejewski-Szmek 708deb
Subject: [PATCH] login: pause devices before acknowledging VT switches
Zbigniew Jędrzejewski-Szmek 708deb
Zbigniew Jędrzejewski-Szmek 708deb
If a session controller does not need synchronous VT switches, we allow
Zbigniew Jędrzejewski-Szmek 708deb
them to pass VT control to logind, which acknowledges all VT switches
Zbigniew Jędrzejewski-Szmek 708deb
unconditionally. This works fine with all sessions using the dbus API,
Zbigniew Jędrzejewski-Szmek 708deb
but causes out-of-sync device use if we switch to legacy sessions that
Zbigniew Jędrzejewski-Szmek 708deb
are notified via VT signals. Those are processed before logind notices
Zbigniew Jędrzejewski-Szmek 708deb
the session-switch via sysfs. Therefore, leaving the old session still
Zbigniew Jędrzejewski-Szmek 708deb
active for a short amount of time.
Zbigniew Jędrzejewski-Szmek 708deb
Zbigniew Jędrzejewski-Szmek 708deb
This, in fact, may cause the legacy session to prepare graphics devices
Zbigniew Jędrzejewski-Szmek 708deb
before the old session was deactivated, and thus, maybe causing the old
Zbigniew Jędrzejewski-Szmek 708deb
session to interfer with graphics device usage.
Zbigniew Jędrzejewski-Szmek 708deb
Zbigniew Jędrzejewski-Szmek 708deb
Fix this by releasing devices immediately before acknowledging VT
Zbigniew Jędrzejewski-Szmek 708deb
switches. This way, sessions without VT handlers are required to support
Zbigniew Jędrzejewski-Szmek 708deb
async session switching (which they do in that case, anyway).
Zbigniew Jędrzejewski-Szmek 708deb
---
Zbigniew Jędrzejewski-Szmek 708deb
 src/login/logind-session.c | 21 +++++++++++++++++++++
Zbigniew Jędrzejewski-Szmek 708deb
 src/login/logind-session.h |  1 +
Zbigniew Jędrzejewski-Szmek 708deb
 src/login/logind.c         |  4 ++--
Zbigniew Jędrzejewski-Szmek 708deb
 3 files changed, 24 insertions(+), 2 deletions(-)
Zbigniew Jędrzejewski-Szmek 708deb
Zbigniew Jędrzejewski-Szmek 708deb
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
Zbigniew Jędrzejewski-Szmek 708deb
index eeb58c9031..477ac9ab1b 100644
Zbigniew Jędrzejewski-Szmek 708deb
--- a/src/login/logind-session.c
Zbigniew Jędrzejewski-Szmek 708deb
+++ b/src/login/logind-session.c
Zbigniew Jędrzejewski-Szmek 708deb
@@ -1053,6 +1053,27 @@ void session_restore_vt(Session *s) {
Zbigniew Jędrzejewski-Szmek 708deb
         s->vtfd = safe_close(s->vtfd);
Zbigniew Jędrzejewski-Szmek 708deb
 }
Zbigniew Jędrzejewski-Szmek 708deb
 
Zbigniew Jędrzejewski-Szmek 708deb
+void session_leave_vt(Session *s) {
Zbigniew Jędrzejewski-Szmek 708deb
+        assert(s);
Zbigniew Jędrzejewski-Szmek 708deb
+
Zbigniew Jędrzejewski-Szmek 708deb
+        /* This is called whenever we get a VT-switch signal from the kernel.
Zbigniew Jędrzejewski-Szmek 708deb
+         * We acknowledge all of them unconditionally. Note that session are
Zbigniew Jędrzejewski-Szmek 708deb
+         * free to overwrite those handlers and we only register them for
Zbigniew Jędrzejewski-Szmek 708deb
+         * sessions with controllers. Legacy sessions are not affected.
Zbigniew Jędrzejewski-Szmek 708deb
+         * However, if we switch from a non-legacy to a legacy session, we must
Zbigniew Jędrzejewski-Szmek 708deb
+         * make sure to pause all device before acknowledging the switch. We
Zbigniew Jędrzejewski-Szmek 708deb
+         * process the real switch only after we are notified via sysfs, so the
Zbigniew Jędrzejewski-Szmek 708deb
+         * legacy session might have already started using the devices. If we
Zbigniew Jędrzejewski-Szmek 708deb
+         * don't pause the devices before the switch, we might confuse the
Zbigniew Jędrzejewski-Szmek 708deb
+         * session we switch to. */
Zbigniew Jędrzejewski-Szmek 708deb
+
Zbigniew Jędrzejewski-Szmek 708deb
+        if (s->vtfd < 0)
Zbigniew Jędrzejewski-Szmek 708deb
+                return;
Zbigniew Jędrzejewski-Szmek 708deb
+
Zbigniew Jędrzejewski-Szmek 708deb
+        session_device_pause_all(s);
Zbigniew Jędrzejewski-Szmek 708deb
+        ioctl(s->vtfd, VT_RELDISP, 1);
Zbigniew Jędrzejewski-Szmek 708deb
+}
Zbigniew Jędrzejewski-Szmek 708deb
+
Zbigniew Jędrzejewski-Szmek 708deb
 bool session_is_controller(Session *s, const char *sender) {
Zbigniew Jędrzejewski-Szmek 708deb
         assert(s);
Zbigniew Jędrzejewski-Szmek 708deb
 
Zbigniew Jędrzejewski-Szmek 708deb
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
Zbigniew Jędrzejewski-Szmek 708deb
index 9fb0188a84..a007fb5e84 100644
Zbigniew Jędrzejewski-Szmek 708deb
--- a/src/login/logind-session.h
Zbigniew Jędrzejewski-Szmek 708deb
+++ b/src/login/logind-session.h
Zbigniew Jędrzejewski-Szmek 708deb
@@ -174,6 +174,7 @@ KillWho kill_who_from_string(const char *s) _pure_;
Zbigniew Jędrzejewski-Szmek 708deb
 
Zbigniew Jędrzejewski-Szmek 708deb
 int session_prepare_vt(Session *s);
Zbigniew Jędrzejewski-Szmek 708deb
 void session_restore_vt(Session *s);
Zbigniew Jędrzejewski-Szmek 708deb
+void session_leave_vt(Session *s);
Zbigniew Jędrzejewski-Szmek 708deb
 
Zbigniew Jędrzejewski-Szmek 708deb
 bool session_is_controller(Session *s, const char *sender);
Zbigniew Jędrzejewski-Szmek 708deb
 int session_set_controller(Session *s, const char *sender, bool force);
Zbigniew Jędrzejewski-Szmek 708deb
diff --git a/src/login/logind.c b/src/login/logind.c
Zbigniew Jędrzejewski-Szmek 708deb
index f1b6a86298..8f00c46339 100644
Zbigniew Jędrzejewski-Szmek 708deb
--- a/src/login/logind.c
Zbigniew Jędrzejewski-Szmek 708deb
+++ b/src/login/logind.c
Zbigniew Jędrzejewski-Szmek 708deb
@@ -750,11 +750,11 @@ static int manager_vt_switch(sd_event_source *src, const struct signalfd_siginfo
Zbigniew Jędrzejewski-Szmek 708deb
         }
Zbigniew Jędrzejewski-Szmek 708deb
 
Zbigniew Jędrzejewski-Szmek 708deb
         if (active->vtfd >= 0) {
Zbigniew Jędrzejewski-Szmek 708deb
-                ioctl(active->vtfd, VT_RELDISP, 1);
Zbigniew Jędrzejewski-Szmek 708deb
+                session_leave_vt(active);
Zbigniew Jędrzejewski-Szmek 708deb
         } else {
Zbigniew Jędrzejewski-Szmek 708deb
                 LIST_FOREACH(sessions_by_seat, iter, m->seat0->sessions) {
Zbigniew Jędrzejewski-Szmek 708deb
                         if (iter->vtnr == active->vtnr && iter->vtfd >= 0) {
Zbigniew Jędrzejewski-Szmek 708deb
-                                ioctl(iter->vtfd, VT_RELDISP, 1);
Zbigniew Jędrzejewski-Szmek 708deb
+                                session_leave_vt(iter);
Zbigniew Jędrzejewski-Szmek 708deb
                                 break;
Zbigniew Jędrzejewski-Szmek 708deb
                         }
Zbigniew Jędrzejewski-Szmek 708deb
                 }