From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Qu Wenruo <wqu@suse.com>, Filipe Manana <fdmanana@suse.com>,
David Sterba <dsterba@suse.com>, Sasha Levin <sashal@kernel.org>,
clm@fb.com, josef@toxicpanda.com, linux-btrfs@vger.kernel.org
Subject: [PATCH AUTOSEL 6.16] btrfs: clear block dirty if submit_one_sector() failed
Date: Mon, 25 Aug 2025 08:14:53 -0400 [thread overview]
Message-ID: <20250825121505.2983941-4-sashal@kernel.org> (raw)
In-Reply-To: <20250825121505.2983941-1-sashal@kernel.org>
From: Qu Wenruo <wqu@suse.com>
[ Upstream commit 4bcd3061e8154606af7f721cb75ca04ffe191a12 ]
[BUG]
If submit_one_sector() failed, the block will be kept dirty, but with
their corresponding range finished in the ordered extent.
This means if a writeback happens later again, we can hit the following
problems:
- ASSERT(block_start != EXTENT_MAP_HOLE) in submit_one_sector()
If the original extent map is a hole, then we can hit this case, as
the new ordered extent failed, we will drop the new extent map and
re-read one from the disk.
- DEBUG_WARN() in btrfs_writepage_cow_fixup()
This is because we no longer have an ordered extent for those dirty
blocks. The original for them is already finished with error.
[CAUSE]
The function submit_one_sector() is not following the regular error
handling of writeback. The common practice is to clear the folio dirty,
start and finish the writeback for the block.
This is normally done by extent_clear_unlock_delalloc() with
PAGE_START_WRITEBACK | PAGE_END_WRITEBACK flags during
run_delalloc_range().
So if we keep those failed blocks dirty, they will stay in the page
cache and wait for the next writeback.
And since the original ordered extent is already finished and removed,
depending on the original extent map, we either hit the ASSERT() inside
submit_one_sector(), or hit the DEBUG_WARN() in
btrfs_writepage_cow_fixup().
[FIX]
Follow the regular error handling to clear the dirty flag for the block,
start and finish writeback for that block instead.
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
Based on my analysis of the commit and the kernel repository context,
here's my assessment:
**Backport Status: YES**
This commit should be backported to stable kernel trees for the
following reasons:
## Bug Fix Analysis
1. **Critical Bug Being Fixed**: The commit fixes a serious error
handling bug in btrfs writeback that can lead to two different
assertion failures:
- `ASSERT(block_start != EXTENT_MAP_HOLE)` in submit_one_sector()
- `DEBUG_WARN()` in btrfs_writepage_cow_fixup()
2. **Data Integrity Issue**: The bug causes dirty blocks to remain dirty
after a failed submission, but their corresponding ordered extent is
already finished with error. This creates an inconsistent state
where:
- Dirty blocks exist without proper ordered extent tracking
- Subsequent writeback attempts will fail with assertions/warnings
- The filesystem enters an undefined state that could affect data
integrity
3. **Clear Root Cause**: The commit message clearly identifies the
problem - submit_one_sector() was not following standard writeback
error handling practices. The fix aligns the error handling with the
rest of the btrfs writeback code.
## Code Change Analysis
The fix is minimal and contained:
```c
if (IS_ERR(em)) {
+ /*
+ * When submission failed, we should still clear the folio dirty.
+ * Or the folio will be written back again but without any
+ * ordered extent.
+ */
+ btrfs_folio_clear_dirty(fs_info, folio, filepos, sectorsize);
+ btrfs_folio_set_writeback(fs_info, folio, filepos, sectorsize);
+ btrfs_folio_clear_writeback(fs_info, folio, filepos, sectorsize);
return PTR_ERR(em);
}
```
The changes:
- Add proper error handling to clear dirty flag
- Set and clear writeback status to properly finish the failed writeback
- Update comments to clarify the behavior
## Stable Tree Criteria Met
1. **Fixes a real bug**: Yes - prevents assertion failures and potential
filesystem corruption
2. **Small and contained**: Yes - only ~10 lines of actual code change
in one function
3. **No new features**: Correct - purely bug fix
4. **Low regression risk**: The change follows established patterns used
elsewhere in btrfs (extent_clear_unlock_delalloc)
5. **Important enough**: Yes - prevents filesystem errors and potential
data integrity issues
The fix is straightforward, follows existing btrfs patterns, and
addresses a clear bug that could affect users running btrfs filesystems,
especially under I/O error conditions. This makes it an excellent
candidate for stable backporting.
fs/btrfs/extent_io.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 1dc931c4937f..2e127c109e5b 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1483,7 +1483,7 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
/*
* Return 0 if we have submitted or queued the sector for submission.
- * Return <0 for critical errors.
+ * Return <0 for critical errors, and the sector will have its dirty flag cleared.
*
* Caller should make sure filepos < i_size and handle filepos >= i_size case.
*/
@@ -1506,8 +1506,17 @@ static int submit_one_sector(struct btrfs_inode *inode,
ASSERT(filepos < i_size);
em = btrfs_get_extent(inode, NULL, filepos, sectorsize);
- if (IS_ERR(em))
+ if (IS_ERR(em)) {
+ /*
+ * When submission failed, we should still clear the folio dirty.
+ * Or the folio will be written back again but without any
+ * ordered extent.
+ */
+ btrfs_folio_clear_dirty(fs_info, folio, filepos, sectorsize);
+ btrfs_folio_set_writeback(fs_info, folio, filepos, sectorsize);
+ btrfs_folio_clear_writeback(fs_info, folio, filepos, sectorsize);
return PTR_ERR(em);
+ }
extent_offset = filepos - em->start;
em_end = btrfs_extent_map_end(em);
@@ -1637,8 +1646,8 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode,
* Here we set writeback and clear for the range. If the full folio
* is no longer dirty then we clear the PAGECACHE_TAG_DIRTY tag.
*
- * If we hit any error, the corresponding sector will still be dirty
- * thus no need to clear PAGECACHE_TAG_DIRTY.
+ * If we hit any error, the corresponding sector will have its dirty
+ * flag cleared and writeback finished, thus no need to handle the error case.
*/
if (!submitted_io && !error) {
btrfs_folio_set_writeback(fs_info, folio, start, len);
--
2.50.1
next prev parent reply other threads:[~2025-08-25 12:15 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-25 12:14 [PATCH AUTOSEL 6.16-5.15] fs: writeback: fix use-after-free in __mark_inode_dirty() Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16-6.1] cdc_ncm: Flag Intel OEM version of Fibocom L850-GL as WWAN Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16-6.6] LoongArch: Save LBT before FPU in setup_sigcontext() Sasha Levin
2025-08-25 12:14 ` Sasha Levin [this message]
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16] platform/x86/amd: pmc: Drop SMU F/W match for Cezanne Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16] LoongArch: Add cpuhotplug hooks to fix high cpu usage of vCPU threads Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16-6.12] btrfs: zoned: skip ZONE FINISH of conventional zones Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16-5.10] drm/amd/display: Don't warn when missing DCE encoder caps Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16-6.1] Bluetooth: hci_sync: Avoid adding default advertising on startup Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16-6.6] cpupower: Fix a bug where the -t option of the set subcommand was not working Sasha Levin
2025-08-25 12:15 ` [PATCH AUTOSEL 6.16-6.12] drm/rockchip: vop2: make vp registers nonvolatile Sasha Levin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250825121505.2983941-4-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=clm@fb.com \
--cc=dsterba@suse.com \
--cc=fdmanana@suse.com \
--cc=josef@toxicpanda.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=patches@lists.linux.dev \
--cc=stable@vger.kernel.org \
--cc=wqu@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox