Fix user switching with legacy Xorg

Resolves: RHEL-72694
This commit is contained in:
Joan Torres López 2025-06-13 14:23:12 +02:00
parent a24e6de60c
commit 04df85fd3f
5 changed files with 219 additions and 260 deletions

View File

@ -1,7 +1,7 @@
From bcab8852cf7249a2220f6c737f7bb8a17b99249a Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Mon, 27 Nov 2023 15:29:09 -0500
Subject: [PATCH 1/2] gdm-session: Force reuse vt mode for legacy Xorg mode
Subject: [PATCH 1/4] gdm-session: Force reuse vt mode for legacy Xorg mode
In the legacy Xorg mode, the X session and user session are
supposed to use the same VT.

View File

@ -1,7 +1,7 @@
From 510566699c480226b189215c6222f7e72979baf8 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 22 May 2024 14:05:20 -0400
Subject: [PATCH 2/2] local-display-factory: Fix user switching with legacy
Subject: [PATCH 2/4] local-display-factory: Fix user switching with legacy
xorg
legacy-xorg sessions currently fail to completely user switch.
@ -12,41 +12,14 @@ login screen display.
This commit refactors the code so the same session types are used for
user switching as are used for the initial login.
---
daemon/gdm-local-display-factory.c | 78 +++++++++++++++++++++---------
1 file changed, 54 insertions(+), 24 deletions(-)
daemon/gdm-local-display-factory.c | 103 ++++++++++++++++++++++-------
1 file changed, 78 insertions(+), 25 deletions(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 7447b985a..4efbf0a6d 100644
index 7447b98..34842a7 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -331,118 +331,131 @@ gdm_local_display_factory_get_session_types (GdmLocalDisplayFactory *factory,
if (display_server_enabled (factory, fallback_display_server))
g_ptr_array_add (session_types_array, (gpointer) get_session_type_for_display_server (factory, fallback_display_server));
if (session_types_array->len == 0)
return NULL;
g_ptr_array_add (session_types_array, NULL);
session_types = g_strdupv ((char **) session_types_array->pdata);
return session_types;
}
static void
on_display_disposed (GdmLocalDisplayFactory *factory,
GdmDisplay *display)
{
g_debug ("GdmLocalDisplayFactory: Display %p disposed", display);
}
static void
store_display (GdmLocalDisplayFactory *factory,
GdmDisplay *display)
{
GdmDisplayStore *store;
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
@@ -358,6 +358,26 @@ store_display (GdmLocalDisplayFactory *factory,
gdm_display_store_add (store, display);
}
@ -73,49 +46,7 @@ index 7447b985a..4efbf0a6d 100644
/*
Example:
dbus-send --system --dest=org.gnome.DisplayManager \
--type=method_call --print-reply --reply-timeout=2000 \
/org/gnome/DisplayManager/Manager \
org.gnome.DisplayManager.Manager.GetDisplays
*/
gboolean
gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *factory,
char **id,
GError **error)
{
gboolean ret;
GdmDisplay *display = NULL;
gboolean is_initial = FALSE;
const char *session_type;
g_autofree gchar *preferred_display_server = NULL;
g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
ret = FALSE;
g_debug ("GdmLocalDisplayFactory: Creating transient display");
preferred_display_server = get_preferred_display_server (factory);
#ifdef ENABLE_USER_DISPLAY_SERVER
if (g_strcmp0 (preferred_display_server, "wayland") == 0 ||
g_strcmp0 (preferred_display_server, "xorg") == 0) {
g_auto(GStrv) session_types = NULL;
session_types = gdm_local_display_factory_get_session_types (factory, FALSE);
if (session_types == NULL) {
g_set_error_literal (error,
GDM_DISPLAY_ERROR,
GDM_DISPLAY_ERROR_GENERAL,
"Both Wayland and Xorg are unavailable");
return FALSE;
}
display = gdm_local_display_new ();
g_object_set (G_OBJECT (display),
"session-type", session_types[0],
"supported-session-types", session_types,
NULL);
@@ -407,15 +427,8 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact
is_initial = TRUE;
}
#endif
@ -133,67 +64,14 @@ index 7447b985a..4efbf0a6d 100644
if (display == NULL) {
g_set_error_literal (error,
GDM_DISPLAY_ERROR,
GDM_DISPLAY_ERROR_GENERAL,
"Invalid preferred display server configured");
return FALSE;
}
g_object_set (display,
"seat-id", "seat0",
"allow-timed-login", FALSE,
"is-initial", is_initial,
NULL);
store_display (factory, display);
if (! gdm_display_manage (display)) {
display = NULL;
goto out;
}
if (! gdm_display_get_id (display, id, NULL)) {
display = NULL;
goto out;
}
ret = TRUE;
out:
/* ref either held by store or not at all */
@@ -591,70 +604,87 @@ on_display_status_changed (GdmDisplay *display,
case GDM_DISPLAY_WAITING_TO_FINISH:
break;
default:
g_assert_not_reached ();
break;
}
g_free (seat_id);
g_free (session_type);
g_free (session_class);
}
static gboolean
lookup_by_seat_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
const char *looking_for = user_data;
char *current;
gboolean res;
g_object_get (G_OBJECT (display), "seat-id", &current, NULL);
res = g_strcmp0 (current, looking_for) == 0;
g_free(current);
@@ -618,6 +631,24 @@ lookup_by_seat_id (const char *id,
return res;
}
+static gboolean
+lookup_initial_display (const char *id,
+ GdmDisplay *display)
+ GdmDisplay *display,
+ gpointer user_data)
+{
+ gboolean is_initial = FALSE;
+ int status;
@ -211,72 +89,37 @@ index 7447b985a..4efbf0a6d 100644
static gboolean
lookup_prepared_display_by_seat_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
int status;
status = gdm_display_get_status (display);
- if (status != GDM_DISPLAY_PREPARED)
+ if (status != GDM_DISPLAY_PREPARED && status != GDM_DISPLAY_MANAGED)
return FALSE;
@@ -633,6 +664,21 @@ lookup_prepared_display_by_seat_id (const char *id,
return lookup_by_seat_id (id, display, user_data);
}
+static gboolean
+lookup_managed_display_by_seat_id (const char *id,
+ GdmDisplay *display,
+ gpointer user_data)
+{
+ int status;
+
+ status = gdm_display_get_status (display);
+
+ if (status != GDM_DISPLAY_MANAGED)
+ return FALSE;
+
+ return lookup_by_seat_id (id, display, user_data);
+}
+
#ifdef HAVE_UDEV
static gboolean
udev_is_settled (GdmLocalDisplayFactory *factory)
{
g_autoptr (GUdevEnumerator) enumerator = NULL;
GList *devices;
GList *node;
gboolean is_settled = FALSE;
if (factory->seat0_has_platform_graphics) {
g_debug ("GdmLocalDisplayFactory: udev settled, platform graphics enabled.");
return TRUE;
}
if (factory->seat0_has_boot_up_graphics) {
g_debug ("GdmLocalDisplayFactory: udev settled, boot up graphics available.");
return TRUE;
}
if (factory->seat0_graphics_check_timed_out) {
g_debug ("GdmLocalDisplayFactory: udev timed out, proceeding anyway.");
return TRUE;
}
@@ -834,115 +864,115 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory,
/* It is not yet time to force X11 fallback. */
g_debug ("GdmLocalDisplayFactory: seat0 display requested when there is no graphics support before graphics check timeout.");
}
return;
}
g_debug ("GdmLocalDisplayFactory: Assuming we can use seat0 for X11 even though system says it doesn't support graphics!");
g_debug ("GdmLocalDisplayFactory: This might indicate an issue where the framebuffer device is not tagged as master-of-seat in udev.");
seat_supports_graphics = TRUE;
wayland_enabled = FALSE;
g_strfreev (session_types);
session_types = g_strdupv ((char **) legacy_session_types);
} else {
g_clear_handle_id (&factory->seat0_graphics_check_timeout_id, g_source_remove);
}
}
if (!seat_supports_graphics)
return;
if (session_types != NULL)
g_debug ("GdmLocalDisplayFactory: %s login display for seat %s requested",
session_types[0], seat_id);
else if (g_strcmp0 (preferred_display_server, "legacy-xorg") == 0)
g_debug ("GdmLocalDisplayFactory: Legacy Xorg login display for seat %s requested",
seat_id);
@@ -740,6 +786,7 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory,
int ret;
gboolean seat_supports_graphics;
gboolean is_seat0;
+ gboolean is_initial;
g_auto (GStrv) session_types = NULL;
const char *legacy_session_types[] = { "x11", NULL };
GdmDisplayStore *store;
@@ -861,10 +908,25 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory,
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
@ -284,55 +127,28 @@ index 7447b985a..4efbf0a6d 100644
- display = gdm_display_store_find (store, lookup_prepared_display_by_seat_id, (gpointer) seat_id);
- else
+ if (is_seat0) {
+ display = gdm_display_store_find (store, lookup_prepared_display_by_seat_id, (gpointer) seat_id);
+ if (display != NULL && g_strcmp0 (preferred_display_server, "legacy-xorg") == 0) {
+ if (g_strcmp0 (preferred_display_server, "legacy-xorg") == 0) {
+ GdmDisplay *initial_display = NULL;
+
+ display = gdm_display_store_find (store, lookup_managed_display_by_seat_id, (gpointer) seat_id);
+ initial_display = gdm_display_store_find (store, lookup_initial_display, (gpointer) NULL);
+
+ if (initial_display == NULL)
+ display = NULL;
+ }
+ if (initial_display == NULL || factory->active_vt != GDM_INITIAL_VT)
+ display = NULL;
+
+ is_initial = initial_display == NULL;
+ } else {
+ display = gdm_display_store_find (store, lookup_prepared_display_by_seat_id, (gpointer) seat_id);
+ is_initial = TRUE;
+ }
+ } else {
display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
+ is_initial = FALSE;
+ }
/* Ensure we don't create the same display more than once */
if (display != NULL) {
g_debug ("GdmLocalDisplayFactory: display already created");
return;
}
/* If we already have a login window, switch to it */
if (gdm_get_login_window_session_id (seat_id, &login_session_id)) {
GdmDisplay *display;
display = gdm_display_store_find (store,
lookup_by_session_id,
(gpointer) login_session_id);
if (display != NULL &&
(gdm_display_get_status (display) == GDM_DISPLAY_MANAGED ||
gdm_display_get_status (display) == GDM_DISPLAY_WAITING_TO_FINISH)) {
g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_MANAGED, NULL);
g_debug ("GdmLocalDisplayFactory: session %s found, activating.",
login_session_id);
gdm_activate_session_by_id (factory->connection, seat_id, login_session_id);
return;
}
}
g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id);
#ifdef ENABLE_USER_DISPLAY_SERVER
if (g_strcmp0 (preferred_display_server, "wayland") == 0 ||
g_strcmp0 (preferred_display_server, "xorg") == 0) {
if (is_seat0) {
display = gdm_local_display_new ();
g_object_set (G_OBJECT (display),
"session-type", session_types[0],
"supported-session-types", session_types,
NULL);
}
@@ -905,20 +967,11 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory,
}
#endif
@ -351,34 +167,8 @@ index 7447b985a..4efbf0a6d 100644
+ display = create_legacy_xorg_display (factory);
g_object_set (display, "seat-id", seat_id, NULL);
g_object_set (display, "is-initial", is_seat0, NULL);
- g_object_set (display, "is-initial", is_seat0, NULL);
+ g_object_set (display, "is-initial", is_initial, NULL);
store_display (factory, display);
/* let store own the ref */
g_object_unref (display);
if (! gdm_display_manage (display)) {
gdm_display_unmanage (display);
}
return;
}
static void
delete_display (GdmLocalDisplayFactory *factory,
const char *seat_id) {
GdmDisplayStore *store;
g_debug ("GdmLocalDisplayFactory: Removing used_display_numbers on seat %s", seat_id);
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
gdm_display_store_foreach_remove (store, lookup_by_seat_id, (gpointer) seat_id);
}
static gboolean
gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory)
--
2.40.0

