From: Liam R. Howlett Date: Fri, 6 Nov 2020 21:52:59 +0000 (-0500) Subject: maple_tree: Add mas_store_gfp() and fix mas_prev() and mas_store() X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=5112428a959bfdba6205f8182e42c059430469b0;p=users%2Fjedix%2Flinux-maple.git maple_tree: Add mas_store_gfp() and fix mas_prev() and mas_store() When searching for the previous value, walk the node first. Don't just assume we are looking for the last entry if it's MAS_START. mas_store() and mas_destroy() now workk better with MAS_START as well. Signed-off-by: Liam R. Howlett --- diff --git a/include/linux/maple_tree.h b/include/linux/maple_tree.h index 496e539bc54e..06506c529fd7 100644 --- a/include/linux/maple_tree.h +++ b/include/linux/maple_tree.h @@ -244,6 +244,7 @@ struct ma_state { void *mas_walk(struct ma_state *mas); void *mas_store(struct ma_state *mas, void *entry); +int mas_store_gfp(struct ma_state *mas, void *entry, gfp_t gfp); void *mas_find(struct ma_state *mas, unsigned long max); bool mas_nomem(struct ma_state *mas, gfp_t gfp); diff --git a/lib/maple_tree.c b/lib/maple_tree.c index a6e8736b312c..6b5284db50af 100644 --- a/lib/maple_tree.c +++ b/lib/maple_tree.c @@ -3808,9 +3808,10 @@ void *mas_prev(struct ma_state *mas, unsigned long min) if (!mas_searchable(mas)) return NULL; + if (mas_is_start(mas)) { mas_start(mas); - return mas_last_entry(mas, ULONG_MAX); + mas_walk(mas); } do { @@ -4910,14 +4911,49 @@ EXPORT_SYMBOL(mtree_destroy); */ void *mas_store(struct ma_state *mas, void *entry) { - if (mas->index <= mas->last) - return _mas_store(mas, entry, true); + void *existing = NULL; + + if (mas->index > mas->last) + goto invalid_range; + + existing = _mas_store(mas, entry, true); + if (mas_is_err(mas)) + return existing; + + if (!mte_is_leaf(mas->node)) // gaps were updated + mas->node = MAS_START; + return existing; + +invalid_range: mas_set_err(mas, -EINVAL); return NULL; } +int mas_store_gfp(struct ma_state *mas, void *entry, gfp_t gfp) +{ + + // Detect spanning store. + if ((mas->last == mas->max && !entry) || + (mas->last > mas->max)) + mas->node = MAS_START; + +retry: + _mas_store(mas, entry, true); + if (mas_nomem(mas, gfp)) + goto retry; + + if (mas_is_err(mas)) + return xa_err(mas->node); + + if (!mte_is_leaf(mas->node)) // gaps were updated + mas->node = MAS_START; + + return 0; + +} + /* * mas_entry_count() - Set the expected number of entries that will be inserted. * @@ -4981,6 +5017,9 @@ void mas_destroy(struct ma_state *mas) unsigned char end; unsigned long range_min, range_max; + if (mas_is_start(mas)) + mas_start(mas); + __mas_walk(mas, &range_min, &range_max); end = mas_data_end(mas) + 1; if (end < mt_min_slot_count(mas->node) - 1) {