<feed xmlns='http://www.w3.org/2005/Atom'>
<title>linux-toradex.git/fs/jbd2, branch master</title>
<subtitle>Linux kernel for Apalis and Colibri modules</subtitle>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/'/>
<entry>
<title>Merge tag 'ext4_for_linus-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4</title>
<updated>2026-10-26T02:09:13+00:00</updated>
<author>
<name>Linus Torvalds</name>
<email>torvalds@linux-foundation.org</email>
</author>
<published>2026-10-26T02:09:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=ac5feaad48f0910b3db4047c298dd11157aef1f4'/>
<id>ac5feaad48f0910b3db4047c298dd11157aef1f4</id>
<content type='text'>
Pull ext4 updates from Ted Ts'o:
 "Add support for buffered iomap support in ext4. This is not enabled by
  default, but requires the buffered_iomap mount option, as this mode
  does not support online defragmentation, inline data, fsverify,
  fscrypt, non-extent inodes, and data=journal mode. If buffered_iomap
  is enabled, ext4 will fall back to the original I/O code path
  automatically if necessary. Large writes show significant performance
  improvements when buffered iomap is enabled.

  There are also miscellaneous bug fixes and improvements, including for
  fast commit and avoiding deadlocks and out-of-bound reads when
  handling corner cases involving corrupted file systems"

* tag 'ext4_for_linus-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (41 commits)
  ext4: introduce a mount option for iomap buffered I/O path
  ext4: partially enable iomap for the buffered I/O path of regular files
  ext4: add tracepoints for EOF block zeroing and disksize-grow I/O
  ext4: add tracepoints for DISKSIZE_GROW_PENDING set, clear, and wait
  ext4: set DISKSIZE_GROW_PENDING after zeroing unaligned EOF block
  ext4: clear DISKSIZE_GROW_PENDING on truncate or error
  ext4: submit and wait for disksize-grow I/O in fallocate paths
  ext4: defer i_disksize update while DISKSIZE_GROW_PENDING is set
  ext4: advance i_disksize to i_size upon disksize-grow I/O completion
  ext4: submit and wait for pending disksize-grow I/O on writeback
  ext4: add EXT4_STATE_DISKSIZE_GROW_PENDING state bit and helpers
  ext4: disable online defrag when inode using iomap buffered I/O path
  ext4: add block mapping tracepoints for iomap buffered I/O path
  ext4: drain writeback before removing extents on the iomap path
  ext4: implement partial block zero range path using iomap
  ext4: implement mmap path using iomap
  ext4: implement writeback path using iomap
  ext4: rework handle credit accounting for unwritten extent conversion
  ext4: implement buffered write path using iomap
  ext4: do not use data=ordered mode for inodes using buffered iomap path
  ...
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Pull ext4 updates from Ted Ts'o:
 "Add support for buffered iomap support in ext4. This is not enabled by
  default, but requires the buffered_iomap mount option, as this mode
  does not support online defragmentation, inline data, fsverify,
  fscrypt, non-extent inodes, and data=journal mode. If buffered_iomap
  is enabled, ext4 will fall back to the original I/O code path
  automatically if necessary. Large writes show significant performance
  improvements when buffered iomap is enabled.

  There are also miscellaneous bug fixes and improvements, including for
  fast commit and avoiding deadlocks and out-of-bound reads when
  handling corner cases involving corrupted file systems"

