From: Shashank Mohan Jain <jain.sm@gmail.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: Jeff Layton <jlayton@kernel.org>, Jan Kara <jack@suse.cz>,
NeilBrown <neil@brown.name>,
Thomas Maarseveen <maarseveent@gmail.com>,
linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 0/2] errseq: fix lost writeback errors in errseq_check_and_advance()
Date: Sun, 27 Sep 2026 10:47:24 +0530 [thread overview]
Message-ID: <20260927051726.71337-1-jain.sm@gmail.com> (raw)
errseq_check_and_advance() advances the caller's cursor to the value it
tried to store even when its cmpxchg() failed. If errseq_set() stored a
different errno in the meantime, the cursor holds a value that was
never in the errseq_t. errseq_set() does not bump the counter while the
current error is unseen, so recording the first errno again recreates
exactly that value, and once another subscriber has marked it seen, the
cursor's next check returns 0. For fsync() (file->f_wb_err) and
syncfs() (sb->s_wb_err) this means that a writeback error recorded
after the previous call returned is not reported. The race is rare: it
needs two different errnos, an error recorded while the check runs, and
a second subscriber consuming the value. There is no user report; it
was found with a model checker.
Patch 1 retries with the value found when the cmpxchg() fails, so the
cursor is only ever advanced to a value that was stored with
ERRSEQ_SEEN set. Patch 2 adds a KUnit case that races errseq_set()
against errseq_check_and_advance() on two CPUs.
Two behaviour changes are visible to callers, both intended. When a
writer wins the race, the call now returns the newer errno (still "the
latest error", as documented). And when two threads race on the same
unserialised cursor (syncfs() does not lock f_sb_err), the loser may
now return 0 where both used to return the error, so each open file
description gets one report.
Dependencies: patch 1 applies to mainline (fd179f8a05be) on its own and
carries Cc: stable. Patch 2 extends the errseq KUnit suite from commit
b52f5c1605f2 ("lib/tests: add KUnit tests for errseq"), which is only
in mm-nonmm-unstable, so the series is based on mm-nonmm-unstable
(e8d6475e77a7). Patch 1 could go through mm-hotfixes and patch 2
through mm-nonmm-unstable.
The bug was found with a TLA+ model of lib/errseq.c checked with TLC.
The patches were prepared with Claude Code (Anthropic), model Claude
Opus 5.5 (claude-opus-5-5).
Tested:
- KUnit on UML x86_64 (kunitconfig with CONFIG_ERRSEQ_KUNIT_TEST=y,
CONFIG_SMP=y and CONFIG_NR_CPUS=8, run with --kernel_args seccomp=on
--kernel_args ncpus=4). Without patch 1 the new case loses the error
in 21,957 to 116,003 of 2,000,000 rounds (1-6% over 8 runs,
depending on host load), in 44,886 with ncpus=2, and in 30,353 on
UML i386 with ncpus=4. With patch 1 it loses none (8 runs with 4
CPUs, 1 with 2 CPUs, 1 on i386). All other errseq cases pass. On a
single CPU the new case is skipped.
- A userspace replay of the unmodified lib/errseq.c, with a hook before
the cmpxchg() standing in for the other CPU, loses the error every
time.
- TLC: the current code violates "an error recorded after a check
returned is reported by the next check"; with patch 1 the property
holds exhaustively for 2 subscribers x 3 checks and either 1 writer
x 4 errors (1,364,445 distinct states) or 2 writers x 2 errors
(141,055,253 distinct states).
- W=1 builds of lib/errseq.o and lib/tests/errseq_kunit.o for UML
x86_64 and i386 without warnings, and checkpatch --strict.
Not tested: fsync() or syncfs() on a real failing device, weakly
ordered hardware (the model is sequentially consistent; the fix adds no
ordering requirement beyond cmpxchg()), and architectures other than
UML x86_64 and i386.
Shashank Mohan Jain (2):
errseq: don't let errseq_check_and_advance() hide later errors
lib/tests: errseq: add a concurrent check_and_advance test
lib/errseq.c | 29 +++++++----
lib/tests/errseq_kunit.c | 110 +++++++++++++++++++++++++++++++++++++--
2 files changed, 123 insertions(+), 16 deletions(-)
base-commit: e8d6475e77a75b7a84e42c9d23e238e002f2758f
--
2.43.0
next reply other threads:[~2026-09-27 5:17 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-27 5:17 Shashank Mohan Jain [this message]
2026-09-27 5:17 ` [PATCH 1/2] errseq: don't let errseq_check_and_advance() hide later errors Shashank Mohan Jain
2026-09-29 20:15 ` Jan Kara
2026-09-27 5:17 ` [PATCH 2/2] lib/tests: errseq: add a concurrent check_and_advance test Shashank Mohan Jain
2026-09-29 20:18 ` Jan Kara
2026-09-27 15:48 ` [PATCH 0/2] errseq: fix lost writeback errors in errseq_check_and_advance() Jeff Layton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260927051726.71337-1-jain.sm@gmail.com \
--to=jain.sm@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=jack@suse.cz \
--cc=jlayton@kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=maarseveent@gmail.com \
--cc=neil@brown.name \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®