lib: do code optimization for radix_tree_lookup() and radix_tree_lookup_slot()
[sfrench/cifs-2.6.git] / lib / radix-tree.c
index 8d3fb0bd128898b09ba6b01f9c0038b72fbc499a..23abbd93cae1fd50b87b2ed5f8ffd95d940230b1 100644 (file)
@@ -351,20 +351,12 @@ int radix_tree_insert(struct radix_tree_root *root,
 }
 EXPORT_SYMBOL(radix_tree_insert);
 
-/**
- *     radix_tree_lookup_slot    -    lookup a slot in a radix tree
- *     @root:          radix tree root
- *     @index:         index key
- *
- *     Returns:  the slot corresponding to the position @index in the
- *     radix tree @root. This is useful for update-if-exists operations.
- *
- *     This function can be called under rcu_read_lock iff the slot is not
- *     modified by radix_tree_replace_slot, otherwise it must be called
- *     exclusive from other writers. Any dereference of the slot must be done
- *     using radix_tree_deref_slot.
+/*
+ * is_slot == 1 : search for the slot.
+ * is_slot == 0 : search for the node.
  */
-void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
+static void *radix_tree_lookup_element(struct radix_tree_root *root,
+                               unsigned long index, int is_slot)
 {
        unsigned int height, shift;
        struct radix_tree_node *node, **slot;
@@ -376,7 +368,7 @@ void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
        if (!radix_tree_is_indirect_ptr(node)) {
                if (index > 0)
                        return NULL;
-               return (void **)&root->rnode;
+               return is_slot ? (void *)&root->rnode : node;
        }
        node = radix_tree_indirect_to_ptr(node);
 
@@ -397,7 +389,25 @@ void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
                height--;
        } while (height > 0);
 
-       return (void **)slot;
+       return is_slot ? (void *)slot:node;
+}
+
+/**
+ *     radix_tree_lookup_slot    -    lookup a slot in a radix tree
+ *     @root:          radix tree root
+ *     @index:         index key
+ *
+ *     Returns:  the slot corresponding to the position @index in the
+ *     radix tree @root. This is useful for update-if-exists operations.
+ *
+ *     This function can be called under rcu_read_lock iff the slot is not
+ *     modified by radix_tree_replace_slot, otherwise it must be called
+ *     exclusive from other writers. Any dereference of the slot must be done
+ *     using radix_tree_deref_slot.
+ */
+void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
+{
+       return (void **)radix_tree_lookup_element(root, index, 1);
 }
 EXPORT_SYMBOL(radix_tree_lookup_slot);
 
@@ -415,38 +425,7 @@ EXPORT_SYMBOL(radix_tree_lookup_slot);
  */
 void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
 {
-       unsigned int height, shift;
-       struct radix_tree_node *node, **slot;
-
-       node = rcu_dereference(root->rnode);
-       if (node == NULL)
-               return NULL;
-
-       if (!radix_tree_is_indirect_ptr(node)) {
-               if (index > 0)
-                       return NULL;
-               return node;
-       }
-       node = radix_tree_indirect_to_ptr(node);
-
-       height = node->height;
-       if (index > radix_tree_maxindex(height))
-               return NULL;
-
-       shift = (height-1) * RADIX_TREE_MAP_SHIFT;
-
-       do {
-               slot = (struct radix_tree_node **)
-                       (node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK));
-               node = rcu_dereference(*slot);
-               if (node == NULL)
-                       return NULL;
-
-               shift -= RADIX_TREE_MAP_SHIFT;
-               height--;
-       } while (height > 0);
-
-       return node;
+       return radix_tree_lookup_element(root, index, 0);
 }
 EXPORT_SYMBOL(radix_tree_lookup);
 
@@ -640,13 +619,14 @@ EXPORT_SYMBOL(radix_tree_tag_get);
  *
  *     Returns: the index of the hole if found, otherwise returns an index
  *     outside of the set specified (in which case 'return - index >= max_scan'
- *     will be true).
+ *     will be true). In rare cases of index wrap-around, 0 will be returned.
  *
  *     radix_tree_next_hole may be called under rcu_read_lock. However, like
- *     radix_tree_gang_lookup, this will not atomically search a snapshot of the
- *     tree at a single point in time. For example, if a hole is created at index
- *     5, then subsequently a hole is created at index 10, radix_tree_next_hole
- *     covering both indexes may return 10 if called under rcu_read_lock.
+ *     radix_tree_gang_lookup, this will not atomically search a snapshot of
+ *     the tree at a single point in time. For example, if a hole is created
+ *     at index 5, then subsequently a hole is created at index 10,
+ *     radix_tree_next_hole covering both indexes may return 10 if called
+ *     under rcu_read_lock.
  */
 unsigned long radix_tree_next_hole(struct radix_tree_root *root,
                                unsigned long index, unsigned long max_scan)
@@ -665,6 +645,43 @@ unsigned long radix_tree_next_hole(struct radix_tree_root *root,
 }
 EXPORT_SYMBOL(radix_tree_next_hole);
 
+/**
+ *     radix_tree_prev_hole    -    find the prev hole (not-present entry)
+ *     @root:          tree root
+ *     @index:         index key
+ *     @max_scan:      maximum range to search
+ *
+ *     Search backwards in the range [max(index-max_scan+1, 0), index]
+ *     for the first hole.
+ *
+ *     Returns: the index of the hole if found, otherwise returns an index
+ *     outside of the set specified (in which case 'index - return >= max_scan'
+ *     will be true). In rare cases of wrap-around, LONG_MAX will be returned.
+ *
+ *     radix_tree_next_hole may be called under rcu_read_lock. However, like
+ *     radix_tree_gang_lookup, this will not atomically search a snapshot of
+ *     the tree at a single point in time. For example, if a hole is created
+ *     at index 10, then subsequently a hole is created at index 5,
+ *     radix_tree_prev_hole covering both indexes may return 5 if called under
+ *     rcu_read_lock.
+ */
+unsigned long radix_tree_prev_hole(struct radix_tree_root *root,
+                                  unsigned long index, unsigned long max_scan)
+{
+       unsigned long i;
+
+       for (i = 0; i < max_scan; i++) {
+               if (!radix_tree_lookup(root, index))
+                       break;
+               index--;
+               if (index == LONG_MAX)
+                       break;
+       }
+
+       return index;
+}
+EXPORT_SYMBOL(radix_tree_prev_hole);
+
 static unsigned int
 __lookup(struct radix_tree_node *slot, void ***results, unsigned long index,
        unsigned int max_items, unsigned long *next_index)