Veröffentlicht: Juli 17, 2026

CS2 hat mein System mehrfach hart abgeschossen. Nicht nur das Spiel — der ganze Fenstermanager war weg, Steam tot, VLC tot. Alles weg außer dem Cursor. Ich habe den Fix gefunden, eingebaut, neugestartet — und der Crash passierte wieder. Der Fix war aktiv, aber GRUB hat ihn nie gelesen. Hier ist warum.

Das eigentliche Problem: CS2 killt den GPU-Ring

Das dmesg-Log erzählt die Geschichte ziemlich klar:

amdgpu: ring gfx_0.0.0 timeout — Process MainThrd / thread dxvk-submit
amdgpu: MES failed to respond to msg=RESET
amdgpu: Ring gfx_0.0.0 reset failed
amdgpu: GPU reset begin! Source: 1
amdgpu: MODE1 reset
amdgpu: VRAM is lost due to GPU reset!
kwin_wayland_wrapper: amdgpu: The CS has cancelled because the context is lost.

DXVK schickt einen Submit an den GPU-Ring → Ring-Timeout → AMD MES soll resetten → MES antwortet nicht → Hardware-Reset → VRAM-Verlust → XWayland bricht weg → alle X11-Apps (Steam, VLC, …) sterben → plasmashell / KWin crashen.

Eine Kaskade. Und der Auslöser sitzt tief in der GPU-Firmware.

Was ist RDNA3 MES?

MES steht für Micro Engine Scheduler — eine kleine Firmware, die seit RDNA3 (RX 7000er-Serie) auf der GPU läuft und Command-Submission und GPU-Ring-Management übernimmt. Klingt gut, hat aber unter DXVK-Last auf aktuellen Linux-Kerneln bekannte Hang-Probleme: MES beantwortet den Reset-Befehl schlicht nicht, was den gesamten GPU-Zustand korrumpiert.

Der Fix: amdgpu.mes=0 und s2idle

Zwei Parameter müssen in die Kernel-Commandline:

  • amdgpu.mes=0 — schaltet den Firmware-basierten MES ab, nutzt stattdessen den älteren Software-Scheduler. Kein MES = kein MES-Hang.
  • mem_sleep_default=s2idle — behebt einen separaten Bug: S3-Resume auf RDNA3 (Navi 31) ist strukturell kaputt in aktuellen Kerneln, s2idle umgeht das durch einen leichteren Suspend-Zustand.

Also rein in /etc/default/grub:

GRUB_CMDLINE_LINUX_DEFAULT="nowatchdog nvme_load=YES splash loglevel=3 \
  amdgpu.ppfeaturemask=0xffffffff amdgpu.sg_display=0 \
  mem_sleep_default=s2idle amdgpu.mes=0"

Dann:

sudo grub-mkconfig -o /boot/grub/grub.cfg

Neugestartet. CS2 geöffnet. Crash.

Die Parameter waren immer noch nicht aktiv:

cat /proc/cmdline
# → kein mes=0, kein s2idle

Der eigentliche Bug: GRUB liest eine andere Datei

Auf CachyOS mit Btrfs und Snapper laufe ich von einem Snapshot, nicht vom Root-Subvolume. Das System bootet von @/.snapshots/284/snapshot. Wenn ich also /boot/grub/grub.cfg bearbeite, schreibe ich in die Snapshot-grub.cfg: @/.snapshots/284/snapshot/boot/grub/grub.cfg.

GRUB selbst startet aber früher — lange bevor das Betriebssystem weiß, welchen Snapshot es booten soll. GRUB liest vom Btrfs Default Subvolume, und der ist ID 5 (der @-Subvolume):

sudo btrfs subvolume get-default /
# → ID 5 (FS_TREE)

Das bedeutet: GRUB liest /@/boot/grub/grub.cfg. Nicht die Datei, die grub-mkconfig geschrieben hat.

Btrfs Subvolumes

Btrfs kennt kein klassisches Partitions-Konzept — stattdessen gibt es Subvolumes: unabhängige Teilbäume innerhalb desselben Dateisystems. CachyOS mit Snapper legt typischerweise @ als Haupt-Subvolume an und speichert Snapshots unter @/.snapshots/. Beim Booten wird dann nicht @, sondern ein bestimmter Snapshot als Rootfs gemountet. So kannst du bei einem kaputten Update einfach einen älteren Snapshot booten.

GRUB und der Btrfs FS_TREE

GRUB muss seine Konfigurationsdatei lesen, bevor irgendetwas anderes startet. Es kennt zu diesem Zeitpunkt keinen gemounteten Subvolume oder Snapshot — es liest direkt vom Btrfs Default Subvolume (FS_TREE, Subvolume-ID 5). Das ist fast immer @. Was das laufende System als /boot/grub/grub.cfg sieht, liegt aber im aktuell gemounteten Snapshot — eine völlig andere Datei.

Zur Bestätigung:

sudo mount -o subvolid=5 /dev/nvme1n1p2 /mnt/btrfs-root
grep 'mes=' /mnt/btrfs-root/@/boot/grub/grub.cfg
# → leer. Alte Parameter, kein mes=0.

Zwei Dateien. Beide heißen grub.cfg. GRUB liest die eine, grub-mkconfig schreibt in die andere.

Der einmalige Fix

Die aktuelle grub.cfg manuell in den @-Subvolume kopieren:

sudo mount -o subvolid=5 /dev/nvme1n1p2 /mnt/btrfs-root
sudo cp /boot/grub/grub.cfg /mnt/btrfs-root/@/boot/grub/grub.cfg
sudo cp /etc/default/grub  /mnt/btrfs-root/@/etc/default/grub
sudo umount /mnt/btrfs-root

Neugestartet. cat /proc/cmdline zeigte jetzt amdgpu.mes=0. CS2 läuft stabil.

Die dauerhafte Lösung: Pacman Hook

Einmal manuell kopieren reicht, aber beim nächsten Kernel-Update passiert genau dasselbe wieder. Die Lösung ist ein Pacman Hook, der nach jedem grub-mkconfig-Lauf automatisch synchronisiert.

Zuerst das Script unter /usr/local/bin/grub-btrfs-sync:

#!/bin/bash
DEVICE=$(findmnt -n -o SOURCE / | sed 's/\[.*//')
MOUNT_POINT=$(mktemp -d /tmp/btrfs-root-XXXXXX)
cleanup() { umount "$MOUNT_POINT" 2>/dev/null; rmdir "$MOUNT_POINT" 2>/dev/null; }
trap cleanup EXIT
mount -o subvolid=5 "$DEVICE" "$MOUNT_POINT" || exit 1
cp /boot/grub/grub.cfg "$MOUNT_POINT/@/boot/grub/grub.cfg"
echo "grub-btrfs-sync: grub.cfg synced to @ subvolume"
sudo chmod +x /usr/local/bin/grub-btrfs-sync

Dann der Hook unter /etc/pacman.d/hooks/zz-grub-btrfs-sync.hook:

[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = File
Target = usr/lib/modules/*/vmlinuz

[Action]
Description = Syncing GRUB config to Btrfs @ subvolume...
Depends = grub
When = PostTransaction
Exec = /usr/local/bin/grub-btrfs-sync

Pacman Hooks

Pacman Hooks sind Shell-Befehle, die Pacman automatisch vor oder nach bestimmten Paket-Operationen ausführt. Sie werden als .hook-Dateien in /etc/pacman.d/hooks/ abgelegt. Das zz--Präfix sorgt dafür, dass dieser Hook alphabetisch nach dem offiziellen grub.hook läuft — der grub-mkconfig aufruft. So ist die neue grub.cfg bereits geschrieben, wenn unser Sync-Script startet.

Ab sofort: bei jedem Kernel-Update wird grub-mkconfig ausgeführt, dann direkt danach die grub.cfg in den @-Subvolume synchronisiert. Das Problem tritt nie wieder auf.

Zusammenfassung

Zwei Bugs, eine Reboot-Session:

  1. RX 7900 XTX / RDNA3: amdgpu.mes=0 deaktiviert den buggy Micro Engine Scheduler → keine GPU-Ring-Timeouts unter DXVK. mem_sleep_default=s2idle verhindert GPU-Freeze nach Suspend.
  2. CachyOS + Btrfs + Snapper: grub-mkconfig schreibt in den Snapshot, GRUB liest vom @-Subvolume. Nach jedem GRUB-Update: manuell oder per Hook synchronisieren.

Der zweite Bug ist der gemeine — er macht den ersten unsichtbar. Wer keinen Snapshot-basierten Btrfs-Setup hat, wird das nie sehen. Wer ihn hat, versteht nicht, warum seine Kernel-Parameter einfach ignoriert werden.