* tag 'ext4_for_linus-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (41 commits)
  ext4: introduce a mount option for iomap buffered I/O path
  ext4: partially enable iomap for the buffered I/O path of regular files
  ext4: add tracepoints for EOF block zeroing and disksize-grow I/O
  ext4: add tracepoints for DISKSIZE_GROW_PENDING set, clear, and wait
  ext4: set DISKSIZE_GROW_PENDING after zeroing unaligned EOF block
  ext4: clear DISKSIZE_GROW_PENDING on truncate or error
  ext4: submit and wait for disksize-grow I/O in fallocate paths
  ext4: defer i_disksize update while DISKSIZE_GROW_PENDING is set
  ext4: advance i_disksize to i_size upon disksize-grow I/O completion
  ext4: submit and wait for pending disksize-grow I/O on writeback
  ext4: add EXT4_STATE_DISKSIZE_GROW_PENDING state bit and helpers
  ext4: disable online defrag when inode using iomap buffered I/O path
  ext4: add block mapping tracepoints for iomap buffered I/O path
  ext4: drain writeback before removing extents on the iomap path
  ext4: implement partial block zero range path using iomap
  ext4: implement mmap path using iomap
  ext4: implement writeback path using iomap
  ext4: rework handle credit accounting for unwritten extent conversion
  ext4: implement buffered write path using iomap
  ext4: do not use data=ordered mode for inodes using buffered iomap path
  ...
</pre>
</div>
</content>
</entry>
<entry>
<title>jbd2: don't advance j_fc_off before the buffer is recorded</title>
<updated>2026-10-08T15:05:45+00:00</updated>
<author>
<name>Daejun Park</name>
<email>daejun7.park@samsung.com</email>
</author>
<published>2026-08-19T06:09:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=9f359c031885bb50add7d23c7a5a0e9755b134c9'/>
<id>9f359c031885bb50add7d23c7a5a0e9755b134c9</id>
<content type='text'>
jbd2_fc_get_buf() increments journal-&gt;j_fc_off before jbd2_journal_bmap()
and __getblk() have had a chance to fail.  When either does, the slot
j_fc_wbuf[fc_off] is never assigned, but j_fc_off already counts it.

ext4 then fails the fast commit and falls back, and the fallback path
reaches jbd2_fc_release_bufs() via ext4_fc_commit -&gt;
jbd2_fc_end_commit_fallback -&gt; __jbd2_fc_end_commit -&gt; ext4_fc_cleanup.
That walks down from j_fc_off - 1 and put_bh()es every slot until it
sees NULL, so it also touches the slot that was never written.
j_fc_wbuf comes from a plain kmalloc() and is never zeroed, so a slot
used for the first time holds uninitialised heap data.

Advance j_fc_off only after the buffer head has been stored.  That
restores the invariant that j_fc_off covers exactly the filled slots,
which is what jbd2_fc_release_bufs() relies on: the live buffers of the
current fast commit sit above the NULLs the previous one released, so
stopping at the first NULL is correct.

Reproduced on a KASAN kernel with an ext4 fast_commit filesystem on a
loop device, truncating the backing file under the live mount so that
only the journal's fast-commit region falls past the end of the device.
__getblk() then fails for the first fast-commit block while the rest of
the journal is still addressable, so the journal is not aborted and the
fast commit reaches the fallback path.  j_fc_wbuf was poisoned to make
the read of the never-written slot visible:

  BUG: KASAN: wild-memory-access in jbd2_fc_release_bufs+0x6b/0xd0
  Write of size 4 at addr 5a5a5a5a5a5a5ab2 by task sync/961
   jbd2_fc_release_bufs+0x6b/0xd0
   ext4_fc_cleanup+0x97/0x830
   __jbd2_fc_end_commit+0x37/0xc0
   ext4_fc_commit+0x524/0x560
   ext4_sync_file+0x3c4/0x4b0
   __x64_sys_fsync+0x20/0x30

With this patch the same run leaves j_fc_off at 0 across repeated
__getblk() failures and completes cleanly.

Fixes: ff780b91efe9 ("jbd2: add fast commit machinery")
Cc: stable@kernel.org
Reported-by: Yu Junzhe &lt;junzheyu1@gmail.com&gt;
Closes: https://lore.kernel.org/linux-ext4/7e4b109d-64c3-444f-a5dc-93c2ca4576cc@gmail.com/
Signed-off-by: Daejun Park &lt;daejun7.park@samsung.com&gt;
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Link: https://patch.msgid.link/20260819060939epcms2p37bb8589b2f8a52a2b14bef38fadcf69d@epcms2p3
Signed-off-by: Theodore Ts'o &lt;tytso@mit.edu&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
jbd2_fc_get_buf() increments journal-&gt;j_fc_off before jbd2_journal_bmap()
and __getblk() have had a chance to fail.  When either does, the slot
j_fc_wbuf[fc_off] is never assigned, but j_fc_off already counts it.

ext4 then fails the fast commit and falls back, and the fallback path
reaches jbd2_fc_release_bufs() via ext4_fc_commit -&gt;
jbd2_fc_end_commit_fallback -&gt; __jbd2_fc_end_commit -&gt; ext4_fc_cleanup.
That walks down from j_fc_off - 1 and put_bh()es every slot until it
sees NULL, so it also touches the slot that was never written.
j_fc_wbuf comes from a plain kmalloc() and is never zeroed, so a slot
used for the first time holds uninitialised heap data.

Advance j_fc_off only after the buffer head has been stored.  That
restores the invariant that j_fc_off covers exactly the filled slots,
which is what jbd2_fc_release_bufs() relies on: the live buffers of the
current fast commit sit above the NULLs the previous one released, so
stopping at the first NULL is correct.

Reproduced on a KASAN kernel with an ext4 fast_commit filesystem on a
loop device, truncating the backing file under the live mount so that
only the journal's fast-commit region falls past the end of the device.
__getblk() then fails for the first fast-commit block while the rest of
the journal is still addressable, so the journal is not aborted and the
fast commit reaches the fallback path.  j_fc_wbuf was poisoned to make
the read of the never-written slot visible:

  BUG: KASAN: wild-memory-access in jbd2_fc_release_bufs+0x6b/0xd0
  Write of size 4 at addr 5a5a5a5a5a5a5ab2 by task sync/961
   jbd2_fc_release_bufs+0x6b/0xd0
   ext4_fc_cleanup+0x97/0x830
   __jbd2_fc_end_commit+0x37/0xc0
   ext4_fc_commit+0x524/0x560
   ext4_sync_file+0x3c4/0x4b0
   __x64_sys_fsync+0x20/0x30

With this patch the same run leaves j_fc_off at 0 across repeated
__getblk() failures and completes cleanly.

Fixes: ff780b91efe9 ("jbd2: add fast commit machinery")
Cc: stable@kernel.org
Reported-by: Yu Junzhe &lt;junzheyu1@gmail.com&gt;
Closes: https://lore.kernel.org/linux-ext4/7e4b109d-64c3-444f-a5dc-93c2ca4576cc@gmail.com/
Signed-off-by: Daejun Park &lt;daejun7.park@samsung.com&gt;
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Link: https://patch.msgid.link/20260819060939epcms2p37bb8589b2f8a52a2b14bef38fadcf69d@epcms2p3
Signed-off-by: Theodore Ts'o &lt;tytso@mit.edu&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>buffer: clear BH_Write_EIO when a write succeeds, not when one starts</title>
<updated>2026-09-10T07:27:27+00:00</updated>
<author>
<name>Chao Shi</name>
<email>coshi036@gmail.com</email>
</author>
<published>2026-08-06T16:58:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=336e794c59173407d22cfc1f254c517c264ef9ed'/>
<id>336e794c59173407d22cfc1f254c517c264ef9ed</id>
<content type='text'>
BH_Write_EIO is cleared in __bh_submit(), when a buffer that has been
written before is submitted for write again.  That is early: it says the
error is gone at the moment we start trying to fix it, rather than when we
have.

It also loses errors.  A task whose write fails sets the flag and then goes
to look at it; if another task redirties the buffer and resubmits it in
between, the submission clears the flag and the first task sees no error at
all.  Neither of them is doing anything wrong.

Clear it on successful write completion instead, in the end io handlers -
the same three the rest of this series has been converting, plus gfs2's,
which already marked errors this way.  Then the flag means what it says:
the last write of this buffer that finished, failed.  A resubmission no
longer hides an error that has not been fixed yet, and one that has been
fixed clears the flag when the data reaches the disk.

__bh_submit() keeps setting BH_Req, which is what the rest of the tree
reads it for.

Suggested-by: Jan Kara &lt;jack@suse.cz&gt;
Acked-by: Weidong Zhu &lt;weizhu@fiu.edu&gt;
Signed-off-by: Chao Shi &lt;coshi036@gmail.com&gt;
Link: https://patch.msgid.link/1c976fd191aa6e99dbe65d6a1ec63f8706cc0dfa.1785951556.git.coshi036@gmail.com
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Signed-off-by: Christian Brauner (Amutable) &lt;brauner@kernel.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
BH_Write_EIO is cleared in __bh_submit(), when a buffer that has been
written before is submitted for write again.  That is early: it says the
error is gone at the moment we start trying to fix it, rather than when we
have.

It also loses errors.  A task whose write fails sets the flag and then goes
to look at it; if another task redirties the buffer and resubmits it in
between, the submission clears the flag and the first task sees no error at
all.  Neither of them is doing anything wrong.

Clear it on successful write completion instead, in the end io handlers -
the same three the rest of this series has been converting, plus gfs2's,
which already marked errors this way.  Then the flag means what it says:
the last write of this buffer that finished, failed.  A resubmission no
longer hides an error that has not been fixed yet, and one that has been
fixed clears the flag when the data reaches the disk.

__bh_submit() keeps setting BH_Req, which is what the rest of the tree
reads it for.

Suggested-by: Jan Kara &lt;jack@suse.cz&gt;
Acked-by: Weidong Zhu &lt;weizhu@fiu.edu&gt;
Signed-off-by: Chao Shi &lt;coshi036@gmail.com&gt;
Link: https://patch.msgid.link/1c976fd191aa6e99dbe65d6a1ec63f8706cc0dfa.1785951556.git.coshi036@gmail.com
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Signed-off-by: Christian Brauner (Amutable) &lt;brauner@kernel.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>jbd2: check for a fast commit write error with buffer_write_io_error()</title>
<updated>2026-09-10T07:27:26+00:00</updated>
<author>
<name>Chao Shi</name>
<email>coshi036@gmail.com</email>
</author>
<published>2026-08-06T16:58:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=8ed37e18b915a36bf382873833656c181d1fb942'/>
<id>8ed37e18b915a36bf382873833656c181d1fb942</id>
<content type='text'>
jbd2_fc_wait_bufs() decides whether ext4's fast commit blocks reached the
disk by looking at BH_Uptodate once the write has completed.  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 rewrite or re-read it.  Test BH_Write_EIO instead.

Nothing is needed on the producer side.  These buffers used to be
submitted by ext4_fc_submit_bh() with a private completion handler that
cleared BH_Uptodate, but commit 7f0485dd3017 ("ext4: remove
ext4_end_buffer_io_sync()") dropped it in favour of bh_end_write(), which
already reports a failed write with mark_buffer_write_io_error().  The
wait in jbd2 is the only half left to convert.

A stale flag from an earlier write cannot fool the new test.
jbd2_fc_get_buf() looks the buffer up with __getblk() at a fixed block on
the journal device, so the same buffer comes back commit after commit,
but __bh_submit() clears BH_Write_EIO when it resubmits a buffer for
writing.  The flag jbd2_fc_wait_bufs() sees always belongs to the write
it just waited for.

No behaviour change today - bh_end_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.

Acked-by: Weidong Zhu &lt;weizhu@fiu.edu&gt;
Signed-off-by: Chao Shi &lt;coshi036@gmail.com&gt;
Link: https://patch.msgid.link/970d8b9603d4620ab73038f49bc36831e37e00a0.1785951556.git.coshi036@gmail.com
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Signed-off-by: Christian Brauner (Amutable) &lt;brauner@kernel.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
jbd2_fc_wait_bufs() decides whether ext4's fast commit blocks reached the
disk by looking at BH_Uptodate once the write has completed.  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 rewrite or re-read it.  Test BH_Write_EIO instead.

Nothing is needed on the producer side.  These buffers used to be
submitted by ext4_fc_submit_bh() with a private completion handler that
cleared BH_Uptodate, but commit 7f0485dd3017 ("ext4: remove
ext4_end_buffer_io_sync()") dropped it in favour of bh_end_write(), which
already reports a failed write with mark_buffer_write_io_error().  The
wait in jbd2 is the only half left to convert.

A stale flag from an earlier write cannot fool the new test.
jbd2_fc_get_buf() looks the buffer up with __getblk() at a fixed block on
the journal device, so the same buffer comes back commit after commit,
but __bh_submit() clears BH_Write_EIO when it resubmits a buffer for
writing.  The flag jbd2_fc_wait_bufs() sees always belongs to the write
it just waited for.

No behaviour change today - bh_end_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.

Acked-by: Weidong Zhu &lt;weizhu@fiu.edu&gt;
Signed-off-by: Chao Shi &lt;coshi036@gmail.com&gt;
Link: https://patch.msgid.link/970d8b9603d4620ab73038f49bc36831e37e00a0.1785951556.git.coshi036@gmail.com
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Signed-off-by: Christian Brauner (Amutable) &lt;brauner@kernel.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>jbd2: say what jbd2_freeze_jh_data()'s assertion is actually checking</title>
<updated>2026-09-10T07:27:26+00:00</updated>
<author>
<name>Chao Shi</name>
<email>coshi036@gmail.com</email>
</author>
<published>2026-08-06T16:58:41+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=b1c88ae0b554322fa29b4b490ce0b09c2c84ec52'/>
<id>b1c88ae0b554322fa29b4b490ce0b09c2c84ec52</id>
<content type='text'>
The assertion that the buffer about to be copied out is up to date is
correct and stays, but its message - "Possible IO failure" - describes what
a buffer that is not up to date used to mean rather than what is being
checked.

Once this series stops clearing BH_Uptodate on write error, that reading is
wrong twice over.  A failed write no longer makes a buffer not up to date,
and a buffer that does carry BH_Write_EIO is fine here: it still holds
valid data and the journal will write it again.  What the assertion is
really guarding is that there is something valid to copy at all.

Say that instead.

Suggested-by: Jan Kara &lt;jack@suse.cz&gt;
Acked-by: Weidong Zhu &lt;weizhu@fiu.edu&gt;
Signed-off-by: Chao Shi &lt;coshi036@gmail.com&gt;
Link: https://patch.msgid.link/713ffb9c0cdfe55499b3cdd2c06a59a2c152c46c.1785951556.git.coshi036@gmail.com
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Signed-off-by: Christian Brauner (Amutable) &lt;brauner@kernel.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The assertion that the buffer about to be copied out is up to date is
correct and stays, but its message - "Possible IO failure" - describes what
a buffer that is not up to date used to mean rather than what is being
checked.

Once this series stops clearing BH_Uptodate on write error, that reading is
wrong twice over.  A failed write no longer makes a buffer not up to date,
and a buffer that does carry BH_Write_EIO is fine here: it still holds
valid data and the journal will write it again.  What the assertion is
really guarding is that there is something valid to copy at all.

Say that instead.

Suggested-by: Jan Kara &lt;jack@suse.cz&gt;
Acked-by: Weidong Zhu &lt;weizhu@fiu.edu&gt;
Signed-off-by: Chao Shi &lt;coshi036@gmail.com&gt;
Link: https://patch.msgid.link/713ffb9c0cdfe55499b3cdd2c06a59a2c152c46c.1785951556.git.coshi036@gmail.com
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Signed-off-by: Christian Brauner (Amutable) &lt;brauner@kernel.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>jbd2: report journal write errors with BH_Write_EIO</title>
<updated>2026-09-10T07:27:26+00:00</updated>
<author>
<name>Chao Shi</name>
<email>coshi036@gmail.com</email>
</author>
<published>2026-08-06T16:58:40+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=a05d5c40af1bbf32a3fe78a1e25defcf0503f7bf'/>
<id>a05d5c40af1bbf32a3fe78a1e25defcf0503f7bf</id>
<content type='text'>
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 handler stops touching BH_Uptodate in either direction.  Setting it on
success was never needed: every caller marks the buffer up to date before
submitting the write, because a buffer with no valid data is not something
you can write out.  The local flag is renamed to match what it now means.

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.

Acked-by: Weidong Zhu &lt;weizhu@fiu.edu&gt;
Signed-off-by: Chao Shi &lt;coshi036@gmail.com&gt;
Link: https://patch.msgid.link/c700983eea955429d927791fe5fb9ffe6cf11056.1785951556.git.coshi036@gmail.com
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Signed-off-by: Christian Brauner (Amutable) &lt;brauner@kernel.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 handler stops touching BH_Uptodate in either direction.  Setting it on
success was never needed: every caller marks the buffer up to date before
submitting the write, because a buffer with no valid data is not something
you can write out.  The local flag is renamed to match what it now means.

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.

Acked-by: Weidong Zhu &lt;weizhu@fiu.edu&gt;
Signed-off-by: Chao Shi &lt;coshi036@gmail.com&gt;
Link: https://patch.msgid.link/c700983eea955429d927791fe5fb9ffe6cf11056.1785951556.git.coshi036@gmail.com
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Signed-off-by: Christian Brauner (Amutable) &lt;brauner@kernel.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>jbd2: point the shadow buffer at the frozen data directly</title>
<updated>2026-09-10T07:27:23+00:00</updated>
<author>
<name>Chao Shi</name>
<email>coshi036@gmail.com</email>
</author>
<published>2026-08-06T16:58:26+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=3c9ab45852f6368a3c9d5c18451de7d1f893cc74'/>
<id>3c9ab45852f6368a3c9d5c18451de7d1f893cc74</id>
<content type='text'>
When a metadata buffer has to be copied out before it can be journalled,
jbd2_journal_write_metadata_buffer() writes jh-&gt;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 -&gt;mapping, so a shadow buffer looks like it belongs to an
address_space when it does not.  buffer_set_crypto_ctx() already has to
work around 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, which it already is out of alloc_buffer_head(), and set b_data.  The
previous patch taught fs/buffer.c to submit such a buffer.  folio_set_bh()
is now needed on only one path - the one that journals the page cache copy
directly - so it moves there, and new_folio, new_offset and the flag that
used to pick between them all go away.

The two commit-path checksum helpers reach the shadow buffer's contents
through a new kmap_local_bh()/kunmap_local_bh() pair, which handle a buffer
with or without a folio.  Memory outside the page cache is always mapped,
so for those there is nothing to map or unmap.  Mapping it anyway would be
worse than pointless: with CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP,
kmap_local_page() hands back a one page mapping even for such memory, which
is not enough for a buffer bigger than a page.

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) &lt;willy@infradead.org&gt;
Acked-by: Weidong Zhu &lt;weizhu@fiu.edu&gt;
Signed-off-by: Chao Shi &lt;coshi036@gmail.com&gt;
Link: https://patch.msgid.link/6140cd23beb88e99f40eaeff4044a16213f6caab.1785951556.git.coshi036@gmail.com
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Signed-off-by: Christian Brauner (Amutable) &lt;brauner@kernel.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When a metadata buffer has to be copied out before it can be journalled,
jbd2_journal_write_metadata_buffer() writes jh-&gt;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 -&gt;mapping, so a shadow buffer looks like it belongs to an
address_space when it does not.  buffer_set_crypto_ctx() already has to
work around 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, which it already is out of alloc_buffer_head(), and set b_data.  The
previous patch taught fs/buffer.c to submit such a buffer.  folio_set_bh()
is now needed on only one path - the one that journals the page cache copy
directly - so it moves there, and new_folio, new_offset and the flag that
used to pick between them all go away.

The two commit-path checksum helpers reach the shadow buffer's contents
through a new kmap_local_bh()/kunmap_local_bh() pair, which handle a buffer
with or without a folio.  Memory outside the page cache is always mapped,
so for those there is nothing to map or unmap.  Mapping it anyway would be
worse than pointless: with CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP,
kmap_local_page() hands back a one page mapping even for such memory, which
is not enough for a buffer bigger than a page.

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) &lt;willy@infradead.org&gt;
Acked-by: Weidong Zhu &lt;weizhu@fiu.edu&gt;
Signed-off-by: Chao Shi &lt;coshi036@gmail.com&gt;
Link: https://patch.msgid.link/6140cd23beb88e99f40eaeff4044a16213f6caab.1785951556.git.coshi036@gmail.com
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Signed-off-by: Christian Brauner (Amutable) &lt;brauner@kernel.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>ext4: enable scoped NOFS when starting a handle in nojournal mode</title>
<updated>2026-07-23T03:47:06+00:00</updated>
<author>
<name>Theodore Ts'o</name>
<email>tytso@mit.edu</email>
</author>
<published>2026-07-16T14:10:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=61e2a90a910cb9ed27ca647895f073af0b640351'/>
<id>61e2a90a910cb9ed27ca647895f073af0b640351</id>
<content type='text'>
The jbd2 layer enables NOFS mode using memalloc_nofs_{save,restore}()
while a handle is active.  We need to do the same in nojournal mode so
that it is safe to remove GFP_NOFS flags while a jbd2 handle is
active.

This will require that we actually allocate a real handle, but with an
h_invalid flag set, so there is a place to put the saved memalloc
context.

Signed-off-by: Theodore Ts'o &lt;tytso@mit.edu&gt;
Reviewed-by: Andreas Dilger &lt;adilger@dilger.ca&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The jbd2 layer enables NOFS mode using memalloc_nofs_{save,restore}()
while a handle is active.  We need to do the same in nojournal mode so
that it is safe to remove GFP_NOFS flags while a jbd2 handle is
active.

This will require that we actually allocate a real handle, but with an
h_invalid flag set, so there is a place to put the saved memalloc
context.

Signed-off-by: Theodore Ts'o &lt;tytso@mit.edu&gt;
Reviewed-by: Andreas Dilger &lt;adilger@dilger.ca&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>jbd2: bound shrinker scans by examined checkpoint buffers</title>
<updated>2026-07-22T16:36:24+00:00</updated>
<author>
<name>Max Kellermann</name>
<email>max.kellermann@ionos.com</email>
</author>
<published>2026-07-13T10:22:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=15cb16496446b94e67f7abcb049b8e2c75cd3d02'/>
<id>15cb16496446b94e67f7abcb049b8e2c75cd3d02</id>
<content type='text'>
The jbd2 shrinker currently accounts only checkpoint buffers that it
successfully releases against nr_to_scan.  Busy buffers therefore do not
consume the scan budget.

