]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
maple_tree: Fix mas_prev() and mas_find_rev() state handling
authorLiam R. Howlett <Liam.Howlett@oracle.com>
Fri, 10 Feb 2023 21:42:36 +0000 (16:42 -0500)
committerLiam R. Howlett <Liam.Howlett@oracle.com>
Mon, 13 Feb 2023 13:42:04 +0000 (08:42 -0500)
mas_prev() and mas_find_rev() were not setting the correct maple state
when there was not a previous entry.  Fix this by setting the state to
MAS_NONE.

mas_prev() was not treating the lower limit correctly on initial call.
Fix this by setting the index and last to the min & set the node to
MAS_NONE.

Clean up mas_prev() return on single entry trees of 0 - 0.  There was a
locking error for lockdep.

There was also a potential for returning a NULL on a single entry tree
of 0 - 0 when mas_find_rev() was used.

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

index 65e6b811f17a6a1aa6e6581ab9106ff8e13d1fbb..35c0f07f1e01cf0cee3d48bd4234751fe1c33ee7 100644 (file)
@@ -4853,6 +4853,7 @@ retry:
        mas->offset--;
 not_found:
        mas->index = mas->last = min;
+       mas->node = MAS_NONE;
        return NULL;
 }
 
@@ -5905,15 +5906,11 @@ EXPORT_SYMBOL_GPL(mt_next);
  */
 void *mas_prev(struct ma_state *mas, unsigned long min)
 {
-       if (!mas->index) {
-               /* Nothing comes before 0 */
-               mas->last = 0;
-               mas->node = MAS_NONE;
-               return NULL;
-       }
+       if (mas->index <= min)
+               goto none;
 
        if (unlikely(mas_is_ptr(mas)))
-               return NULL;
+               goto none;
 
        if (mas_is_none(mas) || mas_is_paused(mas))
                mas->node = MAS_START;
@@ -5921,19 +5918,19 @@ void *mas_prev(struct ma_state *mas, unsigned long min)
        if (mas_is_start(mas)) {
                mas_walk(mas);
                if (!mas->index)
-                       return NULL;
+                       goto none;
        }
 
        if (mas_is_ptr(mas)) {
-               if (!mas->index) {
-                       mas->last = 0;
-                       return NULL;
-               }
-
                mas->index = mas->last = 0;
-               return mas_root_locked(mas);
+               return mas_root(mas);
        }
        return mas_prev_entry(mas, min);
+
+none:
+       mas->last = mas->index = min;
+       mas->node = MAS_NONE;
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(mas_prev);
 
@@ -6056,8 +6053,16 @@ EXPORT_SYMBOL_GPL(mas_find);
  */
 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_PAUSE;
+       }
+
        if (unlikely(mas_is_paused(mas))) {
-               if (unlikely(mas->last == ULONG_MAX)) {
+               if (unlikely(mas->index <= min)) {
                        mas->node = MAS_NONE;
                        return NULL;
                }
@@ -6065,6 +6070,9 @@ void *mas_find_rev(struct ma_state *mas, unsigned long min)
                mas->last = --mas->index;
        }
 
+       if (unlikely(mas_is_ptr(mas)))
+               goto none;
+
        if (unlikely(mas_is_start(mas))) {
                /* First run or continue */
                void *entry;
@@ -6077,14 +6085,27 @@ void *mas_find_rev(struct ma_state *mas, unsigned long min)
                        return entry;
        }
 
-       if (unlikely(!mas_searchable(mas)))
-               return NULL;
+       if (unlikely(!mas_searchable(mas))) {
+               if (mas_is_ptr(mas)) {
+                       /*
+                        * Walked to the location, and there was nothing so the
+                        * previous location is 0.
+                        */
+                       mas->last = mas->index = 0;
+                       return mas_root(mas);
+               }
+               goto none;
+       }
 
        if (mas->index < min)
                return NULL;
 
        /* Retries on dead nodes handled by mas_prev_entry */
        return mas_prev_entry(mas, min);
+
+none:
+       mas->node = MAS_NONE;
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(mas_find_rev);