View File

@ -0,0 +1,105 @@
From de73b654cd1b726b905a9bf3238c7eaabfe465d5 Mon Sep 17 00:00:00 2001
From: Joan Torres <joantolo@redhat.com>
Date: Fri, 13 Jun 2025 13:05:07 +0200
Subject: [PATCH 3/4] local-display-factory: Ensure displays are properly
handled on status change
1. There are some cases where a display will change its status from any
status to MANAGED and vice versa. Ensure that the display status handlers
dont' re do work that has already been done.
2. For legacy-xorg displays that reuse the display from login manager,
avoid those displays to be killed on successfull authentication.
---
daemon/gdm-local-display-factory.c | 35 +++++++++++++++++++++---------
daemon/gdm-manager.c | 4 +++-
2 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index f28fe1e..61b7b45 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -600,6 +600,9 @@ on_display_status_changed (GdmDisplay *display,
break;
case GDM_DISPLAY_MANAGED:
#if defined(ENABLE_USER_DISPLAY_SERVER)
+ g_signal_handlers_disconnect_by_func (display,
+ G_CALLBACK (on_session_registered_cb),
+ factory);
g_signal_connect_object (display,
"notify::session-registered",
G_CALLBACK (on_session_registered_cb),
@@ -1183,6 +1186,18 @@ maybe_stop_greeter_in_background (GdmLocalDisplayFactory *factory,
g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
}
+static void
+cancel_stop_greeter_in_background (GdmLocalDisplayFactory *factory,
+ GdmDisplay *display)
+{
+ if (gdm_display_get_status (display) != GDM_DISPLAY_WAITING_TO_FINISH)
+ return;
+
+ g_debug ("GdmLocalDisplayFactory: cancelling killing login window");
+
+ g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_MANAGED, NULL);
+}
+
static gboolean
on_vt_changed (GIOChannel *source,
GIOCondition condition,
@@ -1261,23 +1276,23 @@ on_vt_changed (GIOChannel *source,
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
/* if the old VT was running a wayland login screen kill it
+ * but cancel the killing if the user switched back to it
*/
if (gdm_get_login_window_session_id ("seat0", &login_session_id)) {
ret = sd_session_get_vt (login_session_id, &login_window_vt);
if (ret == 0 && login_window_vt != 0) {
- g_debug ("GdmLocalDisplayFactory: VT of login window is %u", login_window_vt);
- if (login_window_vt == previous_vt) {
- GdmDisplay *display;
+ GdmDisplay *display;
- g_debug ("GdmLocalDisplayFactory: VT switched from login window");
+ g_debug ("GdmLocalDisplayFactory: VT of login window is %u", login_window_vt);
- display = gdm_display_store_find (store,
- lookup_by_session_id,
- (gpointer) login_session_id);
- if (display != NULL)
+ display = gdm_display_store_find (store,
+ lookup_by_session_id,
+ (gpointer) login_session_id);
+ if (display != NULL) {
+ if (login_window_vt == previous_vt)
maybe_stop_greeter_in_background (factory, display);
- } else {
- g_debug ("GdmLocalDisplayFactory: VT not switched from login window");
+ else if (login_window_vt == factory->active_vt)
+ cancel_stop_greeter_in_background (factory, display);
}
}
}
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index e1bc62d..7a68d52 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1534,11 +1534,13 @@ on_display_status_changed (GdmDisplay *display,
if ((display_number == -1 && status == GDM_DISPLAY_PREPARED) ||
(display_number != -1 && status == GDM_DISPLAY_MANAGED)) {
char *session_class;
+ gboolean session_registered = FALSE;
g_object_get (display,
"session-class", &session_class,
+ "session-registered", &session_registered,
NULL);
- if (g_strcmp0 (session_class, "greeter") == 0)
+ if (g_strcmp0 (session_class, "greeter") == 0 && !session_registered)
set_up_session (manager, display);
g_free (session_class);
}
--
2.49.0

View File

@ -0,0 +1,54 @@
From 8bcb9f43c203ab4818381cd707128eac74ab958d Mon Sep 17 00:00:00 2001
From: Joan Torres <joantolo@redhat.com>
Date: Fri, 13 Jun 2025 12:56:41 +0200
Subject: [PATCH 4/4] local-display-factory: Return a session type on
legacy-xorg
On legacy-xorg, there's graphic support through Xorg.
When returning none, it's considered that seat doesn't support graphics
and has to wait a 10s timeout, then forces using Xorg.
Avoid that timeout directly returning x11 as session type for
legacy-xorg.
---
daemon/gdm-local-display-factory.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 34842a7..f28fe1e 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -303,6 +303,7 @@ gdm_local_display_factory_get_session_types (GdmLocalDisplayFactory *factory,
const char *fallback_display_server = NULL;
gboolean wayland_preferred = FALSE;
gboolean xorg_preferred = FALSE;
+ gboolean legacy_xorg_preferred = FALSE;
g_autoptr (GPtrArray) session_types_array = NULL;
char **session_types;
@@ -315,13 +316,18 @@ gdm_local_display_factory_get_session_types (GdmLocalDisplayFactory *factory,
wayland_preferred = g_str_equal (preferred_display_server, "wayland");
xorg_preferred = g_str_equal (preferred_display_server, "xorg");
+ legacy_xorg_preferred = g_str_equal (preferred_display_server, "legacy-xorg");
- if (wayland_preferred)
+ if (wayland_preferred) {
fallback_display_server = "xorg";
- else if (xorg_preferred)
+ } else if (xorg_preferred) {
fallback_display_server = "wayland";
- else
+ } else if (legacy_xorg_preferred) {
+ g_ptr_array_add (session_types_array, (gpointer) "x11");
+ return g_strdupv ((char **) session_types_array->pdata);
+ } else {
return NULL;
+ }
if (!should_fall_back) {
if (display_server_enabled (factory, preferred_display_server))
--
2.49.0

View File

@ -11,7 +11,7 @@
Name: gdm
Epoch: 1
Version: 40.1
Release: 30%{?dist}
Release: 31%{?dist}
Summary: The GNOME Display Manager
License: GPLv2+
@ -55,6 +55,8 @@ Patch90004: 0004-data-Use-latest-upstream-udev-rules.patch
Patch100001: 0001-gdm-session-Force-reuse-vt-mode-for-legacy-Xorg-mode.patch
Patch100002: 0002-local-display-factory-Fix-user-switching-with-legacy.patch
Patch100003: 0003-local-display-factory-Ensure-displays-are-properly-h.patch
Patch100004: 0004-local-display-factory-Return-a-session-type-on-legac.patch
Patch110001: 0001-display-Add-new-FAILING-state.patch
Patch110002: 0002-manager-Quit-plymouth-at-first-sign-of-failure.patch
@ -368,6 +370,14 @@ dconf update || :
%{_libdir}/pkgconfig/gdm-pam-extensions.pc
%changelog
* Thu Jun 12 2025 Joan Torres <joantolo@redhat.com> - 40.1-31
- Fix legacy-xorg session switching
The fix that intended to fix the issue wasn't complete and also,
introduced a bug on user switching for non legacy-xorg servers.
This fix addresses both issues.
- Avoid waiting 10s when starting GDM in legacy-xorg mode
Resolves: RHEL-72694
* Fri May 09 2025 Joan Torres <joantolo@redhat.com> - 40.1-30
- Handle conflicting sessions on greeter and allow terminating them
Resolves: RHEL-46383