1 Punkte von GN⁺ 2025-02-18 | 1 Kommentare | Auf WhatsApp teilen
  • Auf einem Linux-Desktop mit AMD RX 570 kam es beim Suspend mit hoher RAM-Auslastung nach dem Aufwachen wiederholt zu schwarzem Bildschirm oder nicht mehr reagierender Eingabe; daher musste über ein reines Anzeigeproblem hinaus bis in den Power-Management-Ablauf des Kernels nachverfolgt werden
  • Die Kernursache lag darin, dass amdgpu vor dem S3-Suspend VRAM in den System-RAM sichern muss, bei knappem freiem RAM aber Disk-Swap nicht korrekt nutzen konnte und durch OOM zusammenbrach
  • Ein erster Patch, der die VRAM-Eviction von dpm_suspend() nach dpm_prepare() vorzog, verringerte die Konkurrenz mit dem Abschalten der SSD, doch pm_restrict_gfp_mask() hatte Swap bereits deaktiviert, sodass weiterhin Mangel an zusammenhängendem Speicher auftreten konnte
  • Als später per register_pm_notifier() beim Ereignis PM_SUSPEND_PREPARE amdgpu_device_evict_resources() aufgerufen wurde, konnte VRAM gesichert werden, solange Swap und Datenträger noch verfügbar waren; in der Testumgebung gelang Suspend damit auch bei hoher RAM- und VRAM-Auslastung
  • Diese Änderung wurde in den amdgpu-Tree gemergt, aber 2025-06 wegen möglicher Deadlocks revertet; in Suspend-Pfaden, die Benutzerprozesse nicht zuerst einfrieren, können 3D-Apps VRAM wieder auf die GPU ziehen und die Eviction blockieren

Wiederholte Suspend-Fehlschläge und anfängliche Fehldiagnosen

  • Der Desktop war als Dual-Boot-System mit Windows und Linux eingerichtet; unter Linux scheiterte das System häufig, wenn bei hoher RAM-Auslastung Suspend versucht wurde
    • Nach dem Aufwachen war nur ein schwarzer Bildschirm mit beweglichem Cursor zu sehen, oder es gab keine Bildausgabe und das System reagierte nur noch auf Magic SysRq oder einen Hard Reset
    • In manchen Fällen aktualisierte sich die Uhr auf dem KDE-Sperrbildschirm in Echtzeit, beim Login oder bei Interaktion blieb das System jedoch hängen
  • Die Testumgebung bestand aus Gigabyte B550M DS3H, AMD RX 570 GPU, Kingston A2000 1 TB NVMe SSD, Arch Linux, systemd-boot und Linux 6.4
  • Beim Prüfen der Logs des vorherigen Boots mit journalctl --system -b -1 erschienen bei einigen Suspend-Versuchen OOM-Fehler im Kernel-Code unterhalb von amdgpu_device_suspend
  • Viele Fehlschläge endeten mit den folgenden Logzeilen; ein Eintrag, dass das beschädigte System wieder aufgewacht wäre, blieb aus
    • systemd-sleep: Entering sleep state 'suspend'...
    • Kernel: PM: suspend entry (deep)
  • Zunächst fiel der Verdacht auf den NVMe-APST-Energiesparmodus; Versuche mit nvme_core.default_ps_max_latency_us=0, iommu=soft, einem SSD-Firmware-Upgrade und dem Austausch gegen eine 2-TB-Boot-SSD lösten das Problem jedoch nicht

