]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
maple_tree: Fix mas_prev() from skipping entries.
authorLiam R. Howlett <Liam.Howlett@Oracle.com>
Mon, 30 Nov 2020 20:27:00 +0000 (15:27 -0500)
committerLiam R. Howlett <Liam.Howlett@Oracle.com>
Tue, 5 Jan 2021 17:33:29 +0000 (12:33 -0500)
When searching backwards, if the node wasn't fully full then the pivot could
be zero and thus return there was no previous entry in the node.  Also set
mas.last/mas.index to ensure correct prev/next functions

Signed-off-by: Liam R. Howlett <Liam.Howlett@Oracle.com>
lib/maple_tree.c

index 904fc63be1197dfce55d653873f6d131e2e9233a..65341848f944be8b91167c5aa459328ab090ccac 100644 (file)
@@ -3467,6 +3467,9 @@ restart_prev_node:
        mt = mte_node_type(mas->node);
        slots = ma_slots(mas_mn(mas), mt);
        mas->max = mas_safe_pivot(mas, offset);
+       if (mas->max < limit)
+               goto no_entry;
+
        while (level > 1) {
                level--;
                mas->node = mas_slot(mas, slots, offset);
@@ -3474,9 +3477,10 @@ restart_prev_node:
                        goto restart_prev_node;
                mt = mte_node_type(mas->node);
                slots = ma_slots(mas_mn(mas), mt);
-               offset = mt_slots[mt];
-               do {} while (!mas_get_slot(mas, --offset));
+               offset = mas_data_end(mas);
                mas->max = mas_safe_pivot(mas, offset);
+               if (mas->max < limit)
+                       goto no_entry;
        }
 
        mas->offset = offset;
@@ -3573,29 +3577,35 @@ no_entry:
 static inline bool mas_prev_nentry(struct ma_state *mas, unsigned long limit,
                unsigned long *max)
 {
-       unsigned long pivot = mas->max;
-       unsigned char slot = mas->offset;
-       void *entry;
+       unsigned long pivot;
+       unsigned char offset;
+       struct maple_node *mn;
+       enum maple_type mt;
+       unsigned long *pivots;
+       void **slots;
 
-       if (!slot)
+       if (!mas->offset)
                return false;
 
-       slot--;
-       do {
-               pivot = mas_safe_pivot(mas, slot);
-               if (pivot < limit)
-                       return false;
+       mn = mas_mn(mas);
+       mt = mte_node_type(mas->node);
+       offset = mas->offset - 1;
+       slots = ma_slots(mn, mt);
+       pivots = ma_pivots(mn, mt);
 
-               entry = mas_get_slot(mas, slot);
-               if (entry)
-                       break;
-       } while (slot--);
+       if (offset == mt_pivots[mt])
+               pivot = mas->max;
+       else
+               pivot = pivots[offset];
 
-       if (!entry)
+       while ((offset && !slots[offset] && pivot >= limit) || !pivot)
+               pivot = pivots[--offset];
+
+       mas->offset = offset;
+       if (!slots[offset])
                return false;
 
        *max = pivot;
-       mas->offset = slot;
        return true;
 }
 
@@ -3772,7 +3782,7 @@ static inline void *_mas_prev(struct ma_state *mas, unsigned long limit)
        }
 
        if (mas_is_none(mas)) {
-               mas->index = 0;
+               mas->index = mas->last = limit;
                return NULL;
        }
 
@@ -3791,8 +3801,10 @@ void *mas_prev(struct ma_state *mas, unsigned long min)
 {
        void *entry;
 
-       if (!mas->index) // Nothing comes before 0.
+       if (!mas->index) {// Nothing comes before 0.
+               mas->last = 0;
                return NULL;
+       }
 
        if (mas_is_none(mas))
                mas->node = MAS_START;
@@ -3808,9 +3820,7 @@ void *mas_prev(struct ma_state *mas, unsigned long min)
 
        do {
                entry = _mas_prev(mas, min);
-               if (!mas_searchable(mas))
-                       break;
-       } while (!entry);
+       } while (mas_searchable(mas) && !entry);
 
        return entry;
 }