]> git.baikalelectronics.ru Git - kernel.git/commitdiff
btrfs: introduce btrfs_lookup_first_ordered_range()
authorQu Wenruo <wqu@suse.com>
Tue, 27 Apr 2021 07:03:40 +0000 (15:03 +0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 21 Jun 2021 13:19:08 +0000 (15:19 +0200)
Although we already have btrfs_lookup_first_ordered_extent() and
btrfs_lookup_ordered_extent(), they all have their own limitations:

- btrfs_lookup_ordered_extent() can't do extra range check

  It's only designed to lookup any ordered extent before certain bytenr.

- btrfs_lookup_first_ordered_extent() may not return the first ordered
  extent in the range

  It doesn't ensure the first ordered extent is returned.
  The existing callers are only interested in exhausting all ordered
  extents in a range, the order is not important.

For incoming btrfs_invalidatepage() refactoring, we need a way to
properly iterate all ordered extents in their bytenr order of a range.

So this patch will introduce a new function,
btrfs_lookup_first_ordered_range(), to do ordered extent with bytenr
order awareness and extra range check.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h

index e7ecce2c1bd8e124a99b1fa27e0a558122a77bfb..f3270396e547b122d3193f06b697ecee26e1e6d2 100644 (file)
@@ -930,6 +930,81 @@ out:
        return entry;
 }
 
+/*
+ * Lookup the first ordered extent that overlaps the range
+ * [@file_offset, @file_offset + @len).
+ *
+ * The difference between this and btrfs_lookup_first_ordered_extent() is
+ * that this one won't return any ordered extent that does not overlap the range.
+ * And the difference against btrfs_lookup_ordered_extent() is, this function
+ * ensures the first ordered extent gets returned.
+ */
+struct btrfs_ordered_extent *btrfs_lookup_first_ordered_range(
+                       struct btrfs_inode *inode, u64 file_offset, u64 len)
+{
+       struct btrfs_ordered_inode_tree *tree = &inode->ordered_tree;
+       struct rb_node *node;
+       struct rb_node *cur;
+       struct rb_node *prev;
+       struct rb_node *next;
+       struct btrfs_ordered_extent *entry = NULL;
+
+       spin_lock_irq(&tree->lock);
+       node = tree->tree.rb_node;
+       /*
+        * Here we don't want to use tree_search() which will use tree->last
+        * and screw up the search order.
+        * And __tree_search() can't return the adjacent ordered extents
+        * either, thus here we do our own search.
+        */
+       while (node) {
+               entry = rb_entry(node, struct btrfs_ordered_extent, rb_node);
+
+               if (file_offset < entry->file_offset) {
+                       node = node->rb_left;
+               } else if (file_offset >= entry_end(entry)) {
+                       node = node->rb_right;
+               } else {
+                       /*
+                        * Direct hit, got an ordered extent that starts at
+                        * @file_offset
+                        */
+                       goto out;
+               }
+       }
+       if (!entry) {
+               /* Empty tree */
+               goto out;
+       }
+
+       cur = &entry->rb_node;
+       /* We got an entry around @file_offset, check adjacent entries */
+       if (entry->file_offset < file_offset) {
+               prev = cur;
+               next = rb_next(cur);
+       } else {
+               prev = rb_prev(cur);
+               next = cur;
+       }
+       if (prev) {
+               entry = rb_entry(prev, struct btrfs_ordered_extent, rb_node);
+               if (range_overlaps(entry, file_offset, len))
+                       goto out;
+       }
+       if (next) {
+               entry = rb_entry(next, struct btrfs_ordered_extent, rb_node);
+               if (range_overlaps(entry, file_offset, len))
+                       goto out;
+       }
+       /* No ordered extent in the range */
+       entry = NULL;
+out:
+       if (entry)
+               refcount_inc(&entry->refs);
+       spin_unlock_irq(&tree->lock);
+       return entry;
+}
+
 /*
  * btrfs_flush_ordered_range - Lock the passed range and ensures all pending
  * ordered extents in it are run to completion.
index 72eb4b8cbb88141233e920bccffb0a09e9bf3159..566472004edd33de19dcf1965e3e527e47f4a0ce 100644 (file)
@@ -196,6 +196,8 @@ void btrfs_start_ordered_extent(struct btrfs_ordered_extent *entry, int wait);
 int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
 struct btrfs_ordered_extent *
 btrfs_lookup_first_ordered_extent(struct btrfs_inode *inode, u64 file_offset);
+struct btrfs_ordered_extent *btrfs_lookup_first_ordered_range(
+                       struct btrfs_inode *inode, u64 file_offset, u64 len);
 struct btrfs_ordered_extent *btrfs_lookup_ordered_range(
                struct btrfs_inode *inode,
                u64 file_offset,