Debugging-Werkzeuge zur Eingrenzung der Fehlerstelle

  • Da systemd beim nacheinander Ausprobieren mehrerer Suspend-Modi Log-Rauschen erzeugen und den Kernel-Zustand verschlechtern kann, wurde in /etc/systemd/sleep.conf SuspendState=mem ergänzt
    • Das vereinfachte das Debugging, die eigentliche Ursache blieb jedoch bestehen
  • Mit echo 1 > /sys/power/pm_trace wurde die Stelle des Suspend-Fehlschlags verfolgt
    • pm_trace speichert den Fortschritt von Suspend/Resume in der Systemzeit
    • Durch den Nebeneffekt, dass asynchroner Suspend deaktiviert wird, zeigte sich außerdem, dass das System nach einem amdgpu-Suspend-Fehler teils wiederhergestellt wurde statt komplett zu hängen
  • Der Kernel-Parameter systemd.debug_shell wurde hinzugefügt, um auch ohne KDE- oder TTY-Login per Ctrl-Alt-F9 eine Root-Shell öffnen zu können
  • Für den Fall, dass USB-Controller und Tastatur ausfallen, wurde eine PS/2-Tastatur verwendet; später wurde zusätzlich eine serielle Konsole eingerichtet
    • Kernel-Parameter: no_console_suspend console=tty0 console=ttyS0,115200 loglevel=8
    • Auf einem Laptop wurden Logs mit sudo minicom --device /dev/ttyUSB0 --baudrate 115200 kontinuierlich mitgeschnitten
    • Die serielle Konsole ermöglichte auch nach Ausfall von Display und Netzwerk noch Befehlsausführung und Log-Erfassung, war aber bei Übertragungsrate sowie Farb- und Bildschirmgrößenbehandlung eingeschränkt

Zusammenhang zwischen amdgpu-VRAM-Eviction und OOM

  • Crash-Logs traten meist im TTM-Buffer-Eviction-Pfad von amdgpu auf
    • amdgpu_device_evict_resources()
    • amdgpu_ttm_evict_resources()
  • Aus verwandten Bugreports wurde klar, dass „evict“ mit dem Kopieren von VRAM in den System-RAM oder dem Verschieben von System-RAM in Swap zusammenhängt
  • Wenn der Desktop in S3-Suspend geht, wird die PCIe-GPU stromlos und die Daten in den VRAM-Chips gehen verloren
    • Der GPU-Treiber muss vor dem Suspend den belegten VRAM in den System-RAM kopieren
    • Nach dem Aufwachen muss er die im RAM gespeicherten Daten wiederherstellen
  • Im Linux-amdgpu-Treiber gab es das Problem, dass er bei zu wenig freiem RAM für den gesamten belegten VRAM nicht System-RAM in diskbasierten Swap auslagerte, sondern wegen Speichermangel abstürzte
  • Trifft Linux während des Suspend auf OOM, versucht es, den Suspend abzubrechen und Geräte neu zu starten; durch den bereits unterbrochenen Suspend können jedoch manche Treiber beschädigt sein oder während Suspend/Resume erneut OOM auslösen
    • Bei aktiviertem asynchronem Suspend ist das Risiko größer
    • Auch wenn der Suspend selbst erfolgreich war, kann beim Gerätestart während Resume OOM auftreten

Erster Lösungsversuch: VRAM-Sicherung früher ausführen

  • Mario Limonciello schlug vor, /sys/power/pm_print_times und /sys/power/pm_debug_messages zu aktivieren und die Suspend-Logs zu prüfen
  • Die Logs zeigten, dass NVMe- und amdgpu-Treiber während des Suspend parallel in pci_pm_suspend eintraten
  • Zunächst wurde nach einer Möglichkeit gesucht, den GPU-Suspend vor den SSD-Suspend zu ziehen; dabei wurde auch der Device-Suspend-Ordering-Mechanismus von Linux geprüft
    • Dieser Mechanismus schien eher für die Synchronisierung eng verbundener Peripheriegeräte gedacht zu sein als dafür, alle GPUs vor allen Systemdatenträgern zu suspenden
  • Mario schlug vor, VRAM in der prepare-Phase des Linux-Suspend zu evicten, und schrieb einen Kernel-Patch, der die VRAM-Eviction von dpm_suspend() nach dpm_prepare() verschob
  • Der Ablauf vor und nach der Änderung sah so aus
    • Bisher: Die VRAM-Sicherung läuft bei dpm_suspend() und kann sich mit dem Abschalten der SSD überschneiden
    • Geändert: In dpm_prepare() wird die VRAM-Sicherung zuerst versucht; schlägt sie fehl, wird der Suspend vor dem Suspend anderer Geräte abgebrochen
  • Diese Änderung war besser als zuvor, scheiterte bei hoher RAM-Auslastung aber weiterhin, weil pm_restrict_gfp_mask() Swap bereits vor dpm_prepare() deaktiviert
    • amdgpu_ttm_evict_resources() kann wegen Mangels an zusammenhängendem Speicher fehlschlagen
    • Selbst wenn der gesamte VRAM in den RAM passt, kann während Sleep oder Wake OOM auftreten, wenn nicht genug Spielraum für spätere Treiber-Allokationen bleibt

Separater amdgpu-Crash, gefunden mit Ghidra

  • Beim Testen trat der Fehler BUG: unable to handle page fault for address: fffffffffffffffc auf, der wie eine Dereferenzierung eines nahezu nullwertigen Pointers aussah
  • Das Crash-Log verwies auf die Stelle dm_resume+0x200, lieferte aber keine Zeilennummer im Quellcode
  • Nach dem Speichern und Extrahieren des Kernel-Moduls amdgpu.ko wurde es mit Ghidra dekompiliert, um die Crash-Stelle in dm_resume einer Kernel-Quellcodezeile zuzuordnen
  • Das Problem trat im Makro for_each_new_crtc_in_state(dm->cached_state, crtc, new_crtc_state, i) auf
    • dm->cached_state war kein gültiger Pointer, sondern fffffffffffffff4
    • Anschließend wurde das Feld [RSI + 0x8] gelesen, wodurch bei der Adresse fffffffffffffffc ein Page Fault entstand
  • Die Ursache lag im Ablauf, bei dem dm_suspend() den Rückgabewert von drm_atomic_helper_suspend() direkt in einem Pointer speicherte
    • drm_atomic_helper_suspend() kann einen gültigen Pointer oder ERR_PTR(err) zurückgeben
    • Durch OOM wurde -ENOMEM (-12) zurückgegeben; der amdgpu-Suspend-Code dereferenzierte dies offenbar wie einen Pointer
  • Mario behob dieses Problem, indem er Code ergänzte, der den Fehler-Rückgabewert prüft und den Suspend abbricht

Verworfener Ansatz: Swap während prepare() erlauben

  • Dass Suspend bei hoher RAM-Auslastung weiter fehlschlug, lag daran, dass amdgpu zwar in dpm_prepare() VRAM sichert, zu diesem Zeitpunkt aber pm_restrict_gfp_mask() den Disk-Swap bereits deaktiviert hat
  • Ein Versuch bestand darin, Swap in dpm_prepare() zu erlauben und ihn erst direkt vor dem Abschalten der Datenträger in dpm_suspend() zu deaktivieren
  • Dafür wurde experimentell der Aufruf von pm_restrict_gfp_mask() aus enter_state() tiefer nach dpm_suspend_start() verschoben
  • Die praktischen Einschränkungen waren erheblich
    • pm_restrict_gfp_mask() ist in kernel/power/power.h deklariert und wird aus kernel/power/suspend.c aufgerufen
    • Die gewünschte Aufrufstelle lag in drivers/base/power/main.c, und diese Datei bindet normalerweise keine Header aus kernel/power/ ein
    • Als temporärer Hack wurde #include <../kernel/power/power.h> ergänzt, eine Upstream-Übernahme hätte aber Überzeugungsarbeit erfordert
  • Auch beim hybriden Suspend gab es Korrektheitsprobleme
    • Hybrid Suspend speichert ein System-Image, ruft pm_restrict_gfp_mask() auf und ruft anschließend mit deaktiviertem Swap suspend_devices_and_enter() auf
    • Würde dieselbe Funktion erneut aufgerufen, gäbe es Warnungen, und pm_restore_gfp_mask() könnte Swap möglicherweise nicht wieder aktivieren
  • In Tests sank die Häufigkeit von Fehlschlägen oder Crashes, vollständig gelöst war das Problem aber nicht; da es eine fragile Änderung am zentralen Power Management war, wurde kein Upstream-Versuch unternommen

