From: Liam R. Howlett Date: Fri, 10 Feb 2023 21:42:36 +0000 (-0500) Subject: maple_tree: Fix mas_prev() and mas_find_rev() state handling X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=bcc91be5fc177962b994127e53bcdc0c0da99765;p=users%2Fjedix%2Flinux-maple.git maple_tree: Fix mas_prev() and mas_find_rev() state handling 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 --- diff --git a/lib/maple_tree.c b/lib/maple_tree.c index 65e6b811f17a..35c0f07f1e01 100644 --- a/lib/maple_tree.c +++ b/lib/maple_tree.c @@ -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);