The symptom, and the wrong first assumption

Every so often my desktop would vanish. Not freeze — vanish. Screen goes black, SDDM's login prompt appears, and everything I had open is gone. Konsole sessions, the editor, mail, the browser tabs I had not got round to reading. A full session teardown with no warning and no prompt.

The obvious conclusion is the one I reached: Plasma is crashing. That is certainly what it looks like from the chair. It is also what the search results tell you if you type the symptom into a search engine — there is an enormous amount of writing about Plasma instability, and it is very easy to spend an evening reading about plasmashell restarts and QML errors.

I had one advantage over my own instinct, which is that I had just come off a project where I got the framing wrong for an entire day and only escaped by running a diagnostic command I should have run first. So this time I went to the logs before I went to the search engine.


Reading the logs in the right order

The first thing worth knowing is that when a session dies, everything in it dies at once, and they all say so. Here is what the journal looked like at the moment of a crash:

11:33:37 kactivitymanagerd: The X11 connection broke (error 1). Did the X11 server die?
11:33:37 org_kde_powerdevil: The X11 connection broke (error 1). Did the X11 server die?
11:33:37 ksmserver:         The X11 connection broke (error 1). Did the X11 server die?
11:33:37 kmail:             The X11 connection broke (error 1). Did the X11 server die?
11:33:37 plasmashell:       The X11 connection broke (error 1). Did the X11 server die?
11:33:37 kwin_x11:          The X11 connection broke: I/O error (code 1)
11:33:37 konsole:           The X11 connection broke (error 1). Did the X11 server die?
11:33:37 plasmashell:       ICE default IO error handler doing an exit(), pid = 106376, errno = 32

Fourteen processes, one second, all reporting the same thing. That pattern is the tell. If plasmashell had crashed, plasmashell would be the one dying and kwin_x11 would still be up. Instead every X client in the session hits an I/O error on its connection simultaneously, which only happens when the thing on the other end of the socket — the X server — goes away.

The message even asks the question outright: Did the X11 server die? Yes. It did.

This is also why nothing useful shows up in coredumpctl for Plasma. I checked — plenty of dumps from my own .NET builds, from kmail, from ksecretd, but nothing from plasmashell or kwin. They did not crash. They exited, cleanly and deliberately, because their display went away. ICE default IO error handler doing an exit() is an orderly shutdown, not a fault.

So: wrong log file. The X server writes its own.


The actual crash

/var/log/Xorg.0.log.old — the .old matters, because a crash means a restart and a restart rotates the log:

[ 4554.012] (WW) modeset(0): flip queue retry
[ 4554.012] (EE)
[ 4554.012] (EE) Backtrace:
[ 4554.013] (EE) 0: /usr/libexec/Xorg (?+0x0)
[ 4554.014] (EE) 1: /lib64/libc.so.6 (?+0x0)
[ 4554.015] (EE) 2: /usr/lib64/xorg/modules/drivers/modesetting_drv.so (?+0x0)
[ 4554.015] (EE) 3: /lib64/libdrm.so.2 (drmHandleEvent+0xba)
[ 4554.016] (EE) 4: /usr/libexec/Xorg (?+0x0)
[ 4554.016] (EE) 5: /usr/libexec/Xorg (WaitForSomething+0x18c)
[ 4554.018] (EE) Segmentation fault at address 0x562aacbcc9f3
[ 4554.018] (EE) Caught signal 11 (Segmentation fault). Server aborting

Three things in there are worth more than the rest.

The timestamps. flip queue retry and the start of the backtrace are both at 4554.012. Same millisecond. That warning is not background noise that happened to precede a crash — the crash is inside the code path that emitted it.

Frames 5 → 3 → 2. Read them bottom-up as a call chain: the X server is in WaitForSomething, its main event loop, waiting on file descriptors. Something arrives on the DRM fd, so it calls into libdrm's drmHandleEvent, whose entire job is to read kernel events and dispatch them to callbacks the driver registered earlier. It dispatches into modesetting_drv.so, and that callback segfaults.

A callback invoked from an event queue, crashing on a pointer — that shape says use-after-free before you know anything else about the code. Something was queued, something freed the thing it pointed at, and the event arrived anyway.

And it was reproducible. I had two crashes logged, a day apart, with byte-for-byte identical structure — same warning, same frames, same signal.

An empty log is not a clean bill of health

I nearly wrote a fourth point here. My notes said, in as many words: no (EE) from the kernel — I checked journalctl -k around the crash for i915 or DRM complaints, found nothing, so the kernel is perfectly happy and this is purely a userspace bug.

That sentence was wrong, and it is worth dwelling on why, because the mistake is so easy to make that I made it in the middle of an investigation whose whole theme is not trusting summaries.

journalctl -k had returned nothing. But my user account is in xquiet and input, and not in adm, systemd-journal or wheel — so the kernel ring buffer was never visible to me in the first place. journalctl even says so, in a hint I had been scrolling past for an hour:

Hint: You are currently not seeing messages from other users and the system.
      Users in groups 'adm', 'systemd-journal', 'wheel' can see all messages.

Zero lines because there was nothing to report, and zero lines because I was not allowed to see it, look exactly alike on the terminal. I read the second one as the first, and turned "I have no information" into "I have information, and it is negative" — which is a considerably stronger claim, and one I would have put in a bug report where somebody else might have relied on it.

So I went back and read it properly, with privileges, for the fifteen minutes bracketing the crash. Twelve hundred lines. The kernel had been talking the entire time:

302x  pcieport 0000:00:06.0: AER: Correctable error message received from 0000:01:00.0
302x  pci 0000:01:00.0: PCIe Bus Error: severity=Correctable, type=Physical Layer, (Receiver ID)
302x  pci 0000:01:00.0:    [ 0] RxErr (First)
  1x  ksecretd[106106]: segfault ... in libqca-qt6.so.2.3.10     (11:33:37)

0000:01:00.0 is the NVIDIA card. The one I had described, twice, as "present but not implicated". Its PCIe link is throwing correctable receiver errors at about twenty a minute, continuously, including through the crash.

Now — I do not think this caused the segfault, and I want to be as careful about over-correcting as I was careless about the original claim. Correctable means the hardware fixed it and no data was lost; this is a common and usually benign thing to see on a laptop discrete GPU with aggressive power management. More to the point, the rate is flat: twenty-five in the minute of the crash against twenty-ish either side, with no burst that lines up with 11:33:37. If this were the mechanism I would expect a spike, and there isn't one.

But "probably benign" is a different statement from "not implicated", and only one of them was honest to make without looking. It goes in the bug report as a disclosed observation rather than a suspected cause, and it gets its own investigation later — separately, because testing two things at once tells you nothing about either.

What the kernel log doesn't contain is equally worth saying: no i915 errors, no GPU hang, no DRM reset. Every i915 message that day is a clean re-initialisation — GuC firmware, HuC authentication, submission enabled — and those are resume-from-suspend signatures, not faults.

And the Xorg segfault does not appear in the kernel log at all, which is correct and which I should have predicted: Xorg installs its own signal handler and writes its own backtrace, so the kernel never sees an unhandled fault. The kernel log was never going to corroborate the crash. It could only show whether something hardware-shaped was standing where the crash was, and nothing was.

The ksecretd line sharing the crash second is a red herring I checked rather than assumed: coredumpctl shows ksecretd and kmail going down together on four separate days, including days with no Xorg crash. It is its own bug. It died at 11:33:37 for the same reason everything else did.

One thing I can rule out, because it is arithmetic rather than absence. Xorg timestamps its log in CLOCK_MONOTONIC, which stops while the machine is suspended, so comparing an Xorg timestamp against the journal's wall clock tells you whether a suspend happened in between. Here: Xorg's 4554.012 plus a boot at 10:17:42 gives 11:33:36, and the journal recorded the session dying at 11:33:37. They match within a second, with no correction needed, so the monotonic clock never froze. This crash was a plain DPMS off→on cycle, with no suspend/resume anywhere near it.

(That distinction earned its keep a few days later, when a different failure on this machine — lock screen up, mouse alive, password field ignoring every keystroke — turned out to sit on the other side of it: a real suspend, a 174 second gap between CLOCK_BOOTTIME and CLOCK_MONOTONIC, and X taking twelve seconds after resume to take its input devices back. Same neighbourhood, different bug, and the clocks are what told them apart. That one is still open.)


What actually triggers it

Two data points were not enough to see the pattern. The third one was, because I caused it myself and noticed what I had done.

The machine had been idle for a few minutes. Plasma's idle configuration had done its thing: lock the session, blank the monitor. I came back and touched the touchpad to wake it up, expecting the unlock prompt.

I got SDDM instead.

That is the reproducer: the crash fires on DPMS wake-up. Not on lock, not on blank — on the transition back. The display comes out of power-save, the driver starts pushing frames again, and the page-flip machinery falls over.

It is worth noting how much this narrows the problem. "Plasma crashes randomly" is not something you can investigate. "The X server segfaults in the page-flip completion callback when the display returns from DPMS off" is a sentence with maybe two possible causes in it.


Why this code exists on my machine at all

Here is where it got interesting, and where the answer turned out to be about packaging rather than about graphics.