Userspace-Workaround: amdgpu-sleep

  • Im Oktober 2024 wurde nach dem Beenden von SuperTuxKart suspendet; beim Aufwachen trat ein schwarzer Bildschirm auf
    • Laut Log lief der erste Suspend-Versuch in dpm_prepare() in OOM, der nächste Versuch führte während Resume zu einem Crash bei einer Speicherallokation in bw_calcs() von amdgpu
  • Als Referenz diente NVIDIAs Userspace-Verfahren zur VRAM-Sicherung
    • NVIDIA führt VRAM-Sicherung und -Wiederherstellung über Services aus, die vor und nach dem Kernel-Suspend durch systemd laufen und in /proc/driver/nvidia/suspend schreiben
  • Darauf aufbauend wurde das Arch-Linux-Paket amdgpu-sleep erstellt
    • Vor dem Suspend wird /sys/kernel/debug/dri/1/amdgpu_evict_vram gelesen
    • Dieser Debug-Endpoint weist amdgpu an, den gesamten VRAM im System-RAM zu speichern
    • systemd wartet, bis die GPU-VRAM-Eviction abgeschlossen ist, und startet erst dann den Kernel-Suspend
  • Beim Suspend des Desktops wurde VRAM schnell in den Speicher kopiert; bei Bedarf wurde RAM in Swap gedrückt, sodass der Vorgang erfolgreich war
  • Wenn mehrere 3D-Apps liefen, renderten die Apps weiter Frames und holten VRAM zurück auf die GPU, wodurch ein Tauziehen-Livelock mit amdgpu_evict_vram entstand
    • Dieser Zustand dauerte über 70 Sekunden an, bevor amdgpu_evict_vram aufgab
    • Anschließend startete systemd den Kernel-Suspend und fror den Userspace ein; in der Kernel-Phase gelang die VRAM-Eviction dann
  • Dieses Skript blieb im Einsatz, weil Kernel-Level-Crashes bei deaktiviertem Skript nicht seltener auftraten als solche Livelocks

Finaler Patch: Power-Management-Notifier

  • Im November 2024 bat Mario darum, einen Patch zu testen, der Eviction erlaubt, solange Swap noch aktiv ist
  • Der Patch nutzte register_pm_notifier() und damit die Power-Management-Notifier-API von Linux
  • Der Callback erhält die Nachrichten PM_HIBERNATION_PREPARE und PM_SUSPEND_PREPARE und ruft amdgpu_device_evict_resources() auf
  • PM_SUSPEND_PREPARE wird in enter_state() → suspend_prepare() über pm_notifier_call_chain_robust(PM_SUSPEND_PREPARE, PM_POST_SUSPEND) ausgegeben
    • Treiber mit Notifier-Callback erhalten PM_SUSPEND_PREPARE
    • Tritt ein Fehler auf, erhalten bereits vorbereitete Treiber PM_POST_SUSPEND, und der Suspend wird abgebrochen
  • Wird VRAM an dieser Stelle evictet, geschieht das bevor pm_restrict_gfp_mask() Swap deaktiviert und solange die Datenträger noch nicht eingefroren sind
  • Der korrigierte Ablauf sieht so aus
    • suspend_prepare()
    • PM_SUSPEND_PREPARE
    • amdgpu_device_pm_notifier() → amdgpu_device_evict_resources()
    • pm_restrict_gfp_mask()
    • dpm_prepare()
    • dpm_suspend()
  • Nach dem Build eines Custom-Kernels mit dem geänderten amdgpu-Treiber traten in Tests auch bei hoher RAM- und VRAM-Auslastung über mehrere Suspend-Vorgänge hinweg keine Fehler auf
  • Allerdings sicherte amdgpu den VRAM, bevor PipeWire oder der Kernel die Lautsprecher stummschalteten, wodurch Audio einige Sekunden lang in einer Schleife wiedergegeben wurde
  • Nach mehreren Code-Review-Runden wurde die Änderung in den amdgpu-Tree gemergt und führte nach über einem Jahr an Versuchen zu einem Schritt, der diesen Bug beheben sollte