If a checkpoint transaction contains mostly busy buffers, the shrinker
can scan its entire checkpoint list while holding journal-&gt;j_list_lock.
Large checkpoint lists can result in excessive lock hold times and leave
other CPUs spinning on j_list_lock, causing soft lockups or RCU stalls.

Pass nr_to_scan into journal_shrink_one_cp_list() and decrement it for
every buffer examined, including busy buffers.  Pass NULL from checkpoint
cleanup paths so their existing full-list behavior is preserved.

This restores the scan-budget semantics that existed before
journal_shrink_one_cp_list() was changed to always scan a complete
checkpoint list.

Fixes: b98dba273a0e ("jbd2: remove journal_clean_one_cp_list()")
Cc: stable@vger.kernel.org
Signed-off-by: Max Kellermann &lt;max.kellermann@ionos.com&gt;
Reviewed-by: Zhang Yi &lt;yi.zhang@huawei.com&gt;
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Link: https://patch.msgid.link/20260713102229.1598812-3-max.kellermann@ionos.com
Signed-off-by: Theodore Ts'o &lt;tytso@mit.edu&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The jbd2 shrinker currently accounts only checkpoint buffers that it
successfully releases against nr_to_scan.  Busy buffers therefore do not
consume the scan budget.

If a checkpoint transaction contains mostly busy buffers, the shrinker
can scan its entire checkpoint list while holding journal-&gt;j_list_lock.
Large checkpoint lists can result in excessive lock hold times and leave
other CPUs spinning on j_list_lock, causing soft lockups or RCU stalls.

Pass nr_to_scan into journal_shrink_one_cp_list() and decrement it for
every buffer examined, including busy buffers.  Pass NULL from checkpoint
cleanup paths so their existing full-list behavior is preserved.

This restores the scan-budget semantics that existed before
journal_shrink_one_cp_list() was changed to always scan a complete
checkpoint list.

Fixes: b98dba273a0e ("jbd2: remove journal_clean_one_cp_list()")
Cc: stable@vger.kernel.org
Signed-off-by: Max Kellermann &lt;max.kellermann@ionos.com&gt;
Reviewed-by: Zhang Yi &lt;yi.zhang@huawei.com&gt;
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Link: https://patch.msgid.link/20260713102229.1598812-3-max.kellermann@ionos.com
Signed-off-by: Theodore Ts'o &lt;tytso@mit.edu&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>jbd2: check need_resched() when skipping busy checkpoint buffers</title>
<updated>2026-07-22T16:36:24+00:00</updated>
<author>
<name>Max Kellermann</name>
<email>max.kellermann@ionos.com</email>
</author>
<published>2026-07-13T10:22:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=f213e12ff5c9590b1034ae8da0e6d09665c772d0'/>
<id>f213e12ff5c9590b1034ae8da0e6d09665c772d0</id>
<content type='text'>
journal_shrink_one_cp_list() skips busy checkpoint buffers when called
with JBD2_SHRINK_BUSY_SKIP.  The continue statement on this path also
skips the need_resched() check at the end of the loop body.

Consequently, when a checkpoint list contains mostly busy buffers, the
shrinker can walk the entire list while holding journal-&gt;j_list_lock,
even when a reschedule has been requested.  Large checkpoint lists under
memory pressure can therefore cause long lock hold times and leave other
CPUs spinning on j_list_lock, resulting in soft lockups or RCU stalls.

Route the busy-buffer path through the need_resched() check so that the
shrinker can release j_list_lock and reschedule promptly, restoring
parity with the clean-buffer path, which already checks need_resched().
This does not change which checkpoint buffers are eligible for removal.

Fixes: b98dba273a0e ("jbd2: remove journal_clean_one_cp_list()")
Cc: stable@vger.kernel.org
Signed-off-by: Max Kellermann &lt;max.kellermann@ionos.com&gt;
Reviewed-by: Zhang Yi &lt;yi.zhang@huawei.com&gt;
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Link: https://patch.msgid.link/20260713102229.1598812-2-max.kellermann@ionos.com
Signed-off-by: Theodore Ts'o &lt;tytso@mit.edu&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
journal_shrink_one_cp_list() skips busy checkpoint buffers when called
with JBD2_SHRINK_BUSY_SKIP.  The continue statement on this path also
skips the need_resched() check at the end of the loop body.

Consequently, when a checkpoint list contains mostly busy buffers, the
shrinker can walk the entire list while holding journal-&gt;j_list_lock,
even when a reschedule has been requested.  Large checkpoint lists under
memory pressure can therefore cause long lock hold times and leave other
CPUs spinning on j_list_lock, resulting in soft lockups or RCU stalls.

Route the busy-buffer path through the need_resched() check so that the
shrinker can release j_list_lock and reschedule promptly, restoring
parity with the clean-buffer path, which already checks need_resched().
This does not change which checkpoint buffers are eligible for removal.

Fixes: b98dba273a0e ("jbd2: remove journal_clean_one_cp_list()")
Cc: stable@vger.kernel.org
Signed-off-by: Max Kellermann &lt;max.kellermann@ionos.com&gt;
Reviewed-by: Zhang Yi &lt;yi.zhang@huawei.com&gt;
Reviewed-by: Jan Kara &lt;jack@suse.cz&gt;
Link: https://patch.msgid.link/20260713102229.1598812-2-max.kellermann@ionos.com
Signed-off-by: Theodore Ts'o &lt;tytso@mit.edu&gt;
</pre>
</div>
</content>
</entry>
</feed>
