aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQu Wenruo <wqu@suse.com>2026-05-07 14:59:19 +0930
committerDavid Sterba <dsterba@suse.com>2026-06-08 15:53:32 +0200
commit7d97bdca4bcb0e36b2d1251bffac3ff4e4e09c8c (patch)
treec3f5ca947295cc40cd7a24cf7027641a515baaeb
parent095be159f3eb4670fab75f795ce9539a381ebd3f (diff)
btrfs: use dirty flag to check if an ordered extent needs to be truncated
Currently there are only two folio ordered flag users: - extent_writepage_io() To ensure the folio range has an ordered extent covering it. This is from the legacy COW fixup mechanism, which is already removed and only a simple check is left. - btrfs_invalidate_folio() This is to avoid race with end_bbio_data_write(), where btrfs_finish_ordered_extent() will be called to handle the OE finishing. But for btrfs_invalidate_folio() we have already waited for the folio writeback to finish, and locked the folio. This means we can use the dirty flag to check if a range is already submitted or not. If the OE range is not dirty, it means the range has been submitted and its dirty flag was cleared. And since we have already waited for writeback, the endio function will handle the OE finishing. Thus if the range is not dirty, we must skip the range. If the OE range is dirty, it means we have allocated an ordered extent but have not yet submitted the range. And that's exactly the case where we need to truncate the ordered extent. Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/inode.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index c70e541d5d9a..76923c28a243 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -7593,15 +7593,20 @@ static void btrfs_invalidate_folio(struct folio *folio, size_t offset,
page_end);
ASSERT(range_end + 1 - cur < U32_MAX);
range_len = range_end + 1 - cur;
- if (!btrfs_folio_test_ordered(fs_info, folio, cur, range_len)) {
- /*
- * If Ordered is cleared, it means endio has
- * already been executed for the range.
- * We can't delete the extent states as
- * btrfs_finish_ordered_io() may still use some of them.
- */
+ /*
+ * If the range is not dirty, the range has been submitted and
+ * since we have waited for the writeback, endio has been
+ * executed, thus we must skip the range to avoid double
+ * accounting for the ordered extent.
+ */
+ if (!btrfs_folio_test_dirty(fs_info, folio, cur, range_len))
goto next;
- }
+
+ /*
+ * The range is dirty meaning it has not been submitted.
+ * Here we need to truncate the OE range as the range will never
+ * be submitted.
+ */
btrfs_folio_clear_ordered(fs_info, folio, cur, range_len);
/*