Update 2025-06 und Revert

  • Zunächst wurde erwartet, dass die Änderung in den Stable-Linux-Kernel 6.14 aufgenommen wird; später wurde sie jedoch wegen möglicher Deadlocks revertet
  • Das neu eingeführte Problem tritt auf, wenn systemd den System-Suspend aufruft, ohne vorher alle Userspace-Prozesse einzufrieren
    • Der Kernel versucht dann, VRAM in den System-RAM zu evicten, bevor er die Prozesse selbst einfriert
    • Holt gleichzeitig ein 3D-Programm VRAM zurück auf die GPU, kann die Suspend-Eviction deadlocken
  • Das ähnelt dem Livelock, der beim Userspace-Workaround amdgpu_evict_vram beobachtet wurde
  • Der Linux-PM-Maintainer schlug vor, den Aufruf von pm_restrict_gfp_mask() nach innerhalb von suspend_devices_and_enter() zu verschieben
    • Das entspricht der zuvor experimentierten Richtung, Swap während prepare() zu erlauben
  • Es gibt keinen Plan, dies selbst zu implementieren und einzureichen
    • Die AMD-GPU wurde in einen älteren Computer mit langsamerer CPU und 8 GB RAM umgebaut, und in dieser Umgebung sollen keine Kernel-Builds laufen
  • Der Hauptrechner wurde auf eine Intel Arc B570 aufgerüstet, doch auch bei 10 GB VRAM tritt derselbe Problemtyp auf
    • Dieses Problem wurde im drm/xe-Kernel-Bugtracker gemeldet

