Commit fff4a58c authored by Liam R. Howlett's avatar Liam R. Howlett Committed by Andrew Morton

maple_tree: introduce mas_next_slot() interface

Sometimes, during a tree walk, the user needs the next slot regardless of
if it is empty or not.  Add an interface to get the next slot.

Since there are no consecutive NULLs allowed in the tree, the mas_next()
function can only advance two slots at most.  So use the new
mas_next_slot() interface to align both implementations.  Use this method
for mas_find() as well.

Link: https://lkml.kernel.org/r/20230518145544.1722059-28-Liam.Howlett@oracle.comSigned-off-by: default avatarLiam R. Howlett <Liam.Howlett@oracle.com>
Cc: David Binderman <dcb314@hotmail.com>
Cc: Peng Zhang <zhangpeng.00@bytedance.com>
Cc: Sergey Senozhatsky <senozhatsky@chromium.org>
Cc: Vernon Yang <vernon2gm@gmail.com>
Cc: Wei Yang <richard.weiyang@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 17e7436b
...@@ -4607,11 +4607,10 @@ static inline int mas_prev_node(struct ma_state *mas, unsigned long min) ...@@ -4607,11 +4607,10 @@ static inline int mas_prev_node(struct ma_state *mas, unsigned long min)
static inline int mas_next_node(struct ma_state *mas, struct maple_node *node, static inline int mas_next_node(struct ma_state *mas, struct maple_node *node,
unsigned long max) unsigned long max)
{ {
unsigned long min, pivot; unsigned long min;
unsigned long *pivots; unsigned long *pivots;
struct maple_enode *enode; struct maple_enode *enode;
int level = 0; int level = 0;
unsigned char offset;
unsigned char node_end; unsigned char node_end;
enum maple_type mt; enum maple_type mt;
void __rcu **slots; void __rcu **slots;
...@@ -4619,19 +4618,16 @@ static inline int mas_next_node(struct ma_state *mas, struct maple_node *node, ...@@ -4619,19 +4618,16 @@ static inline int mas_next_node(struct ma_state *mas, struct maple_node *node,
if (mas->max >= max) if (mas->max >= max)
goto no_entry; goto no_entry;
min = mas->max + 1;
level = 0; level = 0;
do { do {
if (ma_is_root(node)) if (ma_is_root(node))
goto no_entry; goto no_entry;
min = mas->max + 1; /* Walk up. */
if (min > max)
goto no_entry;
if (unlikely(mas_ascend(mas))) if (unlikely(mas_ascend(mas)))
return 1; return 1;
offset = mas->offset;
level++; level++;
node = mas_mn(mas); node = mas_mn(mas);
mt = mte_node_type(mas->node); mt = mte_node_type(mas->node);
...@@ -4640,36 +4636,37 @@ static inline int mas_next_node(struct ma_state *mas, struct maple_node *node, ...@@ -4640,36 +4636,37 @@ static inline int mas_next_node(struct ma_state *mas, struct maple_node *node,
if (unlikely(ma_dead_node(node))) if (unlikely(ma_dead_node(node)))
return 1; return 1;
} while (unlikely(offset == node_end)); } while (unlikely(mas->offset == node_end));
slots = ma_slots(node, mt); slots = ma_slots(node, mt);
pivot = mas_safe_pivot(mas, pivots, ++offset, mt); mas->offset++;
while (unlikely(level > 1)) { enode = mas_slot(mas, slots, mas->offset);
/* Descend, if necessary */
enode = mas_slot(mas, slots, offset);
if (unlikely(ma_dead_node(node))) if (unlikely(ma_dead_node(node)))
return 1; return 1;
mas->node = enode; if (level > 1)
mas->offset = 0;
while (unlikely(level > 1)) {
level--; level--;
mas->node = enode;
node = mas_mn(mas); node = mas_mn(mas);
mt = mte_node_type(mas->node); mt = mte_node_type(mas->node);
slots = ma_slots(node, mt); slots = ma_slots(node, mt);
pivots = ma_pivots(node, mt); enode = mas_slot(mas, slots, 0);
if (unlikely(ma_dead_node(node))) if (unlikely(ma_dead_node(node)))
return 1; return 1;
offset = 0;
pivot = pivots[0];
} }
enode = mas_slot(mas, slots, offset); if (!mas->offset)
pivots = ma_pivots(node, mt);
mas->max = mas_safe_pivot(mas, pivots, mas->offset, mt);
if (unlikely(ma_dead_node(node))) if (unlikely(ma_dead_node(node)))
return 1; return 1;
mas->node = enode; mas->node = enode;
mas->min = min; mas->min = min;
mas->max = pivot;
return 0; return 0;
no_entry: no_entry:
...@@ -4680,83 +4677,106 @@ static inline int mas_next_node(struct ma_state *mas, struct maple_node *node, ...@@ -4680,83 +4677,106 @@ static inline int mas_next_node(struct ma_state *mas, struct maple_node *node,
return 0; return 0;
} }
static inline void mas_rewalk(struct ma_state *mas, unsigned long index)
{
retry:
mas_set(mas, index);
mas_state_walk(mas);
if (mas_is_start(mas))
goto retry;
}
static inline bool mas_rewalk_if_dead(struct ma_state *mas,
struct maple_node *node, const unsigned long index)
{
if (unlikely(ma_dead_node(node))) {
mas_rewalk(mas, index);
return true;
}
return false;
}
/* /*
* mas_next_nentry() - Get the next node entry * mas_next_slot() - Get the entry in the next slot
* @mas: The maple state
* @max: The maximum value to check
* @*range_start: Pointer to store the start of the range.
* *
* Sets @mas->offset to the offset of the next node entry, @mas->last to the * @mas: The maple state
* pivot of the entry. * @max: The maximum starting range
* @empty: Can be empty
* *
* Return: The next entry, %NULL otherwise * Return: The entry in the next slot which is possibly NULL
*/ */
static inline void *mas_next_nentry(struct ma_state *mas, static void *mas_next_slot(struct ma_state *mas, unsigned long max, bool empty)
struct maple_node *node, unsigned long max, enum maple_type type)
{ {
unsigned char count;
unsigned long pivot;
unsigned long *pivots;
void __rcu **slots; void __rcu **slots;
unsigned long *pivots;
unsigned long pivot;
enum maple_type type;
struct maple_node *node;
unsigned char data_end;
unsigned long save_point = mas->last;
void *entry; void *entry;
if (mas->last == mas->max) { retry:
mas->index = mas->max; node = mas_mn(mas);
return NULL; type = mte_node_type(mas->node);
}
slots = ma_slots(node, type);
pivots = ma_pivots(node, type); pivots = ma_pivots(node, type);
count = ma_data_end(node, type, pivots, mas->max); data_end = ma_data_end(node, type, pivots, mas->max);
if (unlikely(ma_dead_node(node))) if (unlikely(mas_rewalk_if_dead(mas, node, save_point)))
return NULL; goto retry;
mas->index = mas_safe_min(mas, pivots, mas->offset);
if (unlikely(ma_dead_node(node)))
return NULL;
if (mas->index > max)
return NULL;
if (mas->offset > count)
return NULL;
while (mas->offset < count) { again:
if (mas->max >= max) {
if (likely(mas->offset < data_end))
pivot = pivots[mas->offset]; pivot = pivots[mas->offset];
entry = mas_slot(mas, slots, mas->offset); else
if (ma_dead_node(node)) return NULL; /* must be mas->max */
return NULL;
mas->last = pivot; if (unlikely(mas_rewalk_if_dead(mas, node, save_point)))
if (entry) goto retry;
return entry;
if (pivot >= max) if (pivot >= max)
return NULL; return NULL;
}
if (pivot >= mas->max) if (likely(mas->offset < data_end)) {
return NULL; mas->index = pivots[mas->offset] + 1;
mas->index = pivot + 1;
mas->offset++; mas->offset++;
if (likely(mas->offset < data_end))
mas->last = pivots[mas->offset];
else
mas->last = mas->max;
} else {
if (mas_next_node(mas, node, max)) {
mas_rewalk(mas, save_point);
goto retry;
} }
pivot = mas_logical_pivot(mas, pivots, mas->offset, type); if (mas_is_none(mas))
entry = mas_slot(mas, slots, mas->offset);
if (ma_dead_node(node))
return NULL; return NULL;
mas->last = pivot; mas->offset = 0;
return entry; mas->index = mas->min;
} node = mas_mn(mas);
type = mte_node_type(mas->node);
pivots = ma_pivots(node, type);
mas->last = pivots[0];
}
static inline void mas_rewalk(struct ma_state *mas, unsigned long index) slots = ma_slots(node, type);
{ entry = mt_slot(mas->tree, slots, mas->offset);
retry: if (unlikely(mas_rewalk_if_dead(mas, node, save_point)))
mas_set(mas, index);
mas_state_walk(mas);
if (mas_is_start(mas))
goto retry; goto retry;
if (entry)
return entry;
if (!empty) {
if (!mas->offset)
data_end = 2;
goto again;
}
return entry;
} }
/* /*
...@@ -4774,47 +4794,12 @@ static inline void mas_rewalk(struct ma_state *mas, unsigned long index) ...@@ -4774,47 +4794,12 @@ static inline void mas_rewalk(struct ma_state *mas, unsigned long index)
static inline void *mas_next_entry(struct ma_state *mas, unsigned long limit) static inline void *mas_next_entry(struct ma_state *mas, unsigned long limit)
{ {
void *entry = NULL; void *entry = NULL;
struct maple_node *node;
unsigned long last;
enum maple_type mt;
if (mas->last >= limit) if (mas->last >= limit)
return NULL; return NULL;
last = mas->last; entry = mas_next_slot(mas, limit, false);
retry:
node = mas_mn(mas);
mt = mte_node_type(mas->node);
mas->offset++;
if (unlikely(mas->offset >= mt_slots[mt])) {
mas->offset = mt_slots[mt] - 1;
goto next_node;
}
while (!mas_is_none(mas)) {
entry = mas_next_nentry(mas, node, limit, mt);
if (unlikely(ma_dead_node(node))) {
mas_rewalk(mas, last);
goto retry;
}
if (likely(entry))
return entry; return entry;
if (unlikely((mas->last >= limit)))
return NULL;
next_node:
if (unlikely(mas_next_node(mas, node, limit))) {
mas_rewalk(mas, last);
goto retry;
}
mas->offset = 0;
node = mas_mn(mas);
mt = mte_node_type(mas->node);
}
return NULL;
} }
/* /*
...@@ -4845,10 +4830,8 @@ static inline void *mas_prev_nentry(struct ma_state *mas, unsigned long limit, ...@@ -4845,10 +4830,8 @@ static inline void *mas_prev_nentry(struct ma_state *mas, unsigned long limit,
slots = ma_slots(mn, mt); slots = ma_slots(mn, mt);
pivots = ma_pivots(mn, mt); pivots = ma_pivots(mn, mt);
count = ma_data_end(mn, mt, pivots, mas->max); count = ma_data_end(mn, mt, pivots, mas->max);
if (unlikely(ma_dead_node(mn))) { if (unlikely(mas_rewalk_if_dead(mas, mn, index)))
mas_rewalk(mas, index);
goto retry; goto retry;
}
offset = mas->offset - 1; offset = mas->offset - 1;
if (offset >= mt_slots[mt]) if (offset >= mt_slots[mt])
...@@ -4861,10 +4844,8 @@ static inline void *mas_prev_nentry(struct ma_state *mas, unsigned long limit, ...@@ -4861,10 +4844,8 @@ static inline void *mas_prev_nentry(struct ma_state *mas, unsigned long limit,
pivot = pivots[offset]; pivot = pivots[offset];
} }
if (unlikely(ma_dead_node(mn))) { if (unlikely(mas_rewalk_if_dead(mas, mn, index)))
mas_rewalk(mas, index);
goto retry; goto retry;
}
while (offset && !mas_slot(mas, slots, offset)) { while (offset && !mas_slot(mas, slots, offset)) {
pivot = pivots[--offset]; pivot = pivots[--offset];
...@@ -4881,10 +4862,8 @@ static inline void *mas_prev_nentry(struct ma_state *mas, unsigned long limit, ...@@ -4881,10 +4862,8 @@ static inline void *mas_prev_nentry(struct ma_state *mas, unsigned long limit,
min = mas_safe_min(mas, pivots, offset); min = mas_safe_min(mas, pivots, offset);
entry = mas_slot(mas, slots, offset); entry = mas_slot(mas, slots, offset);
if (unlikely(ma_dead_node(mn))) { if (unlikely(mas_rewalk_if_dead(mas, mn, index)))
mas_rewalk(mas, index);
goto retry; goto retry;
}
mas->offset = offset; mas->offset = offset;
mas->last = pivot; mas->last = pivot;
...@@ -6103,8 +6082,8 @@ void *mas_find(struct ma_state *mas, unsigned long max) ...@@ -6103,8 +6082,8 @@ void *mas_find(struct ma_state *mas, unsigned long max)
if (mas->index == max) if (mas->index == max)
return NULL; return NULL;
/* Retries on dead nodes handled by mas_next_entry */ /* Retries on dead nodes handled by mas_next_slot */
return mas_next_entry(mas, max); return mas_next_slot(mas, max, false);
ptr_out_of_range: ptr_out_of_range:
mas->node = MAS_NONE; mas->node = MAS_NONE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment