]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
maple_tree: Fix check_find_2 testcase.
authorLiam R. Howlett <Liam.Howlett@Oracle.com>
Tue, 15 Oct 2019 02:40:35 +0000 (22:40 -0400)
committerLiam R. Howlett <Liam.Howlett@Oracle.com>
Tue, 15 Oct 2019 02:40:35 +0000 (22:40 -0400)
The check_find_2 exposed issues when the tree was a simple pointer.  The
pointer case was not being handled correctly in mas_start, or _mas_walk.
Fixing these two functions also required fixing calling functions to
check for MAS_ROOT (a root pointer).

There was also a bug in mas_next_entry where the next node was checked -
which is not possible if it's the root node.

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

index 6f14ed658a0e5739ca4592f7da21b01153dfad82..793f3e18bbf336e2c13f502d0cb585918229a789 100644 (file)
@@ -223,7 +223,7 @@ static inline bool _ma_is_root(struct maple_node *node)
        return ((unsigned long)node->parent & MA_ROOT_PARENT);
 }
 
-static inline bool mte_is_root(struct maple_enode *node)
+static inline bool mte_is_root(const struct maple_enode *node)
 {
        return _ma_is_root(mte_to_node(node));
 }
@@ -947,17 +947,21 @@ static inline struct maple_node *mas_node_cnt(struct ma_state *ms, int count)
 
 static inline struct maple_enode *mas_start(struct ma_state *mas)
 {
-       if (mas->node == MAS_START) {
+       if (mas_is_start(mas)) {
+               struct maple_enode *root;
+
                mas->min = 0;
+               if (!mas->tree->ma_root) // empty tree.
+                       return NULL;
+
                if (!xa_is_node(mas->tree->ma_root)) {
                        if (mas->index > 0)
                                return NULL;
                        mas->node = MAS_ROOT;
                        mas_set_slot(mas, MAPLE_NODE_SLOTS);
-                       return NULL;
+                       return mas->node;
                }
-               struct maple_enode *root = mte_safe_root(
-                               mas->tree->ma_root);
+               root = mte_safe_root(mas->tree->ma_root);
                mas->max = mt_node_max(root);
                return root;
        }
@@ -2524,6 +2528,11 @@ static inline unsigned long mas_next_entry(struct ma_state *mas,
                        if (mas_next_nentry(mas, max, &pivot))
                                break;
 
+                       if (mte_is_root(mas->node)) {
+                               mas->node = MAS_NONE;
+                               break;
+                       }
+
                        p_slot = mte_parent_slot(mas->node);
                        mas_set_slot(mas, p_slot);
                        mas_next_node(mas, max);
@@ -3278,6 +3287,14 @@ done:
 static inline bool _mas_walk(struct ma_state *mas)
 {
        mas->node = mas_start(mas);
+       if (!mas->node) {
+               mas_set_slot(mas, MAPLE_NODE_SLOTS);
+               return false;
+       }
+
+       if (mas->node == MAS_ROOT)
+               return true;
+
        mas_set_slot(mas, 0);
        return __mas_walk(mas);
 }
@@ -3305,6 +3322,7 @@ static inline int mas_dead_node(struct ma_state *mas, unsigned long index)
 {
        if (!mas->node)
                return 0;
+
        if (!mte_dead_node(mas->node))
                return 0;
 
@@ -3339,10 +3357,16 @@ void *mas_find(struct ma_state *mas, unsigned long max)
        unsigned char slot = 0;
 
        if (!mas->node)
-               return MAS_NONE;
+               goto not_found;
 
-       if (mas->node == MAS_START) {
+       if (mas_is_start(mas)) {
                _mas_walk(mas);
+               if (!mas->node)
+                       return NULL;
+
+               if (mas->node == MAS_ROOT)
+                       return mas->tree->ma_root;
+
                do {} while (mas_dead_node(mas, mas->index));
 
                slot = mas_get_slot(mas);
@@ -3358,6 +3382,8 @@ void *mas_find(struct ma_state *mas, unsigned long max)
                        goto done;
                }
        }
+       if (mas->node == MAS_ROOT)
+               goto not_found;
 
        last_piv = mas_safe_next_entry(mas, max);
        if (mas->node == MAS_NONE)
@@ -3416,6 +3442,14 @@ void *mt_find(struct maple_tree *mt, unsigned long start,
 
        rcu_read_lock();
        _mas_walk(&mas);
+       if (!mas.node)
+               goto done;
+
+       if (mas.node == MAS_ROOT) {
+               entry = mas.tree->ma_root;
+               goto done;
+       }
+
        do {} while (mas_dead_node(&mas, mas.index));
 
        slot = mas_get_slot(&mas);
@@ -3461,6 +3495,13 @@ void *mt_find_after(struct maple_tree *mt, unsigned long *index,
 
        rcu_read_lock();
        _mas_walk(&mas);
+       if (!mas.node)
+               goto done;
+
+       if (mas.node == MAS_ROOT) {
+               entry = mas.tree->ma_root;
+               goto done;
+       }
 retry:
        mas_set_slot(&mas, mas_get_slot(&mas) + 1);
        mas_safe_next_entry(&mas, max);
@@ -3655,6 +3696,10 @@ static inline void mas_rev_awalk(struct ma_state *mas, unsigned long size)
        unsigned char slot, coalesce;
 
        mas->node = mas_start(mas);
+       if (!mas->node) {
+               mas_set_slot(mas, MAPLE_NODE_SLOTS);
+               return;
+       }
        slot = mas_data_end(mas, mte_node_type(mas->node), &last_piv, &coalesce);
        mas_set_slot(mas, slot);
 
@@ -3678,6 +3723,9 @@ static inline void mas_awalk(struct ma_state *mas, unsigned long size)
        struct maple_enode *last = NULL;
 
        mas->node = mas_start(mas);
+       if (!mas->node)
+               return;
+
        mas_set_slot(mas, 0);
 
        /* There are 4 options:
@@ -3789,6 +3837,11 @@ static inline int ma_alloc(struct ma_state *mas, void *entry,
        unsigned long min;
 
        mas->node = mas_start(mas);
+       if (!mas->node) {
+               slot = 0;
+               goto empty_tree;
+       }
+
        if (!xa_is_node(rcu_dereference(mas->tree->ma_root))) {
                ma_root_expand(mas, entry);
                if (!mas->index)
@@ -3797,6 +3850,8 @@ static inline int ma_alloc(struct ma_state *mas, void *entry,
        }
 
        mas_awalk(mas, size);
+       // cannot be an empty tree here.
+
        if (mas_is_err(mas))
                return xa_err(mas->node);
 
@@ -3813,6 +3868,7 @@ static inline int ma_alloc(struct ma_state *mas, void *entry,
        if (mas->index < min)
                mas->index = min;
 
+empty_tree:
        return mas_fill_gap(mas, entry, slot, size, index);
 
 no_gap:
@@ -3833,6 +3889,11 @@ static inline int ma_rev_alloc(struct ma_state *mas, void *entry,
        unsigned char slot = MAPLE_NODE_SLOTS;
 
        mas->node = mas_start(mas);
+       if (!mas->node) {
+               slot = 0;
+               goto empty_tree;
+       }
+
        if (!xa_is_node(rcu_dereference(mas->tree->ma_root))) {
                ma_root_expand(mas, entry);
                if (!mas->index)
@@ -3841,6 +3902,8 @@ static inline int ma_rev_alloc(struct ma_state *mas, void *entry,
        }
 
        mas_rev_awalk(mas, size);
+       // cannot be empty tree.
+
        if (mas_is_err(mas))
                return xa_err(mas->node);
 
@@ -3859,6 +3922,7 @@ static inline int ma_rev_alloc(struct ma_state *mas, void *entry,
 
        mas->last = mas->index + size - 1;
 
+empty_tree:
        return mas_fill_gap(mas, entry, slot, size, index);
 
 no_gap: