Btrfs: add helper for tree enumeration
authorArne Jansen <sensille@gmx.net>
Tue, 13 Sep 2011 09:18:10 +0000 (11:18 +0200)
committerAlexander Block <ablock84@googlemail.com>
Wed, 25 Jul 2012 15:33:18 +0000 (17:33 +0200)
Often no exact match is wanted but just the next lower or
higher item. There's a lot of duplicated code throughout
btrfs to deal with the corner cases. This patch adds a
helper function that can facilitate searching.

Signed-off-by: Arne Jansen <sensille@gmx.net>
fs/btrfs/ctree.c
fs/btrfs/ctree.h

index 8206b39..c82a9e4 100644 (file)
@@ -2722,6 +2722,80 @@ done:
 }
 
 /*
+ * helper to use instead of search slot if no exact match is needed but
+ * instead the next or previous item should be returned.
+ * When find_higher is true, the next higher item is returned, the next lower
+ * otherwise.
+ * When return_any and find_higher are both true, and no higher item is found,
+ * return the next lower instead.
+ * When return_any is true and find_higher is false, and no lower item is found,
+ * return the next higher instead.
+ * It returns 0 if any item is found, 1 if none is found (tree empty), and
+ * < 0 on error
+ */
+int btrfs_search_slot_for_read(struct btrfs_root *root,
+                              struct btrfs_key *key, struct btrfs_path *p,
+                              int find_higher, int return_any)
+{
+       int ret;
+       struct extent_buffer *leaf;
+
+again:
+       ret = btrfs_search_slot(NULL, root, key, p, 0, 0);
+       if (ret <= 0)
+               return ret;
+       /*
+        * a return value of 1 means the path is at the position where the
+        * item should be inserted. Normally this is the next bigger item,
+        * but in case the previous item is the last in a leaf, path points
+        * to the first free slot in the previous leaf, i.e. at an invalid
+        * item.
+        */
+       leaf = p->nodes[0];
+
+       if (find_higher) {
+               if (p->slots[0] >= btrfs_header_nritems(leaf)) {
+                       ret = btrfs_next_leaf(root, p);
+                       if (ret <= 0)
+                               return ret;
+                       if (!return_any)
+                               return 1;
+                       /*
+                        * no higher item found, return the next
+                        * lower instead
+                        */
+                       return_any = 0;
+                       find_higher = 0;
+                       btrfs_release_path(p);
+                       goto again;
+               }
+       } else {
+               if (p->slots[0] == 0) {
+                       ret = btrfs_prev_leaf(root, p);
+                       if (ret < 0)
+                               return ret;
+                       if (!ret) {
+                               p->slots[0] = btrfs_header_nritems(leaf) - 1;
+                               return 0;
+                       }
+                       if (!return_any)
+                               return 1;
+                       /*
+                        * no lower item found, return the next
+                        * higher instead
+                        */
+                       return_any = 0;
+                       find_higher = 1;
+                       btrfs_release_path(p);
+                       goto again;
+               } else {
+                       --p->slots[0];
+               }
+       }
+       return 0;
+}
+
+/*
  * adjust the pointers going up the tree, starting at level
  * making sure the right key of each node is points to 'key'.
  * This is used after shifting pointers to the left, so it stops
index fa5c45b..8cfde93 100644 (file)
@@ -2711,6 +2711,9 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
                      ins_len, int cow);
 int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
                          struct btrfs_path *p, u64 time_seq);
+int btrfs_search_slot_for_read(struct btrfs_root *root,
+                              struct btrfs_key *key, struct btrfs_path *p,
+                              int find_higher, int return_any);
 int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                       struct btrfs_root *root, struct extent_buffer *parent,
                       int start_slot, int cache_only, u64 *last_ret,