Add a thin lookup which uses minimal state.
Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
void mas_destroy(struct ma_state *mas);
int mas_expected_entries(struct ma_state *mas, unsigned long nr_entries);
+void *ma_peek(struct maple_tree *mt, unsigned long addr);
void *mas_prev(struct ma_state *mas, unsigned long min);
void *mas_prev_range(struct ma_state *mas, unsigned long max);
void *mas_next(struct ma_state *mas, unsigned long max);
return found;
}
+/* ma_peek() - Cheaper version of walking to a specific address with minimal
+ * state.
+ * @mt: The maple tree
+ * @addr: The address
+ *
+ * Note: Only works holding the write lock.
+ */
+void *ma_peek(struct maple_tree *mt, unsigned long addr)
+{
+ struct maple_enode *enode;
+ struct maple_node *node;
+ unsigned long max;
+ unsigned long *pivots;
+ unsigned char offset, end;
+ enum maple_type type;
+ void __rcu **slots;
+
+ enode = rcu_dereference_protected(mt->ma_root, mt_locked(mt));
+
+ if (unlikely(!enode))
+ return NULL;
+
+ if (unlikely(!xa_is_node(enode))) {
+ if (addr == 0)
+ return (void *)enode;
+
+ return NULL;
+ }
+
+ enode = mte_safe_root(enode);
+ max = ULONG_MAX;
+ do {
+ offset = 0;
+ node = mte_to_node(enode);
+ type = mte_node_type(enode);
+ pivots = ma_pivots(node, type);
+
+ if (pivots[0] >= addr)
+ goto descend;
+
+ end = ma_data_end(node, type, pivots, max);
+ do {
+ offset++;
+ } while ((offset < end) && (pivots[offset] < addr));
+
+descend:
+ if (pivots[offset])
+ max = pivots[offset];
+ slots = ma_slots(node, type);
+ enode = mt_slot_locked(mt, slots, offset);
+ } while (!ma_is_leaf(type));
+
+ return (void *) enode;
+}
+EXPORT_SYMBOL_GPL(ma_peek);
+
/**
* mas_walk() - Search for @mas->index in the tree.
* @mas: The maple state.
mt_set_non_kernel(0);
}
+static noinline void __init check_peek(struct maple_tree *mt)
+{
+ MA_STATE(mas, mt, 0, 0);
+ unsigned long i, index = 40;
+ void *tmp;
+
+ mt_set_non_kernel(99999);
+
+ mas_lock(&mas);
+ for (i = 0; i <= index; i++) {
+ unsigned long end = 5;
+ if (i > 18 && i < 35)
+ end = 9;
+ mas_set_range(&mas, i*10, i*10 + end);
+ mas_store_gfp(&mas, xa_mk_value(i), GFP_KERNEL);
+ }
+
+ mas_set_range(&mas, 18*10, 18*10 + 2);
+ mas_store_gfp(&mas, xa_mk_value(18), GFP_KERNEL);
+ mas_set(&mas, 0);
+ mas_for_each(&mas, tmp, ULONG_MAX)
+ MAS_BUG_ON(&mas, tmp != ma_peek(mt, mas.index));
+
+ mas_unlock(&mas);
+ mt_set_non_kernel(0);
+}
+
static DEFINE_MTREE(tree);
static int __init maple_tree_seed(void)
{
check_slot_iterators(&tree);
mtree_destroy(&tree);
+ mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
+ check_peek(&tree);
+ mtree_destroy(&tree);
+
#if defined(BENCH)
skip:
#endif