mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
maple_tree: try harder to keep active node with mas_prev()
Keep a reference to the node when possible with mas_prev(). This will avoid re-walking the tree. In keeping a reference to the node, keep the last/index accurate to the range being referenced. This means the limit may be within the range, but the range may extend outside of the limit. Also fix the single entry tree to respect the range (of 0), or set the node to MAS_NONE in the case of shifting beyond 0. Link: https://lkml.kernel.org/r/20230518145544.1722059-25-Liam.Howlett@oracle.com Signed-off-by: Liam 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: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
ca80f61004
commit
39193685d5
1 changed files with 87 additions and 46 deletions
127
lib/maple_tree.c
127
lib/maple_tree.c
|
@ -4828,7 +4828,7 @@ static inline void *mas_prev_nentry(struct ma_state *mas, unsigned long limit,
|
||||||
unsigned long index)
|
unsigned long index)
|
||||||
{
|
{
|
||||||
unsigned long pivot, min;
|
unsigned long pivot, min;
|
||||||
unsigned char offset;
|
unsigned char offset, count;
|
||||||
struct maple_node *mn;
|
struct maple_node *mn;
|
||||||
enum maple_type mt;
|
enum maple_type mt;
|
||||||
unsigned long *pivots;
|
unsigned long *pivots;
|
||||||
|
@ -4841,30 +4841,43 @@ retry:
|
||||||
|
|
||||||
mn = mas_mn(mas);
|
mn = mas_mn(mas);
|
||||||
mt = mte_node_type(mas->node);
|
mt = mte_node_type(mas->node);
|
||||||
|
offset = mas->offset - 1;
|
||||||
|
slots = ma_slots(mn, mt);
|
||||||
|
pivots = ma_pivots(mn, mt);
|
||||||
|
count = ma_data_end(mn, mt, pivots, mas->max);
|
||||||
|
if (unlikely(ma_dead_node(mn))) {
|
||||||
|
mas_rewalk(mas, index);
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
offset = mas->offset - 1;
|
offset = mas->offset - 1;
|
||||||
if (offset >= mt_slots[mt])
|
if (offset >= mt_slots[mt])
|
||||||
offset = mt_slots[mt] - 1;
|
offset = mt_slots[mt] - 1;
|
||||||
|
|
||||||
slots = ma_slots(mn, mt);
|
if (offset >= count) {
|
||||||
pivots = ma_pivots(mn, mt);
|
|
||||||
if (unlikely(ma_dead_node(mn))) {
|
|
||||||
mas_rewalk(mas, index);
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset == mt_pivots[mt])
|
|
||||||
pivot = mas->max;
|
pivot = mas->max;
|
||||||
else
|
offset = count;
|
||||||
|
} else {
|
||||||
pivot = pivots[offset];
|
pivot = pivots[offset];
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely(ma_dead_node(mn))) {
|
if (unlikely(ma_dead_node(mn))) {
|
||||||
mas_rewalk(mas, index);
|
mas_rewalk(mas, index);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (offset && ((!mas_slot(mas, slots, offset) && pivot >= limit) ||
|
while (offset && !mas_slot(mas, slots, offset)) {
|
||||||
!pivot))
|
|
||||||
pivot = pivots[--offset];
|
pivot = pivots[--offset];
|
||||||
|
if (pivot >= limit)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the slot was null but we've shifted outside the limits, then set
|
||||||
|
* the range to the last NULL.
|
||||||
|
*/
|
||||||
|
if (unlikely((pivot < limit) && (offset < mas->offset)))
|
||||||
|
pivot = pivots[++offset];
|
||||||
|
|
||||||
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);
|
||||||
|
@ -4873,32 +4886,33 @@ retry:
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(entry)) {
|
|
||||||
mas->offset = offset;
|
mas->offset = offset;
|
||||||
mas->last = pivot;
|
mas->last = pivot;
|
||||||
mas->index = min;
|
mas->index = min;
|
||||||
}
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *mas_prev_entry(struct ma_state *mas, unsigned long min)
|
static inline void *mas_prev_entry(struct ma_state *mas, unsigned long min)
|
||||||
{
|
{
|
||||||
void *entry;
|
void *entry;
|
||||||
|
struct maple_enode *prev_enode;
|
||||||
|
unsigned char prev_offset;
|
||||||
|
|
||||||
if (mas->index < min) {
|
if (mas->index < min)
|
||||||
mas->index = mas->last = min;
|
|
||||||
mas->node = MAS_NONE;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
retry:
|
retry:
|
||||||
|
prev_enode = mas->node;
|
||||||
|
prev_offset = mas->offset;
|
||||||
while (likely(!mas_is_none(mas))) {
|
while (likely(!mas_is_none(mas))) {
|
||||||
entry = mas_prev_nentry(mas, min, mas->index);
|
entry = mas_prev_nentry(mas, min, mas->index);
|
||||||
if (unlikely(mas->last < min))
|
|
||||||
goto not_found;
|
|
||||||
|
|
||||||
if (likely(entry))
|
if (likely(entry))
|
||||||
return entry;
|
return entry;
|
||||||
|
|
||||||
|
if (unlikely(mas->index <= min))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (unlikely(mas_prev_node(mas, min))) {
|
if (unlikely(mas_prev_node(mas, min))) {
|
||||||
mas_rewalk(mas, mas->index);
|
mas_rewalk(mas, mas->index);
|
||||||
goto retry;
|
goto retry;
|
||||||
|
@ -4907,9 +4921,8 @@ retry:
|
||||||
mas->offset++;
|
mas->offset++;
|
||||||
}
|
}
|
||||||
|
|
||||||
mas->offset--;
|
mas->node = prev_enode;
|
||||||
not_found:
|
mas->offset = prev_offset;
|
||||||
mas->index = mas->last = min;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5952,15 +5965,8 @@ EXPORT_SYMBOL_GPL(mt_next);
|
||||||
*/
|
*/
|
||||||
void *mas_prev(struct ma_state *mas, unsigned long min)
|
void *mas_prev(struct ma_state *mas, unsigned long min)
|
||||||
{
|
{
|
||||||
if (!mas->index) {
|
if (mas->index <= min)
|
||||||
/* Nothing comes before 0 */
|
goto none;
|
||||||
mas->last = 0;
|
|
||||||
mas->node = MAS_NONE;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unlikely(mas_is_ptr(mas)))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (mas_is_none(mas) || mas_is_paused(mas))
|
if (mas_is_none(mas) || mas_is_paused(mas))
|
||||||
mas->node = MAS_START;
|
mas->node = MAS_START;
|
||||||
|
@ -5968,19 +5974,30 @@ void *mas_prev(struct ma_state *mas, unsigned long min)
|
||||||
if (mas_is_start(mas)) {
|
if (mas_is_start(mas)) {
|
||||||
mas_walk(mas);
|
mas_walk(mas);
|
||||||
if (!mas->index)
|
if (!mas->index)
|
||||||
return NULL;
|
goto none;
|
||||||
}
|
|
||||||
|
|
||||||
if (mas_is_ptr(mas)) {
|
|
||||||
if (!mas->index) {
|
|
||||||
mas->last = 0;
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unlikely(mas_is_ptr(mas))) {
|
||||||
|
if (!mas->index)
|
||||||
|
goto none;
|
||||||
mas->index = mas->last = 0;
|
mas->index = mas->last = 0;
|
||||||
return mas_root_locked(mas);
|
return mas_root(mas);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mas_is_none(mas)) {
|
||||||
|
if (mas->index) {
|
||||||
|
/* Walked to out-of-range pointer? */
|
||||||
|
mas->index = mas->last = 0;
|
||||||
|
mas->node = MAS_ROOT;
|
||||||
|
return mas_root(mas);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
return mas_prev_entry(mas, min);
|
return mas_prev_entry(mas, min);
|
||||||
|
|
||||||
|
none:
|
||||||
|
mas->node = MAS_NONE;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mas_prev);
|
EXPORT_SYMBOL_GPL(mas_prev);
|
||||||
|
|
||||||
|
@ -6106,8 +6123,16 @@ EXPORT_SYMBOL_GPL(mas_find);
|
||||||
*/
|
*/
|
||||||
void *mas_find_rev(struct ma_state *mas, unsigned long min)
|
void *mas_find_rev(struct ma_state *mas, unsigned long min)
|
||||||
{
|
{
|
||||||
|
if (unlikely(mas_is_none(mas))) {
|
||||||
|
if (mas->index <= min)
|
||||||
|
goto none;
|
||||||
|
|
||||||
|
mas->last = mas->index;
|
||||||
|
mas->node = MAS_START;
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely(mas_is_paused(mas))) {
|
if (unlikely(mas_is_paused(mas))) {
|
||||||
if (unlikely(mas->last == ULONG_MAX)) {
|
if (unlikely(mas->index <= min)) {
|
||||||
mas->node = MAS_NONE;
|
mas->node = MAS_NONE;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -6127,14 +6152,30 @@ void *mas_find_rev(struct ma_state *mas, unsigned long min)
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(!mas_searchable(mas)))
|
if (unlikely(!mas_searchable(mas))) {
|
||||||
return NULL;
|
if (mas_is_ptr(mas))
|
||||||
|
goto none;
|
||||||
|
|
||||||
|
if (mas_is_none(mas)) {
|
||||||
|
/*
|
||||||
|
* Walked to the location, and there was nothing so the
|
||||||
|
* previous location is 0.
|
||||||
|
*/
|
||||||
|
mas->last = mas->index = 0;
|
||||||
|
mas->node = MAS_ROOT;
|
||||||
|
return mas_root(mas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mas->index < min)
|
if (mas->index < min)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Retries on dead nodes handled by mas_prev_entry */
|
/* Retries on dead nodes handled by mas_prev_entry */
|
||||||
return mas_prev_entry(mas, min);
|
return mas_prev_entry(mas, min);
|
||||||
|
|
||||||
|
none:
|
||||||
|
mas->node = MAS_NONE;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mas_find_rev);
|
EXPORT_SYMBOL_GPL(mas_find_rev);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue