diff mbox series

[v3,10/10] btrfs: move ordered extent cleanup to where they are allocated

Message ID 194696d75e87010d4c2ed7e5b536d7d2cfe59652.1736479224.git.wqu@suse.com (mailing list archive)
State New
Headers show
Series btrfs: error handling fixes | expand

Commit Message

Qu Wenruo Jan. 10, 2025, 3:31 a.m. UTC
The ordered extent cleanup is hard to grasp because it doesn't follow
the common pattern that the cleanup happens where ordered extent get
allocated.

E.g. run_delalloc_nocow() and cow_file_range() allocate one or more
ordered extents, but if any error is hit, the cleanup is done inside
btrfs_run_delalloc_range().

Change the pattern to who-allocates-who-cleanup behavior, and update the
comment of involved functions to make it explicit on the ordered extents
cleanup behavior.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/inode.c | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)
diff mbox series

Patch

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 03d76579878c..d884b0ff0b9b 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1273,10 +1273,10 @@  u64 btrfs_get_extent_allocation_hint(struct btrfs_inode *inode, u64 start,
  * - Else all pages except for @locked_folio are unlocked.
  *
  * When a failure happens in the second or later iteration of the
- * while-loop, the ordered extents created in previous iterations are kept
- * intact. So, the caller must clean them up by calling
- * btrfs_cleanup_ordered_extents(). See btrfs_run_delalloc_range() for
- * example.
+ * while-loop, the ordered extents created in previous iterations will be
+ * cleaned up.
+ * So if cow_file_range() returned error, there will be no ordered extents
+ * created.
  */
 static noinline int cow_file_range(struct btrfs_inode *inode,
 				   struct folio *locked_folio, u64 start,
@@ -1489,9 +1489,7 @@  static noinline int cow_file_range(struct btrfs_inode *inode,
 
 	/*
 	 * For the range (1). We have already instantiated the ordered extents
-	 * for this region. They are cleaned up by
-	 * btrfs_cleanup_ordered_extents() in e.g,
-	 * btrfs_run_delalloc_range().
+	 * for this region, and need to be cleaned up.
 	 * EXTENT_DELALLOC_NEW | EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV
 	 * are also handled by the cleanup function.
 	 *
@@ -1505,6 +1503,8 @@  static noinline int cow_file_range(struct btrfs_inode *inode,
 
 		if (!locked_folio)
 			mapping_set_error(inode->vfs_inode.i_mapping, ret);
+
+		btrfs_cleanup_ordered_extents(inode, orig_start, start - orig_start);
 		extent_clear_unlock_delalloc(inode, orig_start, start - 1,
 					     locked_folio, NULL, clear_bits, page_ops);
 	}
@@ -1981,6 +1981,9 @@  static void cleanup_dirty_folios(struct btrfs_inode *inode,
  *
  * If no cow copies or snapshots exist, we write directly to the existing
  * blocks on disk
+ *
+ * If error is hit, any ordered extent created inside the range will be
+ * properly cleaned up.
  */
 static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
 				       struct folio *locked_folio,
@@ -2250,9 +2253,8 @@  static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
 	 *
 	 *    For range [start, cur_offset) the folios are already unlocked (except
 	 *    @locked_folio), EXTENT_DELALLOC already removed.
-	 *    Only need to clear the dirty flag as they will never be submitted.
-	 *    Ordered extent and extent maps are handled by
-	 *    btrfs_mark_ordered_io_finished() inside run_delalloc_range().
+	 *    Need to finish the ordered extents and their extent maps, then
+	 *    clear the dirty flag as they will never to submitted.
 	 *
 	 * 2) Failed with error from fallback_to_cow()
 	 *    start         cur_offset  cow_end    end
@@ -2265,10 +2267,13 @@  static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
 	 *    Thus we should not call extent_clear_unlock_delalloc() on range
 	 *    [cur_offset, cow_end), as the folios are already unlocked.
 	 *
-	 * So clear the folio dirty flags for [start, cur_offset) first.
+	 * So clear the folio dirty flags for [start, cur_offset) and finish
+	 * the ordered extents.
 	 */
-	if (cur_offset > start)
+	if (cur_offset > start) {
+		btrfs_cleanup_ordered_extents(inode, start, cur_offset - start);
 		cleanup_dirty_folios(inode, locked_folio, start, cur_offset - 1, ret);
+	}
 
 	/*
 	 * If an error happened while a COW region is outstanding, cur_offset
@@ -2333,7 +2338,7 @@  int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct folio *locked_fol
 
 	if (should_nocow(inode, start, end)) {
 		ret = run_delalloc_nocow(inode, locked_folio, start, end);
-		goto out;
+		return ret;
 	}
 
 	if (btrfs_inode_can_compress(inode) &&
@@ -2347,10 +2352,6 @@  int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct folio *locked_fol
 	else
 		ret = cow_file_range(inode, locked_folio, start, end, NULL,
 				     false, false);
-
-out:
-	if (ret < 0)
-		btrfs_cleanup_ordered_extents(inode, start, end - start + 1);
 	return ret;
 }