1 Kommentare

 
GN⁺ 2025-02-18
Meinungen auf Hacker News
  • Die Annahme, dass bei einem Desktop im S3-Suspend die Stromversorgung der PCIe-GPU abgeschaltet wird, ist nicht gesichert.
    Zwar schaltet S3 tatsächlich alles außer dem RAM ab, aber zum Beispiel Gigabyte-Aorus-Mainboards sind berüchtigt für einen NVMe-SSD-Suspend-Bug, durch den das System nicht richtig einschläft oder wieder aufwacht.
    Meist lässt sich das mit einer udev-Regel umgehen, die das Aufwecken über alle PCIe-Ports verhindert: ACTION=="offline", SUBSYSTEM=="pci", DRIVER=="pcieport", ATTR{power/wakeup}="disabled"
    Enger gefasst kann man nur den problematischen PCIe-Port angeben, etwa mit ATTR{vendor}=="0x8086", ATTR{device}=="0x43bc"; die Ursache lässt sich über /proc/acpi/wakeup, /sys/class/pci_bus/*/*/yourWakeupDevicePci/uevent | grep PCI_ID und udevadm info --attribute-walk /dev/whatever finden.
    Statt udev kann man /proc/acpi/wakeup auch in einem systemd-Service oder Automatisierungsskript umschalten, aber das ist weniger zuverlässig, und solche Linux-Suspend-Probleme sind wirklich zermürbend.

    • Auf meinem Mainboard musste ich in /etc/udev/rules.d/ ACTION=="add", KERNELS=="0000:00:01.1", ATTR{power/wakeup}="disabled" eintragen, um spontanes Aufwecken zu verhindern.
      Auch der Logitech-Bolt-Empfänger weckt mehrere Linux-Rechner sofort auf, unter Windows aber nicht; ich weiß nicht, warum, und es ist unklar, ob man für einen USB-Mitschnitt Geräte wie einen Logic Analyzer oder Glasgow braucht.
      Vorläufig habe ich das mit der Regel ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c548", ATTR{power/wakeup}="disabled" unterbunden.
    • Ich habe wegen dieses Problems auf einem Aorus-Mainboard wohl einige kWh vergeudet und hatte auf eine Lösung gehofft, aber in meinem Fall half es nicht.
    • Auch auf einem X570 Aorus Master hatte ich Suspend-Probleme; sie waren behoben, nachdem beim Booten eine systemd-Unit echo GPP0 >> /proc/acpi/wakeup ausgeführt hat.
      Allerdings wachte das System nach dem Booten beim ersten Suspend immer sofort wieder auf; mit der obigen udev-Regel scheint auch dieses Problem gelöst zu sein.
    • Man hofft, dass sich erkennen lässt, ob die Hardware tatsächlich eingeschlafen ist, oder dass es unproblematisch ist, Hardware wieder aufzuwecken, die gar nicht eingeschlafen war.
      Es sollte doch möglich sein, einem PCIe-Gerät einen Suspend-Befehl zu schicken und danach den Bus selbst schlafen zu legen; beim Aufwecken dann zuerst den Bus wiederherzustellen und anschließend das Gerät zu wecken.
    • Ich habe mich eine Weile mit diesem Problem herumgeschlagen, aber auch diese Methode hat nicht funktioniert; meine Zusammenfassung steht unter https://bbs.archlinux.org/viewtopic.php?id=302440.
      In meinem Fall scheint die Wakeup-Ursache von .../devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:45/wakeup/wakeup6 zu kommen, aber ich weiß nicht genau, was dieser Pfad bedeutet.
  • Als Autor von memreserver, einem der erwähnten Userspace-Workarounds, habe ich dieses Problem vor einigen Jahren debuggt.
    Der öffentliche Kommentar, den ich auf die Schnelle finden konnte, ist https://gitlab.freedesktop.org/drm/amd/-/issues/2125#note_17...; ich meine, es gab auch eine Diskussion auf der Mailingliste.
    Der Kernpunkt war, dass Linux keine gestuften Suspend-Hooks hatte, die zuverlässig ausgeführt werden, bevor Teile des Festplatten- und Speichersubsystems eingefroren werden; inzwischen scheint das möglich zu sein.
    Leider scheint Freedesktop Gitlab schlecht indexiert zu sein, sodass dieses Wissen wohl verschüttet wurde.

  • Wirklich hervorragende Arbeit.
    Falls man sich gefragt hat, warum es unter Linux so schwierig ist, den Wechsel in den Energiesparmodus zuverlässig hinzubekommen und zu debuggen, zeigt dieser Beitrag allein schon sehr gut, an wie vielen Stellen etwas kaputtgehen kann.
    Auf meinem ThinkPad P1G4 schalten sich die Lüfter bis heute vor dem Sleep nicht automatisch ab, wenn ich sie nicht manuell ausschalte, und seit Kurzem bekomme ich nach dem Aufwachen aus dem Sleep Störgeräusche in Bluetooth-Kopfhörern, sodass ich auch das Node-Sleep von PipeWire deaktivieren musste: https://wiki.archlinux.org/title/PipeWire#Noticeable_audio_d...

    • Es ist erstaunlich, dass sleep/suspend auf Linux-Laptops selbst 2025 noch immer nicht richtig funktioniert.
      Das erste Mal hatte ich solche Probleme vermutlich vor etwa 15 Jahren.
    • Sleep ist wirklich Glückssache, und Fehler wie der im Artikel sind extrem schwer zu debuggen.
      Unter den für verschiedene Probleme vorgeschlagenen Workarounds gibt es einige, die Stromsparmodi abschalten; da man Sleep normalerweise nutzt, um die Akkulaufzeit zu verlängern, ist das wenig praktikabel, weil es die tatsächliche Nutzungsdauer deutlich verkürzen kann.
      Trotzdem ist es nicht unmöglich, S0ix-Sleep zum Laufen zu bringen.
      Ich habe Arch Linux auf Handhelds mit AMD 7840U und AMD 8840U installiert, nämlich GPD Win Max 2, GPD Win Mini, GPD Win 4, Minisforum V3 und OneXPlayer X1 Ryzen; es erscheint eher unwahrscheinlich, dass diese Firmen mit Blick auf Linux-Support entwickelt oder getestet haben.
      Dennoch bekam ich, abgesehen vom neuesten OneXPlayer X1 Ryzen, nahezu perfekten S0ix-Support, indem ich nur ein wenig an falschen Wakeup-Quellen in /proc/acpi/wakeup und /sys/devices/*/*/*/power/wakeup gedreht habe.
      Auch der grundlegende Linux-Kernel-Support ist hervorragend: Touchscreen, Stifteingabe, Wi-Fi und Bluetooth funktionieren gut, und die einzige Lücke, die ich gesehen habe, ist die Unterstützung des Fingerabdrucksensors.
      Solche kleineren Hersteller betreiben weniger extreme Bauteil-Anpassung und weniger eng verzahnte Integration; praktisch zeigt sich das daran, dass die Geräte ein paar Millimeter dicker sind.
      Dadurch wählen sie wohl konservativere Komponenten, und das könnte dazu führen, dass der Linux-Support überraschend gut ist.
    • Wenn Endnutzer Sleep einfach und zuverlässig nutzen wollen, ist die Lösung, validierte kompatible Hardware zu kaufen.
      Meiner Erfahrung nach war das bei Business-ThinkPads schon seit Langem sehr stabil, und Windows-Nutzer desselben Modells scheinen eher häufiger Sleep-Probleme zu haben.
  • Ich bin persönlich wirklich dankbar.
    Mein Haupt-Laptop ist ein Ryzen-basiertes ThinkPad mit Linux, und ich nutze Sleep und Ruhezustand häufig; dieses Problem ist bei mir sporadisch aufgetreten.
    Ich freue mich auf Linux 6.14.

  • Der Grund, warum dm->cached_state statt eines Zeigers -12 gespeichert hat, ist höchstwahrscheinlich, dass während des Suspend dm_suspend() einfach dm.cached_state = drm_atomic_helper_suspend(adev_to_drm(adev)) zugewiesen hat.
    Das aufgerufene drm_atomic_helper_suspend() kann entweder einen gültigen Zeiger oder einen per negativem Zeiger als Fehler kodierten ERR_PTR(err) zurückgeben; der Aufrufer hat den Fehler nicht geprüft, sondern ihn direkt in den Zeiger geschrieben und ihn beim Resume dereferenziert.
    Noch ein weiterer Grund, Rust in den Kernel zu bringen: Wenn die Behandlung des Result-Typs erzwungen wird, ist so etwas deutlich schwerer möglich.

    • Auch mit dem C-Präprozessor kann man algebraische Summentypen bauen: https://github.com/Hirrolot/datatype99
      Aber Defaults sind wichtig, und die lange Geschichte des Kernels, die Modernisierung von Coding-Praktiken aufzuschieben, wirkt sich ungünstig auf Verbesserungen auf der C-Seite aus.
      Ironischerweise frustriert derselbe Widerstand auch Rust-Entwickler, weil selbst das Aufräumen einzelner Subsysteme oder das Dokumentieren ihrer Funktionsweise kaum akzeptiert wird.
      Dinge wie https://github.com/llvm/llvm-project/issues/74205 könnten helfen, wenn sie bis in den Kernel durchsickern, aber vermutlich würde man trotzdem weiter manuell Zeiger überladen, statt Sicherheit über Typen herzustellen.
  • Ich nutze Dual-Boot mit Linux/Windows auf einem Framework-AMD-Laptop mit GPU-Erweiterungsmodul, daher dürfte diese Arbeit für mich hilfreich sein.
    Ich würde gern direkt unterstützen oder an eine bevorzugte Wohltätigkeitsorganisation spenden; Kontaktmöglichkeiten stehen im Profil.

  • Ich dachte, Naming, Cache-Invalidierung und Off-by-one-Fehler seien die zwei größten Probleme der Informatik, aber seit ich sleep/wake-Probleme kenne, wirkt das NP-vollständig.

    • sleep/wake ist meiner Ansicht nach eine Teilmenge von Cache-Invalidierung.
      Wenn nicht jedes Peripheriegerät einen Zustand hätte, wäre es vermutlich kein Problem.
    • Nur unter Linux; unter Windows ist es O(n²), unter macOS O(log n).
  • Unter Linux sind Speicherverwaltung und insbesondere OOM-Situationen immer noch ein unglaublich schmerzhafter Albtraum.
    Ich habe solche Probleme zwar nicht ständig, aber ich bin definitiv schon daran gescheitert, ähnliche Probleme zu debuggen, und am Ende steckt man bei OOM meist einfach mehr RAM dazu.
    Das ist verschwenderisch und teuer, aber OOM-Situationen elegant zu behandeln, dürfte für Linux auch künftig ein schwer zu lösendes Problem bleiben.
    Diese Arbeit ist hervorragend und wird künftig als Referenzpunkt dienen, wenn man ähnliche Probleme debuggt.
    Auch die debug-shell-Funktion von systemd ist erfreulich; ich wusste nicht, dass es so etwas gibt.
    Allerdings scheint mein X670E-Steel-Legend-Board keinen seriellen Header zu haben; ich frage mich, wie integrierte serielle Ports heutzutage funktionieren.
    Hängen sie an den PCIe-Lanes des Chipsatzes?
    Wenn man sich in den Linux-Kernel vertieft, helfen Aufzeichnungen von Kernel-Subsystem-Vorträgen etwa von FOSDEM oder der Linux Plumbers Conference sehr. Ein Video zum TTM-Speichersubsystem, das die meisten Desktop-GPU-DRM-Treiber verwenden, ist zum Beispiel hier: https://www.youtube.com/watch?v=MG7_tUNKSt0

    • Unter Windows wird der serielle Port meines Mainboards als mit Pci Bus → PCI standard ISA bridge verbunden angezeigt.
      DOS hoch lebe.
      Das TTM-Video schaue ich mir an, wenn ich Zeit habe.
    • OOM mit cgroups einzugrenzen, hat ziemlich gut funktioniert.
      Ich weiß nicht wirklich, ob es modernere OOM-Behandlungsansätze gibt, die besser sind als das, was Linux macht; falls es dazu lesenswerte Materialien gibt, würde ich sie gern kennen.
    • Genau, selbst freundlich formuliert ist es furchtbar.
      Linux behandelt OOM-Situationen nicht ordentlich.
      Ich weiß, dass man mit cgroups Leitplanken setzen, earlyoom installieren oder mehr Swap beziehungsweise zram verwenden kann.
      Aber am Ende sind das alles nur schmutzige Hacks, die einen gelegentlich einmal retten können, und sie ändern nichts daran, wie solche Situationen behandelt werden.
      Ich wünschte, solche Dinge würden nicht als Lösung präsentiert.
      Ich habe gesehen, wie der Kernel in dm_crypt keinen Speicher mehr allozieren konnte und ein LUKS-Volume sich selbst read-only gemountet hat; bitte, es reicht doch, einen einzelnen Userspace-Prozess zu töten.
      Der aktuelle Zustand ist schlicht nicht akzeptabel, und die Ausreden bin ich leid.
    • Ich frage mich, ob du zswap/zram ausprobiert hast.
      Mit zstd kann man 8 GB RAM ohne große Probleme wie 20 GB „RAM“ nutzen, 16 GB wie 40 GB.
      Noch aggressiver kann man Speicher auch über 100 % overcommitten; Android macht das ebenfalls, daher ist es ein ziemlich stabiler Ansatz.
  • Gute Nachrichten.
    AMDs Linux-Grafiktreiber haben insgesamt gut funktioniert, aber genau dieses Problem war die Ausnahme, die ich mehrfach erlebt habe.

    • Ich hatte etwas weniger Glück.
      Das Problem, das ich in letzter Zeit sehe, ist, dass der Treiber nach dem Aufwachen aus dem Standby nach WARNING: CPU: 12 PID: 11871 at drivers/gpu/drm/amd/amdgpu/../display/dc/dc_helper.c:100 generic_reg_update_ex+0x1d2/0x290 [amdgpu] fortlaufend "[drm] scheduler comp_1.0.n is not ready, skipping" ins Log schreibt.
      https://gitlab.freedesktop.org/drm/amd/-/issues/3911
    • Meine Erfahrung ist insgesamt auch gut, aber wenn ich Thunderbolt mit angeschlossenem Monitor trenne, während das Gerät schläft, tritt ein ähnliches Problem auf.
      Allerdings ist es ein Laptop, daher ist die Treiberkonfiguration deutlich anders, und es gibt auch keine PCIe-GPU.
  • Dass man das Kernelmodul amdgpu.ko speichert und herauszieht, es anschließend mit Ghidra dekompiliert und dann die Absturzstelle in dm_resume der entsprechenden Zeile im Kernel-Quellcode zuordnet, ist beim Debugging immer einer meiner Lieblingsmomente.