mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 6.6.y] btrfs: fix unfinished ordered extent when cow_file_range() fails
@ 2026-11-09 12:47 Joseph Qi
  0 siblings, 0 replies; only message in thread
From: Joseph Qi @ 2026-11-09 12:47 UTC (permalink / raw)
  To: Sasha Levin, David Sterba
  Cc: Chris Mason, stable, linux-btrfs, linux-kernel, Joseph Qi

Commit 4ace6fb49c8b ("btrfs: do proper folio cleanup when cow_file_range()
failed") moved the extent and folio unlock out of the allocation loop.
The per-iteration PAGE_SET_ORDERED went with it, and the replacement
after the loop only runs on success, so the range that already has
ordered extents is now cleaned up with PAGE_UNLOCK, PAGE_START_WRITEBACK
and PAGE_END_WRITEBACK only.

Upstream can do that because btrfs_run_delalloc_range() passes NULL to
btrfs_cleanup_ordered_extents(), which then accounts the whole range
without consulting any page bit.  Where that function still takes
@locked_page it skips it instead, leaving its share of the ordered
extent to the caller, which finishes it through
btrfs_mark_ordered_io_finished() with the page argument.
can_finish_ordered_extent() returns early when the Ordered bit is not
set, so that share is never accounted and bytes_left never reaches zero.
btrfs_wait_ordered_range() then waits forever, and a later write to the
same offset can reach the -EEXIST btrfs_panic() in
insert_ordered_extent().

Both callers that rely on this are affected: __extent_writepage(), and
submit_uncompressed_range(), the compression fallback, which reaches
cow_file_range() through run_delalloc_cow().

Set PAGE_SET_ORDERED again for that range.  The cleanup still skips
@locked_page and accounts the rest with a NULL page, so the two ranges
do not overlap and nothing is accounted twice.

Upstream fixed this differently, in "btrfs: fix double accounting race
when btrfs_run_delalloc_range() failed", which is earlier in the same
series.  That commit depends on the writepage_delalloc() rework and the
folio conversion of extent_io.c, so restore the flag here instead.

Fixes: 4ace6fb49c8b ("btrfs: do proper folio cleanup when cow_file_range() failed")
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
---
 fs/btrfs/inode.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index c8034d86f844f..a40201596b80f 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1532,10 +1532,16 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
 	 *
 	 * So here we only clear EXTENT_LOCKED and EXTENT_DELALLOC flag, and
 	 * finish the writeback of the involved folios, which will be never submitted.
+	 *
+	 * PAGE_SET_ORDERED is still needed here:
+	 * btrfs_cleanup_ordered_extents() skips @locked_page and leaves
+	 * its share of the ordered extent to the caller, which can only
+	 * account for it while the Ordered bit is set.
 	 */
 	if (orig_start < start) {
 		clear_bits = EXTENT_LOCKED | EXTENT_DELALLOC;
-		page_ops = PAGE_UNLOCK | PAGE_START_WRITEBACK | PAGE_END_WRITEBACK;
+		page_ops = PAGE_UNLOCK | PAGE_SET_ORDERED |
+			   PAGE_START_WRITEBACK | PAGE_END_WRITEBACK;
 
 		if (!locked_page)
 			mapping_set_error(inode->vfs_inode.i_mapping, ret);
-- 
2.39.3


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-11-09 12:47 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-09 12:47 [PATCH 6.6.y] btrfs: fix unfinished ordered extent when cow_file_range() fails Joseph Qi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®