maple_tree: Add mas_store_gfp() and fix mas_prev() and mas_store()
authorLiam R. Howlett <Liam.Howlett@Oracle.com>
Fri, 6 Nov 2020 21:52:59 +0000 (16:52 -0500)
committerLiam R. Howlett <Liam.Howlett@Oracle.com>
Fri, 6 Nov 2020 21:52:59 +0000 (16:52 -0500)
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 <Liam.Howlett@Oracle.com>
include/linux/maple_tree.h
lib/maple_tree.c

index 496e539bc54ebc6a231ff67c153796404cecce27..06506c529fd71f38bd2ce8de42ce6aa7f4875f87 100644 (file)
@@ -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);
index a6e8736b312cccf9c3e5595d4535e460aa397b41..6b5284db50af6f94e7f3348bab38addf9b4cf8a0 100644 (file)
@@ -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) {