* [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails
@ 2026-08-01 22:00 Chao Shi
2026-08-01 22:00 ` [PATCH 01/19] buffer_head: Remove b_page Chao Shi
` (18 more replies)
0 siblings, 19 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
When a metadata write fails, the buffer_head completion handlers clear
BH_Uptodate. The buffer still holds exactly the data the filesystem asked
to be written - it is the disk that is stale, not the buffer - and saying
otherwise has consequences:
- mark_buffer_dirty() has a WARN_ON_ONCE(!buffer_uptodate(bh)), so a
filesystem that dirties the buffer again to retry the write trips it.
That is the warning that started this.
- a buffer that is not up to date gets re-read from disk, which silently
replaces the data the filesystem was trying to write with the stale
on-disk copy.
- the state is not self consistent while it lasts: the window between the
write completing and BH_Uptodate being cleared is visible to anyone
holding the folio lock.
BH_Write_EIO already records that the last write failed. This series moves
every consumer over to it, then removes the clears.
Patches 1-3 are groundwork. Matthew's patch 1 removes b_page. Patches 2
and 3 let a buffer_head point at memory outside the page cache and use that
for jbd2's shadow buffers, which today sit on a slab folio - a slab folio
overloads ->mapping, so mark_buffer_write_io_error() cannot be called on
them at all. That is what blocked the jbd2 conversion.
Patches 4-5 make BH_Write_EIO safe to leave set: clear it in bforget() and
discard it on invalidate, so a freed or reused block does not inherit
somebody else's write error.
Patches 6-18 convert the consumers, one filesystem at a time: the two core
helpers in fs/buffer.c, then adfs, ext2, omfs, exfat, fat, ext4, ocfs2,
gfs2 and jbd2. Patch 19 removes the clears.
Every patch builds on its own and the tree behaves identically at each step
until patch 19, because a failed write currently sets BH_Write_EIO and
clears BH_Uptodate together.
Four things are worth a second look, and I would rather point at them than
let you find them:
- gfs2 (patch 15) is not a pure conversion. gfs2_end_log_write_bh()
already marks BH_Write_EIO without clearing BH_Uptodate, so the two ail
checks are blind to log write errors today and start catching them.
Jan and I agreed that is the desired fix rather than a regression, but
it is a real behaviour change for gfs2.
- ocfs2 (patch 14) has a check that turns the filesystem read-only when a
buffer whose previous write failed is handed back to a transaction. It
sits inside an if (!buffer_uptodate(bh)) that goes dead, so it has to be
hoisted or ocfs2 silently stops making that check. The code in that
patch is Jan's.
- after patch 19, BH_Write_EIO stays set until the buffer is written
again, forgotten or invalidated. So a site like ext4's itable sync
(patch 12) now reports on every subsequent sync rather than only on the
write that failed. That is intended, and matches what ocfs2 has always
done with this flag.
- the read path changes too. __bread_gfp() and bh_uptodate_or_lock()
currently re-read a buffer whose write failed, replacing the
filesystem's data with the stale on-disk copy. After patch 19 they
return the in-memory data. Better, but different.
On the original report: patch 19 provably closes that WARN for the write
error case, since the state it warns about can no longer be produced that
way. I could not reproduce the WARN itself with fail_make_request, which
fails synchronously at submit; the original came from a fuzzer injecting
delayed error completions, which is what opens the window. So there is no
ready reproducer to offer, only the argument.
Based on vfs.git vfs.all, because Jan's "fs: Fix missed inode write during
fsync" series is in it and rewrites __ext4_handle_dirty_metadata(), which
patch 12 touches.
Testing: built and booted with all of the above filesystems enabled;
checkpatch --strict clean on all 19; each patch built individually.
Patches 2 and 3 were validated by crashing with sysrq-b during ext4
data=journal,journal_checksum traffic engineered to force copy-out into
b_frozen_data, then replaying the journal on the next mount - recovery
completed, file contents matched, e2fsck -fn clean, and an instrumented
build confirmed the folio-less path was actually taken. I have not
exercised the adfs, omfs or exfat paths beyond compiling them.
The conversion was asked for here:
https://lore.kernel.org/linux-fsdevel/xaqwfkwjnp7h2lg7ir6wy2tnyay26t3im3ftkdl64rhys3rhmu@lc5vfh5tc2f5/
and the shape of it was settled in the two exchanges after it:
https://lore.kernel.org/linux-fsdevel/CACd_6n17-pJuNoCLsstP7goocedrr5F8T8BwTjRUNx8frKEPgA@mail.gmail.com/
https://lore.kernel.org/linux-fsdevel/bnchcfog427eo3bxt5h6qautlq7sb2o4ww7cjgad73biycdn5f@np7qkbyqizup/
Per-filesystem maintainers were not on that thread, hence the summary above.
The earlier attempt at this, which Jan correctly rejected, was
https://lore.kernel.org/linux-fsdevel/20260430053645.1466196-1-coshi036@gmail.com/
Chao Shi (18):
buffer: allow a buffer_head to point at memory outside the page cache
jbd2: point the shadow buffer at the frozen data directly
buffer: clear BH_Write_EIO when a buffer is forgotten
buffer: discard BH_Write_EIO along with the rest of the buffer state
buffer: detect metadata write errors with buffer_write_io_error()
adfs: check for a directory write error with buffer_write_io_error()
ext2: check for an xattr block write error with
buffer_write_io_error()
omfs: check for an inode write error with buffer_write_io_error()
exfat: check for a directory write error with buffer_write_io_error()
fat: check for a metadata write error with buffer_write_io_error()
ext4: check for a metadata write error with buffer_write_io_error()
ocfs2: check for a metadata write error with buffer_write_io_error()
ocfs2: check for a stale write error before reusing a metadata buffer
gfs2: check for a metadata write error with buffer_write_io_error()
jbd2: report journal write errors with BH_Write_EIO
jbd2: assert on a failed write, not on a buffer that is not up to date
ext4, jbd2: report fast commit write errors with BH_Write_EIO
buffer: stop clearing BH_Uptodate when a write fails
Matthew Wilcox (Oracle) (1):
buffer_head: Remove b_page
fs/adfs/dir.c | 2 +-
fs/buffer.c | 26 +++++++++++++++++---------
fs/exfat/misc.c | 2 +-
fs/ext2/xattr.c | 2 +-
fs/ext4/ext4_jbd2.c | 2 +-
fs/ext4/fast_commit.c | 2 +-
fs/ext4/mmp.c | 2 +-
fs/fat/misc.c | 2 +-
fs/gfs2/log.c | 4 ++--
fs/gfs2/lops.c | 2 +-
fs/jbd2/commit.c | 20 +++++++++++++-------
fs/jbd2/journal.c | 21 +++++++++++++++------
fs/jbd2/transaction.c | 2 +-
fs/ocfs2/buffer_head_io.c | 12 +++++++-----
fs/ocfs2/journal.c | 25 +++++++++++++------------
fs/omfs/inode.c | 4 ++--
include/linux/buffer_head.h | 7 ++-----
17 files changed, 80 insertions(+), 57 deletions(-)
base-commit: 05c09c9c8a79d5539fef30d42e732eba90a15dcf
--
2.43.0
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 01/19] buffer_head: Remove b_page
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 02/19] buffer: allow a buffer_head to point at memory outside the page cache Chao Shi
` (17 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
All users except bh_offset() have been converted to use b_folio instead.
Convert bh_offset() and remove b_page.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
include/linux/buffer_head.h | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index fd2c7115c054..699970b4bbf2 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -59,10 +59,7 @@ struct address_space;
struct buffer_head {
unsigned long b_state; /* buffer state bitmap (see above) */
struct buffer_head *b_this_page;/* circular list of page's buffers */
- union {
- struct page *b_page; /* the page this bh is mapped to */
- struct folio *b_folio; /* the folio this bh is mapped to */
- };
+ struct folio *b_folio; /* the folio this bh is mapped to */
sector_t b_blocknr; /* start block number */
size_t b_size; /* size of mapping */
@@ -172,7 +169,7 @@ static __always_inline int buffer_uptodate(const struct buffer_head *bh)
static inline unsigned long bh_offset(const struct buffer_head *bh)
{
- return (unsigned long)(bh)->b_data & (page_size(bh->b_page) - 1);
+ return (unsigned long)(bh)->b_data & (folio_size(bh->b_folio) - 1);
}
/* If we *know* page->private refers to buffer_heads */
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 02/19] buffer: allow a buffer_head to point at memory outside the page cache
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
2026-08-01 22:00 ` [PATCH 01/19] buffer_head: Remove b_page Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 03/19] jbd2: point the shadow buffer at the frozen data directly Chao Shi
` (16 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
jbd2 builds a temporary buffer_head to write out the frozen copy of a
metadata block, and that copy lives in slab memory. Today jbd2 points the
temporary buffer at the slab folio backing it. A slab folio's ->mapping is
not an address_space, so anything that follows bh->b_folio->mapping there
gets garbage rather than NULL; mark_buffer_write_io_error() does exactly
that, and we are about to start calling it on this buffer.
Rather than teach every such helper about slab folios, allow bh->b_folio to
be NULL and let b_data point straight at the memory. Code that needs the
folio has to check. There are two places in this file:
- __bh_submit() adds the data by virtual address using
bio_add_virt_nofail(), and skips the cgroup accounting: a buffer that is
not in the page cache has no owning folio to attribute writeback to.
- buffer_set_crypto_ctx() returns early. fscrypt has no interest in a
buffer that is not part of a file mapping, which is why it already
returns when folio_mapping() comes back NULL.
Nothing sets b_folio to NULL yet, so this patch is a no-op on its own.
This is deliberately not a general capability. Buffers over highmem have
no permanent kernel virtual address, which is why folio_set_bh() records a
folio and an offset instead of an address. A folio-less buffer_head is
only valid over memory that is always mapped, and must not be passed to
bh_offset().
Suggested-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/buffer.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index be8b57a635cd..04fcc34e4fa6 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1099,12 +1099,16 @@ EXPORT_SYMBOL(__bforget);
static void buffer_set_crypto_ctx(struct bio *bio, const struct buffer_head *bh,
gfp_t gfp_mask)
{
- const struct address_space *mapping = folio_mapping(bh->b_folio);
+ const struct address_space *mapping;
/*
* The ext4 journal (jbd2) can submit a buffer_head it directly created
- * for a non-pagecache page. fscrypt doesn't care about these.
+ * for memory that is not in the page cache at all. fscrypt doesn't
+ * care about these.
*/
+ if (!bh->b_folio)
+ return;
+ mapping = folio_mapping(bh->b_folio);
if (!mapping)
return;
fscrypt_set_bio_crypt_ctx(bio, mapping->host,
@@ -1142,7 +1146,11 @@ static void __bh_submit(struct buffer_head *bh, blk_opf_t opf,
bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
bio->bi_write_hint = write_hint;
- bio_add_folio_nofail(bio, bh->b_folio, bh->b_size, bh_offset(bh));
+ if (bh->b_folio)
+ bio_add_folio_nofail(bio, bh->b_folio, bh->b_size,
+ bh_offset(bh));
+ else
+ bio_add_virt_nofail(bio, bh->b_data, bh->b_size);
bio->bi_end_io = end_bio;
bio->bi_private = bh;
@@ -1152,7 +1160,8 @@ static void __bh_submit(struct buffer_head *bh, blk_opf_t opf,
if (wbc) {
wbc_init_bio(wbc, bio);
- wbc_account_cgroup_owner(wbc, bh->b_folio, bh->b_size);
+ if (bh->b_folio)
+ wbc_account_cgroup_owner(wbc, bh->b_folio, bh->b_size);
}
blk_crypto_submit_bio(bio);
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 03/19] jbd2: point the shadow buffer at the frozen data directly
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
2026-08-01 22:00 ` [PATCH 01/19] buffer_head: Remove b_page Chao Shi
2026-08-01 22:00 ` [PATCH 02/19] buffer: allow a buffer_head to point at memory outside the page cache Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 04/19] buffer: clear BH_Write_EIO when a buffer is forgotten Chao Shi
` (15 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
When a metadata buffer has to be copied out before it can be journalled,
jbd2_journal_write_metadata_buffer() writes jh->b_frozen_data rather than
the page cache copy. b_frozen_data is kmalloc()ed, so folio_set_bh() makes
the shadow buffer point at a slab folio.
That is not something the buffer_head layer can reason about. A slab folio
overloads ->mapping, so a shadow buffer looks like it belongs to an
address_space when it does not. buffer_set_crypto_ctx() already has to use
folio_mapping() to avoid tripping over this, and it is the reason
mark_buffer_write_io_error() cannot be called on a shadow buffer today.
Point the shadow buffer at the frozen data itself instead: leave b_folio
NULL and set b_data. The previous patch taught fs/buffer.c to submit such
a buffer. The two commit-path checksum helpers are the only other users of
the shadow buffer's contents, and they take the data directly rather than
kmapping a folio that is already mapped.
Note that the shadow buffer must not be passed to bh_offset() while
b_folio is NULL. All four callers that can see one are handled here and in
the previous patch.
Tested with ext4 mounted data=journal,journal_checksum on a metadata_csum
filesystem, writing files whose every block begins with the JBD2 magic so
that escaping forces the copy-out, then crashing with sysrq-b without
unmounting and replaying the journal on the next mount. Recovery
completed, the file contents matched, e2fsck -fn was clean, and an
instrumented build confirmed the b_folio == NULL path was taken.
Suggested-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/jbd2/commit.c | 12 +++++++++---
fs/jbd2/journal.c | 19 ++++++++++++++-----
2 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 3029cb6f6d64..60273cddf434 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -330,6 +330,8 @@ static __u32 jbd2_checksum_data(__u32 crc32_sum, struct buffer_head *bh)
char *addr;
__u32 checksum;
+ if (!bh->b_folio)
+ return crc32_be(crc32_sum, bh->b_data, bh->b_size);
addr = kmap_local_folio(bh->b_folio, bh_offset(bh));
checksum = crc32_be(crc32_sum, addr, bh->b_size);
kunmap_local(addr);
@@ -357,10 +359,14 @@ static void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag,
return;
seq = cpu_to_be32(sequence);
- addr = kmap_local_folio(bh->b_folio, bh_offset(bh));
csum32 = jbd2_chksum(j->j_csum_seed, (__u8 *)&seq, sizeof(seq));
- csum32 = jbd2_chksum(csum32, addr, bh->b_size);
- kunmap_local(addr);
+ if (!bh->b_folio) {
+ csum32 = jbd2_chksum(csum32, bh->b_data, bh->b_size);
+ } else {
+ addr = kmap_local_folio(bh->b_folio, bh_offset(bh));
+ csum32 = jbd2_chksum(csum32, addr, bh->b_size);
+ kunmap_local(addr);
+ }
if (jbd2_has_feature_csum3(j))
tag3->t_checksum = cpu_to_be32(csum32);
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 09efa337649e..9e4cb04587b4 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -329,6 +329,7 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
struct buffer_head *new_bh;
struct folio *new_folio;
unsigned int new_offset;
+ bool frozen = false;
struct buffer_head *bh_in = jh2bh(jh_in);
journal_t *journal = transaction->t_journal;
@@ -354,8 +355,7 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
* we use that version of the data for the commit.
*/
if (jh_in->b_frozen_data) {
- new_folio = virt_to_folio(jh_in->b_frozen_data);
- new_offset = offset_in_folio(new_folio, jh_in->b_frozen_data);
+ frozen = true;
do_escape = jbd2_data_needs_escaping(jh_in->b_frozen_data);
if (do_escape)
jbd2_data_do_escape(jh_in->b_frozen_data);
@@ -400,13 +400,22 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
jh_in->b_frozen_triggers = jh_in->b_triggers;
copy_done:
- new_folio = virt_to_folio(jh_in->b_frozen_data);
- new_offset = offset_in_folio(new_folio, jh_in->b_frozen_data);
+ frozen = true;
jbd2_data_do_escape(jh_in->b_frozen_data);
}
escape_done:
- folio_set_bh(new_bh, new_folio, new_offset);
+ if (frozen) {
+ /*
+ * b_frozen_data is slab memory, not page cache. Point the
+ * buffer at it directly rather than at a slab folio, whose
+ * ->mapping is not an address_space.
+ */
+ new_bh->b_folio = NULL;
+ new_bh->b_data = jh_in->b_frozen_data;
+ } else {
+ folio_set_bh(new_bh, new_folio, new_offset);
+ }
new_bh->b_size = bh_in->b_size;
new_bh->b_bdev = journal->j_dev;
new_bh->b_blocknr = blocknr;
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 04/19] buffer: clear BH_Write_EIO when a buffer is forgotten
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (2 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 03/19] jbd2: point the shadow buffer at the frozen data directly Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 05/19] buffer: discard BH_Write_EIO along with the rest of the buffer state Chao Shi
` (14 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
BH_Write_EIO records that the last write of this buffer failed. It is
cleared when the buffer is submitted for write again - see the
test_set_buffer_req() check in __bh_submit() - but a filesystem freeing a
metadata block never submits it again. It calls bforget() and hands the
block back to the allocator, so the flag outlives the block it refers to.
That does not matter much today, because the write error is also recorded
by clearing BH_Uptodate and the buffer is discarded soon after. It starts
to matter in the rest of this series, which stops clearing BH_Uptodate on
write error and makes BH_Write_EIO the way a failed metadata write is
reported.
bforget() is where a filesystem says it no longer cares about this
buffer's contents, so clear the error there alongside the dirty flag.
Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/buffer.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/fs/buffer.c b/fs/buffer.c
index 04fcc34e4fa6..7889c30d8715 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1091,6 +1091,7 @@ EXPORT_SYMBOL(__brelse);
void __bforget(struct buffer_head *bh)
{
clear_buffer_dirty(bh);
+ clear_buffer_write_io_error(bh);
remove_assoc_queue(bh);
__brelse(bh);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 05/19] buffer: discard BH_Write_EIO along with the rest of the buffer state
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (3 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 04/19] buffer: clear BH_Write_EIO when a buffer is forgotten Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 06/19] buffer: detect metadata write errors with buffer_write_io_error() Chao Shi
` (13 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
discard_buffer() strips the state that describes where a buffer lives and
what has happened to it, because after an invalidate none of it applies any
more. BH_Write_EIO belongs in that set for the same reason: it describes a
write of the data that is being thrown away.
Leaving it set means a buffer_head reused for a different block starts life
carrying somebody else's write error. Like the bforget() change, this is
mostly theoretical today and becomes load bearing once the rest of the
series makes BH_Write_EIO the report of a failed metadata write.
Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/buffer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index 7889c30d8715..50a63d964815 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1518,7 +1518,7 @@ EXPORT_SYMBOL(folio_set_bh);
/* Bits that are cleared during an invalidate */
#define BUFFER_FLAGS_DISCARD \
(1 << BH_Mapped | 1 << BH_New | 1 << BH_Req | \
- 1 << BH_Delay | 1 << BH_Unwritten)
+ 1 << BH_Delay | 1 << BH_Unwritten | 1 << BH_Write_EIO)
static void discard_buffer(struct buffer_head * bh)
{
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 06/19] buffer: detect metadata write errors with buffer_write_io_error()
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (4 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 05/19] buffer: discard BH_Write_EIO along with the rest of the buffer state Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 07/19] adfs: check for a directory write error " Chao Shi
` (12 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
Both places in this file that report a metadata write error to a caller do
it by testing !buffer_uptodate() after waiting for the write. That works
only because the write completion handlers clear BH_Uptodate when the write
fails, which is what this series is removing: a buffer whose write failed
still holds the correct data, and saying otherwise makes callers rewrite,
re-read or WARN over a buffer that was never wrong.
BH_Write_EIO is the flag that actually means "the last write of this buffer
failed", and both handlers already set it via mark_buffer_write_io_error().
Test that instead.
No behaviour change: today a failed write through bh_end_write() or
bh_end_async_write() sets BH_Write_EIO and clears BH_Uptodate together, so
the two tests agree. They stop agreeing at the end of the series, and this
one stays right.
In __sync_dirty_buffer() the flag also refers unambiguously to the write we
just issued, because __bh_submit() clears it when it resubmits a buffer for
write.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/buffer.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index 50a63d964815..ac978d9090c2 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -618,7 +618,7 @@ int mmb_sync(struct mapping_metadata_bhs *mmb)
}
spin_unlock(&mmb->lock);
wait_on_buffer(bh);
- if (!buffer_uptodate(bh))
+ if (buffer_write_io_error(bh))
err = -EIO;
brelse(bh);
spin_lock(&mmb->lock);
@@ -2743,7 +2743,7 @@ int __sync_dirty_buffer(struct buffer_head *bh, blk_opf_t op_flags)
bh_submit(bh, REQ_OP_WRITE | op_flags, bh_end_write);
wait_on_buffer(bh);
- if (!buffer_uptodate(bh))
+ if (buffer_write_io_error(bh))
return -EIO;
} else {
unlock_buffer(bh);
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 07/19] adfs: check for a directory write error with buffer_write_io_error()
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (5 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 06/19] buffer: detect metadata write errors with buffer_write_io_error() Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 08/19] ext2: check for an xattr block " Chao Shi
` (11 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
adfs_dir_sync() spots a failed write by testing BH_Req together with
!BH_Uptodate. That relies on the write completion handler clearing
BH_Uptodate on error, which this series removes: a buffer whose write
failed still holds the data the filesystem asked to be written, so
declaring it not up to date is wrong and makes callers re-read it.
BH_Write_EIO says exactly what this code wants to know, and it implies
BH_Req, so the pair collapses into one test.
No behaviour change today - a failed write sets BH_Write_EIO and clears
BH_Uptodate together. It stops being a no-op at the end of the series,
where the new test is the one that still works.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/adfs/dir.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 11afa9e157aa..b8cc6a697a05 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -191,7 +191,7 @@ static int adfs_dir_sync(struct adfs_dir *dir)
for (i = dir->nr_buffers - 1; i >= 0; i--) {
struct buffer_head *bh = dir->bhs[i];
sync_dirty_buffer(bh);
- if (buffer_req(bh) && !buffer_uptodate(bh))
+ if (buffer_write_io_error(bh))
err = -EIO;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 08/19] ext2: check for an xattr block write error with buffer_write_io_error()
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (6 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 07/19] adfs: check for a directory write error " Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 09/19] omfs: check for an inode " Chao Shi
` (10 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
ext2_xattr_set2() spots a failed synchronous write by testing BH_Req
together with !BH_Uptodate. That relies on the write completion handler
clearing BH_Uptodate on error, which this series removes: a buffer whose
write failed still holds the data the filesystem asked to be written, so
declaring it not up to date is wrong and makes callers re-read it.
BH_Write_EIO says exactly what this code wants to know, and it implies
BH_Req, so the pair collapses into one test.
No behaviour change today - a failed write sets BH_Write_EIO and clears
BH_Uptodate together. It stops being a no-op at the end of the series,
where the new test is the one that still works.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/ext2/xattr.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
index be63f89402a3..39005ec23fe5 100644
--- a/fs/ext2/xattr.c
+++ b/fs/ext2/xattr.c
@@ -769,7 +769,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
if (IS_SYNC(inode)) {
sync_dirty_buffer(new_bh);
error = -EIO;
- if (buffer_req(new_bh) && !buffer_uptodate(new_bh))
+ if (buffer_write_io_error(new_bh))
goto cleanup;
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 09/19] omfs: check for an inode write error with buffer_write_io_error()
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (7 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 08/19] ext2: check for an xattr block " Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 10/19] exfat: check for a directory " Chao Shi
` (9 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
__omfs_write_inode() spots a failed synchronous write, on both the primary
block and each mirror, by testing BH_Req together with !BH_Uptodate. That
relies on the write completion handler clearing BH_Uptodate on error, which
this series removes: a buffer whose write failed still holds the data the
filesystem asked to be written, so declaring it not up to date is wrong and
makes callers re-read it.
BH_Write_EIO says exactly what this code wants to know, and it implies
BH_Req, so each pair collapses into one test.
No behaviour change today - a failed write sets BH_Write_EIO and clears
BH_Uptodate together. It stops being a no-op at the end of the series,
where the new test is the one that still works.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/omfs/inode.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
index 1d915ef72119..bc37029a4afb 100644
--- a/fs/omfs/inode.c
+++ b/fs/omfs/inode.c
@@ -145,7 +145,7 @@ static int __omfs_write_inode(struct inode *inode, int wait)
mark_buffer_dirty(bh);
if (wait) {
sync_dirty_buffer(bh);
- if (buffer_req(bh) && !buffer_uptodate(bh))
+ if (buffer_write_io_error(bh))
sync_failed = 1;
}
@@ -159,7 +159,7 @@ static int __omfs_write_inode(struct inode *inode, int wait)
mark_buffer_dirty(bh2);
if (wait) {
sync_dirty_buffer(bh2);
- if (buffer_req(bh2) && !buffer_uptodate(bh2))
+ if (buffer_write_io_error(bh2))
sync_failed = 1;
}
brelse(bh2);
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 10/19] exfat: check for a directory write error with buffer_write_io_error()
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (8 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 09/19] omfs: check for an inode " Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 11/19] fat: check for a metadata " Chao Shi
` (8 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
exfat_update_bhs() waits for the writes it issued and then tests
!buffer_uptodate() to find the ones that failed. That relies on the write
completion handler clearing BH_Uptodate on error, which this series
removes: a buffer whose write failed still holds the data the filesystem
asked to be written, so declaring it not up to date is wrong and makes
callers re-read it.
Test BH_Write_EIO, which is what the completion handler sets and what this
code actually wants to know.
No behaviour change today - a failed write sets BH_Write_EIO and clears
BH_Uptodate together. It stops being a no-op at the end of the series,
where the new test is the one that still works.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/exfat/misc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/exfat/misc.c b/fs/exfat/misc.c
index 6f11a96a4ffa..dfd0bbf31c94 100644
--- a/fs/exfat/misc.c
+++ b/fs/exfat/misc.c
@@ -187,7 +187,7 @@ int exfat_update_bhs(struct buffer_head **bhs, int nr_bhs, int sync)
for (i = 0; i < nr_bhs && sync; i++) {
wait_on_buffer(bhs[i]);
- if (!err && !buffer_uptodate(bhs[i]))
+ if (!err && buffer_write_io_error(bhs[i]))
err = -EIO;
}
return err;
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 11/19] fat: check for a metadata write error with buffer_write_io_error()
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (9 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 10/19] exfat: check for a directory " Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 12/19] ext4: " Chao Shi
` (7 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
fat_sync_bhs() waits for the writes it issued and then tests
!buffer_uptodate() to find the ones that failed. That relies on the write
completion handler clearing BH_Uptodate on error, which this series
removes: a buffer whose write failed still holds the data the filesystem
asked to be written, so declaring it not up to date is wrong and makes
callers re-read it.
Test BH_Write_EIO, which is what the completion handler sets and what this
code actually wants to know.
No behaviour change today - a failed write sets BH_Write_EIO and clears
BH_Uptodate together. It stops being a no-op at the end of the series,
where the new test is the one that still works.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/fat/misc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index be18f6b5819b..4a4cd0111e47 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -356,7 +356,7 @@ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
for (i = 0; i < nr_bhs; i++) {
wait_on_buffer(bhs[i]);
- if (!err && !buffer_uptodate(bhs[i]))
+ if (!err && buffer_write_io_error(bhs[i]))
err = -EIO;
}
return err;
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 12/19] ext4: check for a metadata write error with buffer_write_io_error()
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (10 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 11/19] fat: check for a metadata " Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 13/19] ocfs2: " Chao Shi
` (6 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
Two places detect a failed metadata write by testing !buffer_uptodate()
after waiting for it. That relies on the write completion handler clearing
BH_Uptodate on error, which this series removes: a buffer whose write
failed still holds the data the filesystem asked to be written, so
declaring it not up to date is wrong and makes callers re-read it.
ext4 already does this correctly for the superblock - see
ext4_commit_super(), which tests buffer_write_io_error() - so this brings
the other two into line.
In __ext4_handle_dirty_metadata() the old test also required BH_Req.
BH_Write_EIO implies it, so the pair collapses into one test. The new test
is also strictly stronger than consuming sync_dirty_buffer()'s return
value, because it still fires when the buffer was written by background
writeback and that write hit an error, which sync_dirty_buffer() does not
report.
Note that BH_Write_EIO stays set until the buffer is written again,
forgotten or invalidated, so an unrepaired itable block now reports on
every subsequent sync of that inode rather than only on the write that
failed. That is the intended behaviour and matches what ocfs2 has always
done with this flag.
No behaviour change today - a failed write sets BH_Write_EIO and clears
BH_Uptodate together. It stops being a no-op at the end of the series,
where the new test is the one that still works.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/ext4/ext4_jbd2.c | 2 +-
fs/ext4/mmp.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index 02b066299164..f338d6e3c29f 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -413,7 +413,7 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
}
if (inode && inode_needs_sync(inode)) {
sync_dirty_buffer(bh);
- if (buffer_req(bh) && !buffer_uptodate(bh)) {
+ if (buffer_write_io_error(bh)) {
ext4_error_inode_err(inode, where, line,
bh->b_blocknr, EIO,
"IO error syncing itable block");
diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c
index 7ce361484b38..4b18ddef468d 100644
--- a/fs/ext4/mmp.c
+++ b/fs/ext4/mmp.c
@@ -49,7 +49,7 @@ static int write_mmp_block_thawed(struct super_block *sb,
bh_submit(bh, REQ_OP_WRITE | REQ_SYNC | REQ_META | REQ_PRIO,
bh_end_write);
wait_on_buffer(bh);
- if (unlikely(!buffer_uptodate(bh)))
+ if (unlikely(buffer_write_io_error(bh)))
return -EIO;
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 13/19] ocfs2: check for a metadata write error with buffer_write_io_error()
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (11 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 12/19] ext4: " Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 14/19] ocfs2: check for a stale write error before reusing a metadata buffer Chao Shi
` (5 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
ocfs2_write_block() and ocfs2_write_super_or_backup() detect a failed write
by looking at BH_Uptodate afterwards. That relies on the write completion
handler clearing BH_Uptodate on error, which this series removes: a buffer
whose write failed still holds the data the filesystem asked to be written,
so declaring it not up to date is wrong and makes callers re-read it.
Test BH_Write_EIO instead. Note that ocfs2_write_block()'s test is the
positive one, so the sense has to be inverted rather than the flag simply
swapped.
The comment in ocfs2_write_block()'s error arm needs updating for the same
reason. It said the clustered uptodate information did not have to be
removed because the buffer was not marked locally uptodate; after this
series it is, so the reason no longer holds. Not advertising the block to
the cluster is still the right thing to do - the data is in memory but not
on disk - so only the justification changes, not the behaviour.
No behaviour change today - a failed write sets BH_Write_EIO and clears
BH_Uptodate together. It stops being a no-op at the end of the series,
where the new test is the one that still works.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/ocfs2/buffer_head_io.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c
index 7bfe377af2df..733ceda79ca1 100644
--- a/fs/ocfs2/buffer_head_io.c
+++ b/fs/ocfs2/buffer_head_io.c
@@ -66,12 +66,14 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
wait_on_buffer(bh);
- if (buffer_uptodate(bh)) {
+ if (!buffer_write_io_error(bh)) {
ocfs2_set_buffer_uptodate(ci, bh);
} else {
- /* We don't need to remove the clustered uptodate
- * information for this bh as it's not marked locally
- * uptodate. */
+ /*
+ * The buffer still holds what we tried to write, but it did
+ * not reach the disk, so don't advertise it to the cluster
+ * as up to date.
+ */
ret = -EIO;
mlog_errno(ret);
}
@@ -446,7 +448,7 @@ int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
wait_on_buffer(bh);
- if (!buffer_uptodate(bh)) {
+ if (buffer_write_io_error(bh)) {
ret = -EIO;
mlog_errno(ret);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 14/19] ocfs2: check for a stale write error before reusing a metadata buffer
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (12 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 13/19] ocfs2: " Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:00 ` [PATCH 15/19] gfs2: check for a metadata write error with buffer_write_io_error() Chao Shi
` (4 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
__ocfs2_journal_access() refuses to journal a buffer whose previous write
failed, and turns the filesystem read-only rather than risk metadata
inconsistency. That check sits inside an if (!buffer_uptodate(bh)) block,
because until now a failed write also cleared BH_Uptodate.
This series stops clearing BH_Uptodate on write error, so that outer test
would never fire again and ocfs2 would silently start reusing buffers whose
last write failed. Hoist the check out of the debug block, where it does
not depend on BH_Uptodate any more, and drop the now dead second half of
its condition.
The mlog() pair keeps its own !buffer_uptodate() guard: it is a separate
"we can safely remove this assertion after testing" debug aid about being
handed a buffer with no valid contents, which is a different question from
whether the last write of that buffer failed.
The unlocked test followed by a locked retest is deliberate. BH_Write_EIO
is cleared under the buffer lock when the buffer is submitted for write
again, so taking the lock and looking a second time avoids turning the
filesystem read-only over an error that a concurrent rewrite has already
cleared, while keeping the common case lock-free.
The code in this patch is Jan's, from the review discussion linked in the
cover letter.
Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/ocfs2/journal.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index d8afbc1a76bb..ea6802d894c2 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -676,19 +676,20 @@ static int __ocfs2_journal_access(handle_t *handle,
mlog(ML_ERROR, "giving me a buffer that's not uptodate!\n");
mlog(ML_ERROR, "b_blocknr=%llu, b_state=0x%lx\n",
(unsigned long long)bh->b_blocknr, bh->b_state);
-
+ }
+ /*
+ * A previous transaction with a couple of buffer heads fail
+ * to checkpoint, so all the bhs are marked as BH_Write_EIO.
+ * For current transaction, the bh is just among those error
+ * bhs which previous transaction handle. We can't just clear
+ * its BH_Write_EIO and reuse directly, since other bhs are
+ * not written to disk yet and that will cause metadata
+ * inconsistency. So we should set fs read-only to avoid
+ * further damage.
+ */
+ if (buffer_write_io_error(bh)) {
lock_buffer(bh);
- /*
- * A previous transaction with a couple of buffer heads fail
- * to checkpoint, so all the bhs are marked as BH_Write_EIO.
- * For current transaction, the bh is just among those error
- * bhs which previous transaction handle. We can't just clear
- * its BH_Write_EIO and reuse directly, since other bhs are
- * not written to disk yet and that will cause metadata
- * inconsistency. So we should set fs read-only to avoid
- * further damage.
- */
- if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) {
+ if (buffer_write_io_error(bh)) {
unlock_buffer(bh);
return ocfs2_error(osb->sb, "A previous attempt to "
"write this buffer head failed\n");
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 15/19] gfs2: check for a metadata write error with buffer_write_io_error()
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (13 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 14/19] ocfs2: check for a stale write error before reusing a metadata buffer Chao Shi
@ 2026-08-01 22:00 ` Chao Shi
2026-08-01 22:01 ` [PATCH 16/19] jbd2: report journal write errors with BH_Write_EIO Chao Shi
` (3 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:00 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
gfs2_ail1_start_one() and gfs2_ail1_empty_one() decide whether a buffer on
the ail reached the disk by looking at BH_Uptodate once it is no longer
busy. That relies on the write completion handler clearing BH_Uptodate on
error, which this series removes: a buffer whose write failed still holds
the data the filesystem asked to be written, so declaring it not up to date
is wrong and makes callers re-read it. Test BH_Write_EIO instead. In
gfs2_ail1_start_one() the test is the positive one, so the sense has to be
inverted rather than the flag simply swapped.
This is not a pure conversion for gfs2, because gfs2 already has a private
write completion handler that behaves the way this series is heading:
gfs2_end_log_write_bh() calls mark_buffer_write_io_error() and leaves
BH_Uptodate alone. Buffers completed through it are therefore invisible to
both tests today, and start being caught once they look at BH_Write_EIO.
That is a real behaviour change, and it is the one gfs2 wanted: a failed
log write now withdraws the filesystem instead of passing silently.
gfs2_pin() is a different case and gets a different treatment. Its
!buffer_uptodate() test is not only a proxy for a failed write - a buffer
with no valid contents at all is equally a reason to withdraw before
pinning it into a transaction - so the write error test is added to it
rather than replacing it.
Left alone deliberately: the BUG_ON(!buffer_uptodate(bh)) in gfs2_unpin()
and the two WARN_ON()s in fs/gfs2/rgrp.c. After this series they simply
stop firing for write errors, which is correct; turning them into
BUG_ON(buffer_write_io_error(bh)) would newly panic on an I/O error.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/gfs2/log.c | 4 ++--
fs/gfs2/lops.c | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 78bba8cc10b8..e3e0dcb1f567 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -107,7 +107,7 @@ __acquires(&sdp->sd_ail_lock)
gfs2_assert(sdp, bd->bd_tr == tr);
if (!buffer_busy(bh)) {
- if (buffer_uptodate(bh)) {
+ if (!buffer_write_io_error(bh)) {
list_move(&bd->bd_ail_st_list,
&tr->tr_ail2_list);
continue;
@@ -321,7 +321,7 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr,
active_count++;
continue;
}
- if (!buffer_uptodate(bh) &&
+ if (buffer_write_io_error(bh) &&
!cmpxchg(&sdp->sd_log_error, 0, -EIO))
gfs2_io_error_bh(sdp, bh);
/*
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 6dabe73ad790..3df6e4b7e8b9 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -48,7 +48,7 @@ void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
clear_buffer_dirty(bh);
if (test_set_buffer_pinned(bh))
gfs2_assert_withdraw(sdp, 0);
- if (!buffer_uptodate(bh))
+ if (!buffer_uptodate(bh) || buffer_write_io_error(bh))
gfs2_io_error_bh(sdp, bh);
bd = bh->b_private;
/* If this buffer is in the AIL and it has already been written
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 16/19] jbd2: report journal write errors with BH_Write_EIO
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (14 preceding siblings ...)
2026-08-01 22:00 ` [PATCH 15/19] gfs2: check for a metadata write error with buffer_write_io_error() Chao Shi
@ 2026-08-01 22:01 ` Chao Shi
2026-08-01 22:01 ` [PATCH 17/19] jbd2: assert on a failed write, not on a buffer that is not up to date Chao Shi
` (2 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:01 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
The journal's own write completion handler,
journal_end_buffer_io_sync(), reports a failed write by clearing
BH_Uptodate, and the three places that wait for journal writes look for
that. This series is removing that convention: a buffer whose write failed
still holds the data that was supposed to reach the disk, and saying it is
not up to date makes callers rewrite, re-read or WARN over data that was
never wrong.
Set BH_Write_EIO instead, with mark_buffer_write_io_error(), and test it in
journal_wait_on_commit_record() and in the two commit-phase waits.
The two changes have to go together, because commit phase 4 waits on a
mixed list: descriptor blocks are submitted with
journal_end_buffer_io_sync(), while revoke blocks go through
write_dirty_buffer() and land in bh_end_write(). bh_end_write() already
sets BH_Write_EIO, so converting the consumer alone would keep working for
revoke blocks and silently stop detecting failed descriptor writes. With
the handler converted, both halves of the list report the same way.
mark_buffer_write_io_error() is safe on all of these buffers. The shadow
buffers from jbd2_journal_write_metadata_buffer() have no folio and no
associated mapping, so it does nothing beyond setting the flag. Descriptor
and commit blocks are ordinary buffers on the journal device, and marking
the journal's mapping with the error is what write_dirty_buffer() already
does for revoke blocks on the same device.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/jbd2/commit.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 60273cddf434..8912786ebebb 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -39,7 +39,7 @@ static void journal_end_buffer_io_sync(struct bio *bio)
if (uptodate)
set_buffer_uptodate(bh);
else
- clear_buffer_uptodate(bh);
+ mark_buffer_write_io_error(bh);
if (orig_bh) {
clear_and_wake_up_bit(BH_Shadow, &orig_bh->b_state);
}
@@ -169,7 +169,7 @@ static int journal_wait_on_commit_record(journal_t *journal,
clear_buffer_dirty(bh);
wait_on_buffer(bh);
- if (unlikely(!buffer_uptodate(bh)))
+ if (unlikely(buffer_write_io_error(bh)))
ret = -EIO;
put_bh(bh); /* One for getblk() */
@@ -840,7 +840,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
wait_on_buffer(bh);
cond_resched();
- if (unlikely(!buffer_uptodate(bh)))
+ if (unlikely(buffer_write_io_error(bh)))
err = -EIO;
jbd2_unfile_log_bh(bh);
stats.run.rs_blocks_logged++;
@@ -883,7 +883,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
wait_on_buffer(bh);
cond_resched();
- if (unlikely(!buffer_uptodate(bh)))
+ if (unlikely(buffer_write_io_error(bh)))
err = -EIO;
BUFFER_TRACE(bh, "ph5: control buffer writeout done: unfile");
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 17/19] jbd2: assert on a failed write, not on a buffer that is not up to date
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (15 preceding siblings ...)
2026-08-01 22:01 ` [PATCH 16/19] jbd2: report journal write errors with BH_Write_EIO Chao Shi
@ 2026-08-01 22:01 ` Chao Shi
2026-08-01 22:01 ` [PATCH 18/19] ext4, jbd2: report fast commit write errors with BH_Write_EIO Chao Shi
2026-08-01 22:01 ` [PATCH 19/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:01 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
jbd2_freeze_jh_data() asserts that the buffer it is about to copy out is up
to date. Once this series stops clearing BH_Uptodate on write error, that
assertion stops firing for the case it was written for, because a buffer
whose write failed stays up to date - which is the point: the in-memory
copy being frozen is still the data the filesystem wants written.
Assert on the condition that still means something went wrong. The message
loses its "Possible", because BH_Write_EIO is not a guess.
Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/jbd2/transaction.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index 5cc7d097b2ac..fdabe34a7e22 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -920,7 +920,7 @@ static void jbd2_freeze_jh_data(struct journal_head *jh)
char *source;
struct buffer_head *bh = jh2bh(jh);
- J_EXPECT_JH(jh, buffer_uptodate(bh), "Possible IO failure.\n");
+ J_EXPECT_JH(jh, !buffer_write_io_error(bh), "IO failure.\n");
source = kmap_local_folio(bh->b_folio, bh_offset(bh));
/* Fire data frozen trigger just before we copy the data */
jbd2_buffer_frozen_trigger(jh, source, jh->b_triggers);
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 18/19] ext4, jbd2: report fast commit write errors with BH_Write_EIO
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (16 preceding siblings ...)
2026-08-01 22:01 ` [PATCH 17/19] jbd2: assert on a failed write, not on a buffer that is not up to date Chao Shi
@ 2026-08-01 22:01 ` Chao Shi
2026-08-01 22:01 ` [PATCH 19/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:01 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
ext4_end_buffer_io_sync() is the third completion handler in this
series that reports a failed write by clearing BH_Uptodate, and
jbd2_fc_wait_bufs() is the only thing that looks at the result.
Convert both.
They have to move in the same patch. The handler lives in ext4 and
the wait in jbd2, but neither is used by anything else: the buffers
are ext4's fast commit blocks, submitted by ext4_fc_submit_bh() and
waited for by jbd2_fc_wait_bufs(). Converting one without the other
silently disables fast commit write error reporting.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/ext4/fast_commit.c | 2 +-
fs/jbd2/journal.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/ext4/fast_commit.c b/fs/ext4/fast_commit.c
index 8e2259799614..8cd60c9f2272 100644
--- a/fs/ext4/fast_commit.c
+++ b/fs/ext4/fast_commit.c
@@ -213,7 +213,7 @@ static void ext4_end_buffer_io_sync(struct bio *bio)
} else {
ext4_debug("%s: Block %lld not up-to-date",
__func__, bh->b_blocknr);
- clear_buffer_uptodate(bh);
+ mark_buffer_write_io_error(bh);
}
unlock_buffer(bh);
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 9e4cb04587b4..ffe7a22e6699 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -890,7 +890,7 @@ int jbd2_fc_wait_bufs(journal_t *journal, int num_blks)
* Update j_fc_off so jbd2_fc_release_bufs can release remain
* buffer head.
*/
- if (unlikely(!buffer_uptodate(bh))) {
+ if (unlikely(buffer_write_io_error(bh))) {
journal->j_fc_off = i + 1;
return -EIO;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 19/19] buffer: stop clearing BH_Uptodate when a write fails
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
` (17 preceding siblings ...)
2026-08-01 22:01 ` [PATCH 18/19] ext4, jbd2: report fast commit write errors with BH_Write_EIO Chao Shi
@ 2026-08-01 22:01 ` Chao Shi
18 siblings, 0 replies; 20+ messages in thread
From: Chao Shi @ 2026-08-01 22:01 UTC (permalink / raw)
To: Jan Kara, Christian Brauner, Alexander Viro, Matthew Wilcox,
linux-fsdevel
Cc: Theodore Ts'o, Andreas Dilger, Baokun Li, Ojaswin Mujoo,
Ritesh Harjani, Zhang Yi, Bob Copeland, Namjae Jeon, Sungjong Seo,
Yuezhang Mo, OGAWA Hirofumi, Mark Fasheh, Joel Becker, Joseph Qi,
Andreas Gruenbacher, linux-ext4, ocfs2-devel, gfs2,
linux-karma-devel, linux-kernel, Chao Shi
A buffer whose write failed still holds exactly the data the filesystem
asked to be written. It is the disk that is out of date, not the buffer.
Clearing BH_Uptodate says the opposite, and callers act on it:
- mark_buffer_dirty() has a WARN_ON_ONCE(!buffer_uptodate(bh)). A
filesystem that dirties the buffer again after a failed write - which is
the normal way to retry - trips it. That is the warning this series
started from.
- a buffer that is not up to date gets re-read from disk, which replaces
the data the filesystem was trying to write with the stale on-disk copy,
silently.
- the window between the write completing and the buffer being marked not
up to date is visible to anyone holding the folio lock, so the state is
not even self consistent while it lasts.
BH_Write_EIO already records the failure, and by now every place in the
tree that needs to know about it tests that flag instead: the two core
helpers in this file, adfs, exfat, ext2, ext4, fat, gfs2, jbd2, ocfs2 and
omfs, converted one filesystem at a time in the preceding patches. The
private completion handlers in jbd2 and ext4 fast commit were converted
along with their waiters. Nothing is left that reads BH_Uptodate to find
out whether a write failed, so the clears can go.
Found by FuzzNvme.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
fs/buffer.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index ac978d9090c2..0002f0736398 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -207,7 +207,6 @@ void bh_end_write(struct bio *bio)
} else {
buffer_io_error(bh, ", lost sync page write");
mark_buffer_write_io_error(bh);
- clear_buffer_uptodate(bh);
}
unlock_buffer(bh);
}
@@ -441,7 +440,6 @@ void bh_end_async_write(struct bio *bio)
} else {
buffer_io_error(bh, ", lost async page write");
mark_buffer_write_io_error(bh);
- clear_buffer_uptodate(bh);
}
first = folio_buffers(folio);
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
end of thread, other threads:[~2026-08-01 22:01 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-01 22:00 [PATCH 00/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
2026-08-01 22:00 ` [PATCH 01/19] buffer_head: Remove b_page Chao Shi
2026-08-01 22:00 ` [PATCH 02/19] buffer: allow a buffer_head to point at memory outside the page cache Chao Shi
2026-08-01 22:00 ` [PATCH 03/19] jbd2: point the shadow buffer at the frozen data directly Chao Shi
2026-08-01 22:00 ` [PATCH 04/19] buffer: clear BH_Write_EIO when a buffer is forgotten Chao Shi
2026-08-01 22:00 ` [PATCH 05/19] buffer: discard BH_Write_EIO along with the rest of the buffer state Chao Shi
2026-08-01 22:00 ` [PATCH 06/19] buffer: detect metadata write errors with buffer_write_io_error() Chao Shi
2026-08-01 22:00 ` [PATCH 07/19] adfs: check for a directory write error " Chao Shi
2026-08-01 22:00 ` [PATCH 08/19] ext2: check for an xattr block " Chao Shi
2026-08-01 22:00 ` [PATCH 09/19] omfs: check for an inode " Chao Shi
2026-08-01 22:00 ` [PATCH 10/19] exfat: check for a directory " Chao Shi
2026-08-01 22:00 ` [PATCH 11/19] fat: check for a metadata " Chao Shi
2026-08-01 22:00 ` [PATCH 12/19] ext4: " Chao Shi
2026-08-01 22:00 ` [PATCH 13/19] ocfs2: " Chao Shi
2026-08-01 22:00 ` [PATCH 14/19] ocfs2: check for a stale write error before reusing a metadata buffer Chao Shi
2026-08-01 22:00 ` [PATCH 15/19] gfs2: check for a metadata write error with buffer_write_io_error() Chao Shi
2026-08-01 22:01 ` [PATCH 16/19] jbd2: report journal write errors with BH_Write_EIO Chao Shi
2026-08-01 22:01 ` [PATCH 17/19] jbd2: assert on a failed write, not on a buffer that is not up to date Chao Shi
2026-08-01 22:01 ` [PATCH 18/19] ext4, jbd2: report fast commit write errors with BH_Write_EIO Chao Shi
2026-08-01 22:01 ` [PATCH 19/19] buffer: stop clearing BH_Uptodate when a write fails Chao Shi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).