Skip to content

zram: retry the device reset instead of dying silently at boot - #312

Open
kyleinoregon wants to merge 1 commit into
OpenCentauri:mainfrom
kyleinoregon:zram-reset-retry
Open

zram: retry the device reset instead of dying silently at boot#312
kyleinoregon wants to merge 1 commit into
OpenCentauri:mainfrom
kyleinoregon:zram-reset-retry

Conversation

@kyleinoregon

Copy link
Copy Markdown

What I found

My Centauri Carbon was running with no swap at all, although cosmos sets up a 200 % zram swap at boot. free showed Swap: 0, and the kernel log had zram: Added device: zram0 followed by nothing: no capacity change, no "Adding … swap". Two reboots later it came up fine, a third time it failed again, so it is a race.

I added a trace to /etc/init.d/zram and caught the failing boot:

=== boot trace: uptime 18s args=start ===
ls: /dev/zram0: No such file or directory
ls: /sys/block/zram0: No such file or directory
+ set -e
+ start
+ FACTOR=200
+ '[' -f /etc/default/zram ]
+ true
+ factor=200
+ grep MemTotal /proc/meminfo
+ awk ' { print $2 } '
+ memtotal=117232
+ disksize=240091136
+ modprobe zram 'num_devices=1'
+ echo 'zram devices probed successfully'
zram devices probed successfully
+ echo 1
sh: write error: Device or resource busy

Right after modprobe zram, udev opens the new block device to probe it. While it is open, the write to /sys/block/zram0/reset fails with EBUSY, and because the script runs with set -e it just stops there, before mkswap and swapon. Nothing reports it.

Running the same script by hand a minute later works every time, which is why this is easy to miss.

Why it matters on this board

With 114 MB of RAM the machine idles at about 16 MB free. Without swap, an ordinary event like uploading a gcode file from the slicer while a print is starting (Moonraker spawns its metadata scanner) took free memory from 20 MB to 8 MB in a few seconds, Klipper stalled, and the toolhead MCU shut down with "Timer too close". With the zram swap active there is over 200 MB of headroom for exactly that. I suspect a fair number of "Timer too close" reports come from machines that lost this race at boot.

Change

  • udevadm settle --timeout=5 after the modprobe when udevadm exists (it does on the image).
  • Retry the reset for up to five seconds (20 tries, 250 ms apart) instead of failing on the first EBUSY.
  • If it still cannot reset, say so on the console and return non-zero, rather than dying silently.

Everything after the reset is unchanged: same algorithm, size, tuning and priority.

Tested

On a Centauri Carbon running 26.08.0. Before the change, with the traced script, the failure reproduced on one boot in four (trace above). After the change, three reboots in a row came up with the 234 MB zram swap active; the trace shows udevadm settle returning in about 60 ms and the reset then succeeding on the first try, so on this machine the settle alone closes the window and the retry loop is the safety net for boards without udevadm or with slower udev.

The zram init script runs with "set -e". Right after "modprobe zram" udev
opens the new block device to probe it, and while it is open the write to
/sys/block/zram0/reset fails with EBUSY, which ends the script before
mkswap and swapon ever run. Nothing reports the failure: the kernel log
shows "zram: Added device" and then silence, and the machine runs with no
swap at all. It is a race, so it does not happen on every boot.

Wait for udev to settle when udevadm is available, then retry the reset
for up to five seconds, and say so on the console if it still fails.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants