[PATCH 3/5] btrfs: walk waited ordered extents in place

Johannes Thumshirn <[email protected]>
Newsgroups org.kernel.vger.linux-btrfs
Message-ID <[email protected]>
btrfs_wait_ordered_extents() splices root->ordered_extents onto a private
list while it flushes and waits, making the ordered extents temporarily
invisible on the root. Walk the list in place instead, moving each entry to
the tail as it is processed and guarding against re-queueing with the new
BTRFS_ORDERED_FLUSHING flag.

No functional change for current callers; this lets a future lock-free
waiter observe all in-flight ordered extents.

Signed-off-by: Johannes Thumshirn <[email protected]>
---
 fs/btrfs/ordered-data.c | 35 +++++++++++++++++++++--------------
 fs/btrfs/ordered-data.h |  2 ++
 2 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index b32d4eabe0ab..11aa7e8efe04 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -751,6 +751,13 @@ static void btrfs_run_ordered_extent_work(struct btrfs_work *work)
 	complete(&ordered->completion);
 }
 
+static bool ordered_in_range(const struct btrfs_ordered_extent *ordered,
+			     u64 range_start, u64 range_end)
+{
+	return !(range_end <= ordered->disk_bytenr ||
+		 ordered->disk_bytenr + ordered->disk_num_bytes <= range_start);
+}
+
 /*
  * Wait for all the ordered extents in a root. Use @bg as range or do whole
  * range if it's NULL.
@@ -759,13 +766,12 @@ u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr,
 			       const struct btrfs_block_group *bg)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
-	LIST_HEAD(splice);
-	LIST_HEAD(skipped);
 	LIST_HEAD(works);
 	struct btrfs_ordered_extent *ordered, *next;
 	u64 count = 0;
 	u64 range_start, range_len;
 	u64 range_end;
+	u64 remaining;
 
 	if (bg) {
 		range_start = bg->start;
@@ -778,20 +784,22 @@ u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr,
 
 	mutex_lock(&root->ordered_extent_mutex);
 	spin_lock(&root->ordered_extent_lock);
-	list_splice_init(&root->ordered_extents, &splice);
-	while (!list_empty(&splice) && nr) {
-		ordered = list_first_entry(&splice, struct btrfs_ordered_extent,
+	remaining = root->nr_ordered_extents;
+	while (remaining && nr && !list_empty(&root->ordered_extents)) {
+		remaining--;
+		ordered = list_first_entry(&root->ordered_extents,
+					   struct btrfs_ordered_extent,
 					   root_extent_list);
+		list_move_tail(&ordered->root_extent_list,
+			       &root->ordered_extents);
 
-		if (range_end <= ordered->disk_bytenr ||
-		    ordered->disk_bytenr + ordered->disk_num_bytes <= range_start) {
-			list_move_tail(&ordered->root_extent_list, &skipped);
-			cond_resched_lock(&root->ordered_extent_lock);
+		if (!ordered_in_range(ordered, range_start, range_end))
+			continue;
+
+		/* Already queued to 'works' by this call, skip on revisit. */
+		if (test_and_set_bit(BTRFS_ORDERED_FLUSHING, &ordered->flags))
 			continue;
-		}
 
-		list_move_tail(&ordered->root_extent_list,
-			       &root->ordered_extents);
 		refcount_inc(&ordered->refs);
 		spin_unlock(&root->ordered_extent_lock);
 
@@ -806,13 +814,12 @@ u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr,
 		count++;
 		spin_lock(&root->ordered_extent_lock);
 	}
-	list_splice_tail(&skipped, &root->ordered_extents);
-	list_splice_tail(&splice, &root->ordered_extents);
 	spin_unlock(&root->ordered_extent_lock);
 
 	list_for_each_entry_safe(ordered, next, &works, work_list) {
 		list_del_init(&ordered->work_list);
 		wait_for_completion(&ordered->completion);
+		clear_bit(BTRFS_ORDERED_FLUSHING, &ordered->flags);
 		btrfs_put_ordered_extent(ordered);
 		cond_resched();
 	}
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index 8d5d5ba1e02f..f4d0675bb9c3 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -63,6 +63,8 @@ enum {
 	BTRFS_ORDERED_LOGGED_CSUM,
 	/* We wait for this extent to complete in the current transaction. */
 	BTRFS_ORDERED_PENDING,
+	/* Flush work is queued by btrfs_wait_ordered_extents(), avoid requeue. */
+	BTRFS_ORDERED_FLUSHING,
 
 	/*
 	 * Different types for ordered extents, one and only one of these types
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.