Package: plasma-workspace Version: 4:6.3.6-2 Severity: important Tags: patch upstream Forwarded: https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/7012
Dear Maintainer, On the X11 session with the NVIDIA driver, every shutdown or reboot started from the Plasma menu stalls until plasma-kwin_x11.service hits its stop timeout (90 s by default). Everything else in the shutdown finishes within about two seconds. Cause ----- plasma-shutdown (startkde/plasma-shutdown/shutdown.cpp, lines 151-171 in 6.3.6) calls StopUnit on the session target and, as soon as that D-Bus call returns, asks logind to power off. StopUnit returns when the job is enqueued, not when the units have stopped. logind then stops the session scope, which kills sddm-helper, and sddm tears down the X server while kwin_x11 is still handling its SIGTERM with a live GL context. kwin_x11 loses the X connection inside the GLX teardown, prints "XIO: fatal IO error" and never exits, so the user manager waits for TimeoutStopSec and SIGKILLs it. journalctl -b -1 from an affected shutdown (TimeoutStopSec lowered to 30 s here; the default is 90 s): 23:15:24 dbus-daemon: Activating 'org.kde.Shutdown' requested by ksmserver-logout 23:15:24 systemd[2406]: Stopped target plasma-workspace.target 23:15:24 systemd[2406]: Stopping plasma-kwin_x11.service - KDE Window Manager... 23:15:24 systemd[2406]: Stopped target graphical-session.target 23:15:24 systemd-logind: The system will power off now! 23:15:24 systemd[1]: Stopping session-4.scope... 23:15:24 sddm-helper: Signal received: SIGTERM 23:15:24 sddm: Display server stopping... 23:15:24 kwin_x11: The X11 connection broke: I/O error (code 1) 23:15:24 kwin_x11: XIO: fatal IO error 4 (Interrupted system call) on X server ":0" 23:15:54 systemd[2406]: plasma-kwin_x11.service: State 'stop-sigterm' timed out. Killing. 23:15:54 systemd[2406]: plasma-kwin_x11.service: Killing process 2712 (kwin_x11) with signal SIGKILL. 23:15:56 systemd-shutdown[1]: Syncing filesystems and block devices. The same signature is KDE bug 501433 (filed against kwin, but the trigger is in plasma-shutdown) and sddm issues #1783 and #2058. It affects every trixie user of the X11 session with the NVIDIA driver. The Wayland session is not visibly affected because kwin_wayland owns the display, so nothing external kills it mid-stop. Fix --- The attached patch makes plasma-shutdown do what "systemctl stop" does: Subscribe to the user manager, connect to JobRemoved before enqueueing the stop job, and call logind only once ListJobs reports no pending jobs. A 10 s fallback timer keeps a unit that ignores SIGTERM from blocking shutdown; past that point the behaviour is exactly what it is today. The non-systemd fallback path is unchanged. The patch has been forwarded upstream as a merge request against the current stable branch Plasma/6.7: https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/7012 The 6.3 version attached differs from the upstream MR only in that it also switches the stopped target from plasma-workspace.target to graphical-session.target, which upstream did separately in 80f3e0ad8 ("Stop graphical-session.target directly"). That switch is needed so the units bound via PartOf= (kwin, ksmserver, ...) are part of the same stop transaction. Result with the patch applied (4:6.3.6-2 rebuilt locally as 4:6.3.6-2+local1, which is why the package list below shows that version; default TimeoutStopSec, no drop-ins): 22:23:12.645 systemd[2394]: Stopping plasma-kwin_x11.service - KDE Window Manager... 22:23:12.852 systemd[2394]: Stopped plasma-kwin_x11.service - KDE Window Manager. 22:23:12.861 systemd-logind[1278]: The system will power off now! 22:23:12.870 sddm[1752]: Display server stopping... 22:23:16.518 systemd-shutdown[1]: Syncing filesystems and block devices. kwin_x11 stops in about 200 ms, logind is called about 10 ms later, and the whole shutdown takes under 4 s instead of 30 to 90 s. Tested on both the X11 and the Wayland session on this machine, shutdown and reboot, logout unaffected. Once the upstream MR is merged I would like to ask for this to be considered for a trixie point release, in the same vein as the existing upstream_*.patch cherry-picks in debian/patches/series. Hardware: RTX 5060 Ti + RTX 3060, nvidia-driver 590.48.01-1, nvidia-kernel-open-dkms, nvidia-drm.modeset=1. Session started via sddm (startplasma-x11). Workaround in the meantime: systemctl --user edit plasma-kwin_x11.service and set TimeoutStopSec=3s in [Service]. -- System Information: Debian Release: 13.6 APT prefers stable-updates APT policy: (500, 'stable-updates'), (500, 'stable-security'), (500, 'stable-debug'), (500, 'stable') Architecture: amd64 (x86_64) Foreign Architectures: i386 Kernel: Linux 6.12.107+deb13-amd64 (SMP w/28 CPU threads; PREEMPT) Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE=en_US:en Shell: /bin/sh linked to /usr/bin/dash Init: systemd (via /run/systemd/system) LSM: AppArmor: enabled Versions of packages plasma-workspace depends on: ii dbus-user-session [default-dbus-session-bus] 1.16.2-2 ii dbus-x11 [dbus-session-bus] 1.16.2-2 ii drkonqi 6.3.4-1 ii frameworkintegration6 6.13.0-2 ii gdb 16.3-1 ii init-system-helpers 1.69~deb13u1 ii iso-codes 4.18.0-1 ii kactivitymanagerd 6.3.4-1 ii kded6 6.13.0-1 ii kglobalacceld 6.3.6-1 ii kio6 6.13.0-6 ii kwallet6 6.13.0-1 ii kwin-common 4:6.3.6-1 ii kwin-wayland 4:6.3.6-1 ii libappstreamqt3 1.0.5-1 hi libbatterycontrol6 4:6.3.6-2+local1 ii libc6 2.41-12+deb13u3 ii libcanberra0 0.30-18 hi libcolorcorrect6 4:6.3.6-2+local1 ii libcrypt1 1:4.4.38-1 ii libdbus-1-3 1.16.2-2 ii libfontconfig1 2.15.0-2.3 ii libfreetype6 2.13.3+dfsg-1+deb13u1 ii libgcc-s1 14.2.0-19 ii libice6 2:1.1.1-1 ii libicu76 76.1-4 ii libkexiv2qt6-0 25.04.0-1 ii libkf6archive6 6.13.0-2 ii libkf6authcore6 6.13.0-1 ii libkf6baloo6 6.13.0-1 ii libkf6bookmarks6 6.13.0-1 ii libkf6calendarevents6 6.13.0-1 ii libkf6colorscheme6 6.13.0-1 ii libkf6completion6 6.13.0-1 ii libkf6config-bin 6.13.0-2 ii libkf6configcore6 6.13.0-2 ii libkf6configgui6 6.13.0-2 ii libkf6configqml6 6.13.0-2 ii libkf6configwidgets6 6.13.0-1 ii libkf6coreaddons6 6.13.0-1 ii libkf6crash6 6.13.0-1 ii libkf6dbusaddons6 6.13.0-1 ii libkf6globalaccel6 6.13.0-1 ii libkf6guiaddons6 6.13.0-1 ii libkf6holidays6 6.13.0-1 ii libkf6i18n6 6.13.0-1 ii libkf6i18nlocaledata6 6.13.0-1 ii libkf6iconthemes6 6.13.0-2 ii libkf6jobwidgets6 6.13.0-1 ii libkf6kcmutils6 6.13.0-2 ii libkf6kcmutilscore6 6.13.0-2 ii libkf6kcmutilsquick6 6.13.0-2 ii libkf6kiocore6 6.13.0-6 ii libkf6kiofilewidgets6 6.13.0-6 ii libkf6kiogui6 6.13.0-6 ii libkf6kiowidgets6 6.13.0-6 ii libkf6networkmanagerqt6 6.13.0-1 ii libkf6newstuffcore6 6.13.0-1 ii libkf6newstuffwidgets6 6.13.0-1 ii libkf6notifications6 6.13.0-1 ii libkf6notifyconfig6 6.13.0-1 ii libkf6package6 6.13.0-1 ii libkf6parts6 6.13.0-1 ii libkf6prison6 6.13.0-1 ii libkf6runner6 6.13.0-1 ii libkf6service-bin 6.13.0-1 ii libkf6service6 6.13.0-1 ii libkf6solid6 6.13.0-1 ii libkf6statusnotifieritem6 6.13.0-1 ii libkf6svg6 6.13.0-1 ii libkf6texteditor-bin 6.13.0-1 ii libkf6texteditor6 6.13.0-1 ii libkf6textwidgets6 6.13.0-1 ii libkf6unitconversion6 6.13.0-1 ii libkf6userfeedbackcore6 6.13.0-1 ii libkf6wallet6 6.13.0-1 ii libkf6widgetsaddons6 6.13.0-1 ii libkf6windowsystem6 6.13.0-2 ii libkf6xmlgui6 6.13.0-1 hi libkfontinst6 4:6.3.6-2+local1 hi libkfontinstui6 4:6.3.6-2+local1 hi libklipper6 4:6.3.6-2+local1 hi libkmpris6 4:6.3.6-2+local1 ii libkscreenlocker6 6.3.5-1 ii libksysguardsensorfaces2 4:6.3.5-1 ii libkwaylandclient6 4:6.3.4-1 hi libkworkspace6-6 4:6.3.6-2+local1 ii liblayershellqtinterface6 6.3.4-1 hi libnotificationmanager1 4:6.3.6-2+local1 ii libpackagekitqt6-1 1.1.2-1+b1 ii libphonon4qt6-4t64 4:4.12.0-5 ii libplasma5support6 4:6.3.4-1 ii libplasma6 6.3.5-1 ii libplasmaactivities6 6.3.4-1 ii libplasmaactivitiesstats1 6.3.4-1 ii libplasmaquick6 6.3.5-1 ii libpolkit-qt6-1-1 0.200.0-4+b1 ii libprocesscore10 4:6.3.5-1 ii libqalculate23 5.5.2-1+b1 ii libqt6core6t64 [qt6-base-private-abi] 6.8.2+dfsg-9+deb13u2 ii libqt6dbus6 6.8.2+dfsg-9+deb13u2 ii libqt6gui6 6.8.2+dfsg-9+deb13u2 ii libqt6network6 6.8.2+dfsg-9+deb13u2 ii libqt6positioning6 6.8.2-3 ii libqt6printsupport6 6.8.2+dfsg-9+deb13u2 ii libqt6qml6 [qt6-declarative-private-abi] 6.8.2+dfsg-7 ii libqt6quick6 6.8.2+dfsg-7 ii libqt6sql6 6.8.2+dfsg-9+deb13u2 ii libqt6svg6 6.8.2-3 ii libqt6waylandclient6 [qt6-waylandclient-privat 6.8.2-4 e-abi] ii libqt6widgets6 6.8.2+dfsg-9+deb13u2 ii libqt6xml6 6.8.2+dfsg-9+deb13u2 ii libsm6 2:1.2.6-1 ii libstdc++6 14.2.0-19 ii libsystemd0 257.13-1~deb13u1 hi libtaskmanager6 4:6.3.6-2+local1 ii libudev1 257.13-1~deb13u1 ii libwayland-client0 1.23.1-3 hi libweather-ion7 4:6.3.6-2+local1 ii libx11-6 2:1.8.12-1 ii libxcb-composite0 1.17.0-2+b1 ii libxcb-cursor0 0.1.5-1 ii libxcb-damage0 1.17.0-2+b1 ii libxcb-image0 0.4.0-2+b2 ii libxcb-shape0 1.17.0-2+b1 ii libxcb-util1 0.4.1-1 ii libxcb1 1.17.0-2+b1 ii libxcursor1 1:1.2.3-1 ii libxfixes3 1:6.0.0-2+b4 ii libxft2 2.3.6-1+b4 ii libxtst6 2:1.2.5-1 ii milou 4:6.3.5-1 ii plasma-desktoptheme 6.3.5-1 ii plasma-integration 6.3.6-1 hi plasma-workspace-data 4:6.3.6-2+local1 ii python3 3.13.5-1 ii qdbus-qt6 6.8.2-5 ii qml6-module-org-kde-activities 6.3.4-1 ii qml6-module-org-kde-breeze 6.3.5-1 ii qml6-module-org-kde-config 6.13.0-2 ii qml6-module-org-kde-coreaddons 6.13.0-1 ii qml6-module-org-kde-draganddrop 6.13.0-1 ii qml6-module-org-kde-kcmutils 6.13.0-2 ii qml6-module-org-kde-kholidays 6.13.0-1 ii qml6-module-org-kde-kirigami 6.13.0-2 ii qml6-module-org-kde-kirigamiaddons-components 1.7.0-1 ii qml6-module-org-kde-kitemmodels 6.13.0-1 ii qml6-module-org-kde-kquickcontrols 6.13.0-1 ii qml6-module-org-kde-kquickcontrolsaddons 6.13.0-1 ii qml6-module-org-kde-ksvg 6.13.0-1 ii qml6-module-org-kde-ksysguard 4:6.3.5-1 ii qml6-module-org-kde-kwindowsystem 6.13.0-2 ii qml6-module-org-kde-newstuff 6.13.0-1 ii qml6-module-org-kde-notifications 6.13.0-1 ii qml6-module-org-kde-pipewire 6.3.6-1 ii qml6-module-org-kde-plasma-plasma5support 4:6.3.4-1 ii qml6-module-org-kde-prison 6.13.0-1 ii qml6-module-org-kde-quickcharts 6.13.0-1 ii qml6-module-org-kde-userfeedback 6.13.0-1 ii qml6-module-qt5compat-graphicaleffects 6.8.2-3+b1 ii qml6-module-qtcore 6.8.2+dfsg-7 ii qml6-module-qtpositioning 6.8.2-3 ii qml6-module-qtqml 6.8.2+dfsg-7 ii qml6-module-qtqml-models 6.8.2+dfsg-7 ii qml6-module-qtqml-workerscript 6.8.2+dfsg-7 ii qml6-module-qtquick 6.8.2+dfsg-7 ii qml6-module-qtquick-controls 6.8.2+dfsg-7 ii qml6-module-qtquick-dialogs 6.8.2+dfsg-7 ii qml6-module-qtquick-layouts 6.8.2+dfsg-7 ii qml6-module-qtquick-shapes 6.8.2+dfsg-7 ii qml6-module-qtquick-templates 6.8.2+dfsg-7 ii qml6-module-qtquick-virtualkeyboard 6.8.2+dfsg-3 ii qml6-module-qtquick-window 6.8.2+dfsg-7 ii qt6-wayland 6.8.2-4 ii udisks2 2.10.1-12.1+deb13u2 ii x11-utils 7.7+7 ii x11-xserver-utils 7.7+11 ii zlib1g 1:1.3.dfsg+really1.3.1-1+b1 Versions of packages plasma-workspace recommends: ii kde-cli-tools 4:6.3.4-1 ii kio-extras 4:25.04.3-1 ii kio-fuse 5.1.0-1+b1 ii ksystemstats 6.3.4-1 hi plasma-workspace-doc 4:6.3.6-2+local1 ii powerdevil 4:6.3.6-1 ii systemsettings 4:6.3.4-2 plasma-workspace suggests no packages. -- no debconf information
Description: plasma-shutdown: wait for the session stop job before calling logind StopUnit only enqueues a job. Calling logind PowerOff right after it makes the system manager tear down the session scope (and sddm the X server) while units are still stopping; kwin_x11 then hangs until TimeoutStopSec. Stop graphical-session.target and wait until the user manager has no jobs left, with a 10 s fallback. Author: Balint Szollosi-Nagy <[email protected]> Bug-KDE: https://bugs.kde.org/show_bug.cgi?id=501433 Forwarded: https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/7012 Applied-Upstream: no, MR against Plasma/6.7 pending review Last-Update: 2026-09-04 --- --- a/startkde/plasma-shutdown/shutdown.h 2025-07-08 13:48:12.000000000 +0200 +++ b/startkde/plasma-shutdown/shutdown.h 2026-09-03 19:25:29.100019663 +0200 @@ -8,6 +8,7 @@ #pragma once +#include <QDBusObjectPath> #include <QObject> #include <kworkspace.h> @@ -24,10 +25,15 @@ void logoutCancelled(); void logoutComplete(); void ksmServerComplete(); + void systemdJobRemoved(uint id, const QDBusObjectPath &job, const QString &unit, const QString &result); private: void startLogout(KWorkSpace::ShutdownType shutdownType); void runShutdownScripts(); bool usingSystemdManagedSession(); + void stopSystemdSession(); + bool systemdHasPendingJobs(); + void sessionStopped(); KWorkSpace::ShutdownType m_shutdownType; + bool m_sessionStopped = false; }; --- a/startkde/plasma-shutdown/shutdown.cpp 2025-07-08 13:48:12.000000000 +0200 +++ b/startkde/plasma-shutdown/shutdown.cpp 2026-09-03 19:26:32.268427898 +0200 @@ -2,10 +2,14 @@ #include "shutdownadaptor.h" #include <QCoreApplication> +#include <QDBusArgument> #include <QDBusConnection> +#include <QDBusObjectPath> +#include <QDBusReply> #include <QDir> #include <QProcess> #include <QStandardPaths> +#include <QTimer> #include "debug.h" #include "ksmserver_interface.h" @@ -149,23 +153,120 @@ runShutdownScripts(); if (usingSystemdManagedSession()) { - auto msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.systemd1"), - QStringLiteral("/org/freedesktop/systemd1"), - QStringLiteral("org.freedesktop.systemd1.Manager"), - QStringLiteral("StopUnit")); - msg << QStringLiteral("plasma-workspace.target") << QStringLiteral("fail"); - QDBusConnection::sessionBus().call(msg); - } else { - auto msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.ksmserver"), - QStringLiteral("/MainApplication"), - QStringLiteral("org.qtproject.Qt.QCoreApplication"), - QStringLiteral("quit")); - QDBusConnection::sessionBus().call(msg); - - OrgKdeKWinSessionInterface kwinInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Session"), QDBusConnection::sessionBus()); - QDBusPendingReply<> reply = kwinInterface.quit(); - reply.waitForFinished(); + // Asynchronous: sessionStopped() runs once the stop transaction has finished + stopSystemdSession(); + return; + } + + auto msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.ksmserver"), + QStringLiteral("/MainApplication"), + QStringLiteral("org.qtproject.Qt.QCoreApplication"), + QStringLiteral("quit")); + QDBusConnection::sessionBus().call(msg); + + OrgKdeKWinSessionInterface kwinInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Session"), QDBusConnection::sessionBus()); + QDBusPendingReply<> reply = kwinInterface.quit(); + reply.waitForFinished(); + + sessionStopped(); +} + +static QDBusMessage systemdManagerCall(const QString &method) +{ + return QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.systemd1"), + QStringLiteral("/org/freedesktop/systemd1"), + QStringLiteral("org.freedesktop.systemd1.Manager"), + method); +} + +void Shutdown::stopSystemdSession() +{ + // StopUnit only enqueues a job; it returns before any unit has actually stopped. + // If we ask logind to power off at that point, the system manager tears down the + // session scope (and with it the display server) while our units are still shutting + // down, which is what makes e.g. kwin hang until its stop timeout. So enqueue the + // stop, then wait until the user manager has no jobs left before continuing. + // + // graphical-session.target is stopped rather than plasma-workspace.target so that the + // units bound to it via PartOf= (kwin, ksmserver, ...) are part of the same transaction + // and therefore visible to ListJobs immediately. + + // systemd only emits Job*/Unit* signals to clients that subscribed + QDBusConnection::sessionBus().call(systemdManagerCall(QStringLiteral("Subscribe"))); + QDBusConnection::sessionBus().connect(QStringLiteral("org.freedesktop.systemd1"), + QStringLiteral("/org/freedesktop/systemd1"), + QStringLiteral("org.freedesktop.systemd1.Manager"), + QStringLiteral("JobRemoved"), + this, + SLOT(systemdJobRemoved(uint, QDBusObjectPath, QString, QString))); + + auto msg = systemdManagerCall(QStringLiteral("StopUnit")); + msg << QStringLiteral("graphical-session.target") << QStringLiteral("fail"); + QDBusReply<QDBusObjectPath> reply = QDBusConnection::sessionBus().call(msg); + if (!reply.isValid()) { + qCWarning(PLASMA_SESSION) << "Failed to stop the session with systemd:" << reply.error().message() << "- continuing with shutdown"; + sessionStopped(); + return; + } + qCDebug(PLASMA_SESSION) << "Waiting for session stop job" << reply.value().path(); + + // Safety net: a unit that ignores SIGTERM can hold the transaction open for its full + // TimeoutStopSec. Do not let that block shutdown indefinitely; past this point we behave + // as before this wait existed. + auto timer = new QTimer(this); + timer->setSingleShot(true); + timer->setInterval(std::chrono::seconds(10)); + connect(timer, &QTimer::timeout, this, [this]() { + qCWarning(PLASMA_SESSION) << "Timed out waiting for the session to stop, continuing with shutdown"; + sessionStopped(); + }); + timer->start(); + + // The transaction may already have completed (nothing was running) + if (!systemdHasPendingJobs()) { + sessionStopped(); + } +} + +bool Shutdown::systemdHasPendingJobs() +{ + QDBusMessage reply = QDBusConnection::sessionBus().call(systemdManagerCall(QStringLiteral("ListJobs"))); + if (reply.type() != QDBusMessage::ReplyMessage || reply.arguments().isEmpty()) { + return false; + } + // a(usssoo): id, unit, type, state, job path, unit path + const auto jobs = reply.arguments().first().value<QDBusArgument>(); + bool pending = false; + jobs.beginArray(); + while (!jobs.atEnd()) { + uint id; + QString unit, type, state; + QDBusObjectPath jobPath, unitPath; + jobs.beginStructure(); + jobs >> id >> unit >> type >> state >> jobPath >> unitPath; + jobs.endStructure(); + qCDebug(PLASMA_SESSION) << "Pending systemd job" << id << type << unit << state; + pending = true; + } + jobs.endArray(); + return pending; +} + +void Shutdown::systemdJobRemoved(uint id, const QDBusObjectPath &job, const QString &unit, const QString &result) +{ + Q_UNUSED(job) + qCDebug(PLASMA_SESSION) << "systemd job" << id << "for" << unit << "finished:" << result; + if (!systemdHasPendingJobs()) { + sessionStopped(); + } +} + +void Shutdown::sessionStopped() +{ + if (m_sessionStopped) { + return; } + m_sessionStopped = true; if (m_shutdownType == KWorkSpace::ShutdownTypeHalt) { SessionBackend::self()->shutdown();