flip queue retry is a distinctive string, so I went looking for it in the X server source. It lives in hw/xfree86/drivers/modesetting/pageflip.c, in the retry loop of do_queue_flip_on_crtc(). My machine runs x11-server-xorg-21.1.24, so I fetched that file from the stable branch and from the development branch to compare:

$ grep -c -i tearfree pageflip.c          # server-21.1-branch
0
$ grep -c -i tearfree drmmode_display.c   # server-21.1-branch
0

$ grep -c -i tearfree pageflip.c          # master
39
$ grep -c -i tearfree drmmode_display.c   # master
13

Upstream's 21.1 stable branch has no TearFree code whatsoever. Not a reduced version, not a disabled version — it does not exist there. TearFree is a development-branch feature.

My Xorg log, however, says this:

[ 4554.667] (II) modeset(0): Atomic modesetting disabled
[ 4554.667] (II) modeset(0): TearFree: enabled

And the installed driver binary is full of it:

$ strings /usr/lib64/xorg/modules/drivers/modesetting_drv.so | grep -i tearfree
TearFree cannot synchronize PRIME; use 'PRIME Synchronization' instead
TearFree requires either universal planes, or setting 'Option "PageFlip" "off"'
TearFree requires Glamor acceleration
TearFree flip failed, rendering frame without TearFree
TearFree: enabled

So the feature is present in a release that upstream does not ship it in. The package changelog explains itself in one line:

$ rpm -q --changelog x11-server-xorg | grep -i tearfree
- Merge patchset from master upstream to enable screen Tearfree.

From 21.1.20-2.mga10, last October. Mageia backported the TearFree patchset from the development branch onto the stable branch, and enabled it by default.

I want to be careful about the tone here, because this is a genuinely reasonable thing for a distribution to do and I am not interested in dunking on a volunteer maintainer. TearFree eliminates tearing without a compositor, it is a real improvement, and it had presumably been soaking upstream for a while. The xorg-server 21.1 branch is in deep maintenance and gets essentially nothing but security fixes, so if you want any display improvement at all on X11 in 2026, backporting is the only mechanism available. That is the actual situation X11 is in.

But a backport takes code written against one set of surrounding assumptions and drops it into a different one, and the bugs that produces are exactly the kind that do not show up in testing: timing-dependent, hardware-dependent, and triggered by a transition — DPMS wake — that nobody thinks to exercise deliberately.

You can see the shape of what goes wrong by reading the retry loop in the development branch, which is TearFree-aware:

while (drmmode_crtc_flip(crtc, fb_id, x, y, flags, (void *)(long)seq)) {
    if (ms_flush_drm_events(screen) <= 0) {
        /* The failure could be caused by a pending TearFree flip, in which
         * case we should wait until there's a new event and try again. */
        if (!trf->flip_seq || ms_flush_drm_events_timeout(screen, -1) < 0) {
            ms_drm_abort_seq(crtc->scrn, seq);
            return TRUE;
        }
    }
    xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING, "flip queue retry\n");
}

That code knows about trf->flip_seq — a TearFree flip that is already in flight — and treats a flush failure differently depending on whether one exists. The bookkeeping around which flips are outstanding, and who owns the data structure each queued flip points at, is precisely the part that has to be right when the display is being torn down and brought back by DPMS. Get the ordering wrong and a queued flip's flipdata is freed while the kernel still has an event for it in the pipe. The event arrives, drmHandleEvent dispatches it, the callback reads through a dangling pointer, and you are looking at my backtrace.

One more thing from the log matters:

(II) modeset(0): Atomic modesetting disabled

That is upstream's default — the Atomic option is off unless you ask for it. With atomic off, flips go through the legacy drmModePageFlip path rather than drmModeAtomicCommit. So TearFree, backported onto a stable branch, running on the legacy flip path, on a hybrid-GPU laptop, across a DPMS transition. Four conditions, all of them true on this machine, and probably not all true on the machine where the backport was tested.


Somebody else already found it

Before deciding what to do I wanted to know whether this was known. That turned out to be harder than it should be: the freedesktop GitLab is behind proof-of-work bot protection, which blocks scripted access to both the web UI and the REST API. The Mageia bug tracker has a browser check of its own. Neither is unreasonable given what crawler traffic looks like now, but it does mean the old habit of grepping bug trackers from a terminal no longer works, and I ended up searching through a mirror of the same code base instead.

In the X11Libre fork's tracker — same modesetting driver, same code — there is issue #3432, "Xorg Server crash at 'flip queue retry'". Labels: hybrid-gpu-setup, intel-gpu, nvidia-gpu. The reporter has an Intel + NVIDIA laptop where X is not running on the NVIDIA card, and describes the trigger as:

the second i try to move a mouse or do anything which for removing dpms xserver crashes and i get thrown to my dm

Same hardware class, same trigger, same crash, same outcome. It is open, with no maintainer response and no patch.

There is also #1200, where the same flip queue retry warning floods the log on another hybrid Intel+NVIDIA machine, causing rendering freezes rather than a crash. Closed as not planned. The reporter notes the problem does not occur under Wayland.

So: known, unfixed, and specific to roughly the configuration I have. There is no patch to cherry-pick. That leaves mitigation.

One near-miss worth being careful about

Searching Mageia's own tracker turns up bug 29405, "Can't record my desktop in KDE Plasma", which mentions TearFree and Plasma and is still open. It is not this bug, and I want to be explicit about that rather than quietly cite it: different driver (the intel DDX, not modesetting), different symptom (screen recording captures the wrong frames — nothing crashes at all), different hardware era, and there TearFree is proposed as a workaround rather than being the cause.

The reason I looked twice is one line in its comment 10. Having suggested Option "TearFree" "true" on the intel DDX as a fix for the recording problem, the reporter comes back with:

But it stuck on suspend and resume

Two different DDX drivers, two independently written TearFree implementations, and both of them turn out to have trouble across a display power-management transition. That is not evidence about my crash — it is a different codebase and I have not read it. But it does suggest that "what happens to the flip bookkeeping when the display is torn down and brought back" is a recurring soft spot in this kind of code, which makes it a reasonable first place to look rather than a surprising one.

I mention it mostly as a caution. When you are deep in an investigation and find an old bug with three of your keywords in it, the pull to declare it a match is strong, and matching on keywords rather than mechanism is how you end up filing a duplicate of something unrelated and wasting a maintainer's afternoon.


The fix

The bug is in a backported feature. The most targeted thing I can do is switch that feature off, which removes the entire code path from the picture without touching anything else:

# /etc/X11/xorg.conf.d/20-modesetting-tearfree.conf
Section "Device"
    Identifier "Intel Graphics"
    Driver     "modesetting"
    Option     "TearFree" "false"
EndSection

Log out and back in — this needs a fresh X server, not just a Plasma restart — and confirm it took:

$ grep TearFree /var/log/Xorg.0.log
(II) modeset(0): TearFree: disabled

The cost is that tearing may come back in video playback and fullscreen content. On a Plasma desktop, KWin composites by default and handles that itself, so in practice I expect to notice very little. I would rather have occasional tearing than lose a session.

Two other options I considered and did not take:

Switch to Wayland. Both upstream reports say the problem does not occur there, and it cannot occur there — KWin on Wayland never runs this code. Plasma 6.5.5 and kwin-wayland are already installed on this machine. This is probably where I end up eventually; I did not do it today because I wanted to verify the diagnosis by fixing the specific thing I had identified, and changing display servers changes too many variables at once to prove anything.

Turn on atomic modesetting (Option "Atomic" "on"), which routes flips through drmModeAtomicCommit instead of the legacy path. That might sidestep the race. It might also be a different set of bugs — atomic is off by default upstream for reasons I have not investigated. Worth testing separately, not together with the TearFree change, or I will not know which one did what.


What I take from it

The whole investigation was about forty minutes once I stopped reading about Plasma and started reading the X server's log. Everything I needed was in two files that were already on disk.

The thing I would generalise is about layer attribution. The crash presented as a desktop environment problem, and the desktop environment was the most visible thing involved, and it was completely innocent. Every symptom I could see — session gone, apps gone, back to the login screen — was Plasma correctly handling a catastrophe that happened underneath it. ICE default IO error handler doing an exit() is not a crash message. It is a well-behaved program saying my display is gone, there is nothing further I can do.

The second thing is that rpm -q --changelog deserves to be a reflex. I have spent years comparing installed versions against upstream release notes and assuming a version number tells me what code I am running. It does not. A distribution package is upstream plus a patch stack, and on a stable branch the patch stack is where the interesting divergence lives. The single most useful command in this whole investigation was the one that printed a line of changelog from last October explaining why my X server contained a feature that its own version number says it should not have.


Mageia 10 (Cauldron), kernel 6.18.44, Plasma 6.5.5 on X11, x11-server-xorg 21.1.24-1.mga10. MSI Stealth 15M B12UE — Intel Alder Lake-P Iris Xe driving the display, NVIDIA RTX 3060 Mobile present but not scanning out (and quietly filling the kernel log with correctable PCIe errors, which is a different afternoon's problem). Filed against x11-server as Mageia bug 36308, with the backport, both backtraces, and X11Libre#3432.