fs/buffer: serialize set_buffer_uptodate against concurrent clears#1305
Open
vfsci-bot[bot] wants to merge 1 commit intovfs.base.cifrom
Open
fs/buffer: serialize set_buffer_uptodate against concurrent clears#1305vfsci-bot[bot] wants to merge 1 commit intovfs.base.cifrom
vfsci-bot[bot] wants to merge 1 commit intovfs.base.cifrom
Conversation
A WARN_ON_ONCE(!buffer_uptodate(bh)) in mark_buffer_dirty() is
reachable from the buffered write path on a block device when the
underlying device returns I/O errors at high density. Reproduced
by fuzzing an NVMe controller (FEMU) that returns crafted error
completions for a sustained workload from /dev/nvme0n1.
The contract documented at set_buffer_uptodate() in
include/linux/buffer_head.h reads:
Any other serialization (with IO errors or whatever that might
clear the bit) has to come from other state (eg BH_Lock).
In fs/buffer.c, BH_Uptodate can be cleared from four I/O completion
callbacks: __end_buffer_read_notouch, end_buffer_write_sync,
end_buffer_async_read, end_buffer_async_write.
end_buffer_async_read() runs with BH_Lock held throughout, so its
clear is already serialized against any caller that also holds
BH_Lock around set_buffer_uptodate(); the call may in fact be
redundant, but addressing that is independent of this fix.
end_buffer_write_sync() likewise holds BH_Lock while it clears
BH_Uptodate on the write-error path. Removing that clear would
change long-standing buffer-cache I/O-error semantics and is out
of scope here.
The race is therefore between block_commit_write() and
end_buffer_write_sync():
CPU A: block_commit_write CPU B: end_buffer_write_sync
(folio lock held, BH_Lock NOT) (BH_Lock held)
set_buffer_uptodate(bh);
clear_buffer_uptodate(bh);
unlock_buffer(bh);
mark_buffer_dirty(bh); /* WARN */
CPU B observes the contract; CPU A does not. With one side unlocked
the serialization is one-sided and ineffective: CPU A's set can be
immediately followed by CPU B's clear, tripping the WARN_ON_ONCE.
In the fuzzing reproducer, write-error completions are frequent
(visible as repeated "lost async page write" and per-LBA write
failures); buffer I/O completion callbacks on the write-error path
(e.g. end_buffer_write_sync, end_buffer_async_write) clear
BH_Uptodate while holding BH_Lock.
The bug is not benign: a not-uptodate buffer can be marked dirty
and subsequently written back; depending on whether the buffer was
fully or partially covered by the user write, this can leave on-disk
content that does not match the intended buffered write state.
Fix this by taking BH_Lock around set_buffer_uptodate() +
mark_buffer_dirty() in block_commit_write(), so both sides of the
contract use the documented serialization.
Found by FuzzNvme (Syzkaller with FEMU fuzzing framework).
Acked-by: Sungwoo Kim <iam@sung-woo.kim>
Acked-by: Dave Tian <daveti@purdue.edu>
Acked-by: Weidong Zhu <weizhu@fiu.edu>
Signed-off-by: Chao Shi <coshi036@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Series: https://patchwork.kernel.org/project/linux-fsdevel/list/?series=1087885
Submitter: Chao Shi
Version: 2
Patches: 1/1
Message-ID:
<20260430053645.1466196-1-coshi036@gmail.com>Base: vfs.base.ci
Lore: https://lore.kernel.org/linux-fsdevel/20260430053645.1466196-1-coshi036@gmail.com
Automated by ml2pr