OpenZFS · error log routing

How ZFS files, keeps, and reads a permanent error

A permanent error lands in one of two logs, decided by a single flag. A stray flag sent errors to the wrong one, where a later scan quietly made them permanent. Four commits fix the routing, heal the pools already hurt, and stop the tools from lying about it.

4 commits 2 kernel · 2 userland

The two logs

Last log
spa_errlog_last

The errors the last completed scan found. This is the settled record: what zpool status reports and what an error scrub re-checks.

Scrub log
spa_errlog_scrub

A scratch list a running scan fills as it goes. When the scan ends it is rotated into the last log, replacing it. It should be empty when no scan is running.

1 · Where a new error is filed

A read finds a bad block spa_log_error() files into one list, decided by the flag spa_scrub_active FIX · dsl_scan set the flag only while a scan is running BUG · zfs destroy latches the flag on and it is never cleared flag off → last log flag stuck on → scrub log LAST LOG spa_errlog_last where it belongs SCRUB LOG spa_errlog_scrub wrong, with no scan running
The cause. A dataset destroy set spa_scrub_active and nothing turned it back off, so ordinary read errors were filed in the scrub log as if a scan were running. During a real scan that right-hand path is correct; the fix is to set the flag only when a scan actually is.

2 · What the two logs feed

LAST LOG spa_errlog_last what scrub -e re-checks SCRUB LOG spa_errlog_scrub holds the stuck errors rotation: scrub log replaces last log FIX · spa: do this at import too zpool status -v reads both logs → lists the affected files zpool scrub -e reads the last log only status reads both logs scrub -e reads last only ✗ no path FIX · zpool: name entries that resolve to no file FIX · libzfs: empty last log reports, not exit 0
The contradiction, and the repair. An error stuck in the scrub log shows up in zpool status but zpool scrub -e cannot see it, and zpool clear never touches either log. The import-time rotation moves such a leftover into the last log, where the repair tool can finally reach it.

The state we found, and healed

Damaged pool, as imported
errlog_last0
errlog_scrub517
After import on the fixed build
errlog_last517
errlog_scrub0

Before, the errors were stranded in the scrub log and scrub -e refused. After import, the rotation put them in the last log, scrub -e ran, and reading them healed the ones whose blocks were gone.

The four commits

dsl_scan · the cause
Stop marking a scrub active for a destroy

A dataset destroy flipped the scan flag on and left it on, so read errors were filed as a scan's findings. Now the flag is set only while a scan truly runs, so nothing is misfiled.

dsl_scan_sync() · gate on dsl_scan_is_running()
spa · heal the hurt pools
Promote a stale scrub log at import

Pools already damaged by the old kernel are repaired on import: a leftover scrub log sitting over an empty last log is rotated into place, so an error scrub can reach the entries.

spa_load_impl() → spa_errlog_rotate()
libzfs · honest scrub -e
Report an error scrub with nothing to do

An error scrub on an empty last log used to exit zero in silence. Now it says the log is empty and to run a full scrub. Scrubbing all pools skips clean ones; -a refuses a pool name.

zpool_scan_range()
zpool · honest status -v
Explain a log that names no files

When recorded blocks were freed or rewritten, status printed a header promising files then listed none. Now it says plainly that the blocks could not be resolved to a file.

print_error_log()

Upstream reports

ReportOpenedStateWhat it describes
openzfs/zfs#138592022-09-09openPermanent errors after a clean scrub, with nothing else wrong
openzfs/zfs#144332023-01-25openPermanent errors listed against UNKNOWN files
openzfs/zfs#158762024-02-10openChronic corruption that lists no affected objects
openzfs/zfs#161582024-05-03openPermanent errors that point to no files — the canonical report
openzfs/zfs#167372024-11-09openzpool status reports inconsistent error information (count vs list)
openzfs/zfs#186782026-06-15openIntermittent false permanent errors