]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
maple_tree: Fix prev_node, change split balancing during inactive.
authorLiam R. Howlett <Liam.Howlett@Oracle.com>
Thu, 16 Jan 2020 15:59:08 +0000 (10:59 -0500)
committerLiam R. Howlett <Liam.Howlett@Oracle.com>
Fri, 30 Oct 2020 18:57:00 +0000 (14:57 -0400)
Also change the real world testcases to use an alloc tree.

Note: set9 fails due to attempt to get 140 nodes allocated.

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

index 7cb11bb4521ce4da3543fa57034621517ba6f064..73e310c0a70fa92bc922b7dd093f653851be401c 100644 (file)
@@ -654,6 +654,8 @@ static inline void ma_set_rcu_slot(struct maple_node *mn,
                RCU_INIT_POINTER(mn->mr64.slot[slot], val);
                break;
        case maple_arange_64:
+               if (slot >= 5)
+                       BUG();
                RCU_INIT_POINTER(mn->ma64.slot[slot], val);
                break;
        }
@@ -1213,7 +1215,7 @@ static inline void mas_ma_cp_store(struct maple_node *mn,
 }
 
 static inline unsigned char mas_cp_calc_split(struct ma_state *mas,
-               enum maple_type mas_type, bool append)
+               enum maple_type mas_type, bool append, bool active)
 {
        unsigned char max = 7, ret = 7;
        unsigned char slot;
@@ -1221,10 +1223,16 @@ static inline unsigned char mas_cp_calc_split(struct ma_state *mas,
        unsigned long half;
        unsigned long piv = 0;
        if (mas_type == maple_arange_64)
-               max = 3;
+               max = 5;
 
-       if (mas->min == 0)
-               max = 7;
+       if (!active) {
+               if (ma_is_leaf(mas_type))
+                       return max;
+               return max - 2;
+       }
+
+       //if (mas->min == 0)
+       //      max = 7;
 
        half = max / 2;
        if (ma_is_leaf(mas_type)) {
@@ -1248,11 +1256,13 @@ static inline unsigned char mas_cp_calc_split(struct ma_state *mas,
 
                }
        } else
+
        return half;
 
 done:
        if (ret < max && (append || piv == ULONG_MAX))
                ret++;
+
        return ret;
 }
 static inline unsigned long mas_leaf_max_gap(struct ma_state *mas);
@@ -1301,7 +1311,8 @@ static inline unsigned char mas_ma_cp(struct ma_state *mas,
                unsigned char p_slot, struct ma_state *left,
                struct ma_state *right, struct maple_node *mn,
                enum maple_type mn_type, unsigned long mn_min,
-               int entry_cnt, void *entry, unsigned char dst_start)
+               int entry_cnt, void *entry, unsigned char dst_start,
+               bool active)
 {
        enum maple_type mas_type = mte_node_type(mas->node);
        struct maple_node *parent = mte_to_node(mas->node);
@@ -1332,9 +1343,8 @@ static inline unsigned char mas_ma_cp(struct ma_state *mas,
        if (ma_is_leaf(mas_type))
                attempt_insert = true;
 
-
        if (right)
-               split = mas_cp_calc_split(mas, mas_type, append);
+               split = mas_cp_calc_split(mas, mas_type, append, active);
 
        if (left) {
                mas_dup_state(&cp, left);
@@ -1345,7 +1355,7 @@ static inline unsigned char mas_ma_cp(struct ma_state *mas,
                mn_type = mte_node_type(cp.node);
                p_slot = mte_parent_slot(left->node);
                parent = mte_parent(left->node);
-               mas_type = mas_parent_enum(mas, left->node);
+               mas_type = mas_parent_enum(left, left->node);
        }
 
        if (!entry_cnt)
@@ -1402,14 +1412,14 @@ static inline unsigned char mas_ma_cp(struct ma_state *mas,
 
                if (!appending) {
                        if (mt_will_coalesce(existing)) {
-                               if (prev_null) {
+                               if (prev_null && piv[2] < cp.index) {
                                        if (slot &&
                                            slot - 1 < mt_pivots[mas_type]) {
                                                ma_set_pivot(mn, slot - 1,
                                                             mas_type, piv[2]);
                                                written_piv = piv[2];
                                        }
-                                       if (update_gaps) {
+                                       if (update_gaps && entry_cnt >= 0) {
                                                mas_ma_update_gap(mas, mas_type,
                                                        mn, mn_type, piv[2],
                                                        written_piv, src_slot,
@@ -1427,13 +1437,11 @@ static inline unsigned char mas_ma_cp(struct ma_state *mas,
                                goto skip_src_slot;
                }
 
-               if (ma_is_leaf(mn_type) &&
-                   (append || (attempt_insert && cp.index <= piv[2]))) {
+               if ((append || (attempt_insert && cp.index <= piv[2]))) {
                        i = 0;
                        if (written_piv == cp.index - 1) {
                                i = 1; // previous pivot matches exactly.
-                       }
-                       else if (!src_slot && written_piv == cp.index)
+                       } else if (!src_slot && written_piv == cp.index)
                                i = 1;
 
                        if (appending)
@@ -1501,7 +1509,7 @@ skip_src_slot:
                src_slot++;
        } while ((entry_cnt-- > 0) || attempt_insert);
 
-       if (right && update_gaps)
+       if (right && update_gaps && p_slot < mt_slots[mas_type])
                parent->ma64.gap[p_slot] = max_gap;
        else if (!right)
                ret = slot - 1;
@@ -2119,7 +2127,7 @@ static inline int mas_split(struct ma_state *mas, unsigned char slot,
                mas_dup_state(&parent, mas);
                mas_ascend(&parent);
                old_parent = parent.node;
-               ptype = mte_node_type(parent.node);
+               ptype = mas_parent_enum(mas, mas->node);
                p_end = mas_data_end(&parent, ptype, &last_pivot, &coalesce);
                if (p_end - coalesce >= mt_slots[ptype] - 1) {
                        /* Must split the parent */
@@ -2130,13 +2138,13 @@ static inline int mas_split(struct ma_state *mas, unsigned char slot,
                                return 0;
 
                        mas_dup_state(&parent, mas);
-                       if (split < p_slot)
+                       if (split <= p_slot)
                                p_slot -= split;
                        // Split will return the parent.
                        old_parent = parent.node;
                        mas_set_slot(&parent, p_slot);
                }
-               ptype = mte_node_type(parent.node);
+               ptype = mas_parent_enum(mas, mas->node);
                p_end = mas_data_end(&parent, ptype, &last_pivot, &coalesce);
                mas_dup_state(mas, &parent);
                mas_set_slot(mas, p_slot);
@@ -2155,17 +2163,17 @@ static inline int mas_split(struct ma_state *mas, unsigned char slot,
        left.node = mt_mk_node(ma_mnode_ptr(mas_next_alloc(mas)), type);
        right.node  = mt_mk_node(ma_mnode_ptr(mas_next_alloc(mas)), type);
 
-       mte_set_parent(left.node, mte_to_node(new_parent), p_slot);
-       mte_set_parent(right.node, mte_to_node(new_parent), p_slot+1);
+       mte_set_parent(left.node, new_parent, p_slot);
+       mte_set_parent(right.node, new_parent, p_slot+1);
        // split the data into left & right and do the insert.
        split = mas_ma_cp(mas, p_slot, &left, &right, NULL, type, 0, entry_cnt,
-                       entry, 0);
+                       entry, 0, active);
 
        // Copy the parents information
        if (!mte_is_root(full)) {
-               MA_CP(cp, old_parent, new_parent, 0, p_slot - 1);
                unsigned char skip = 1;
 
+               MA_CP(cp, old_parent, new_parent, 0, p_slot - 1);
 
                // Copy the parent data up to p_slot - 1.
                if (p_slot)
@@ -2213,8 +2221,8 @@ static inline int mas_split(struct ma_state *mas, unsigned char slot,
 
        // Set up the ma_state for the return.  Point to the correct node for
        // the insert or subsequent split.
-       if (!mt_is_alloc(mas->tree)) // FIXME: citation needed.
-               p_slot = slot - p_slot;
+//     if (!mt_is_alloc(mas->tree)) // FIXME: Something to do with leaf size
+//             p_slot = slot - p_slot;
 
        if (mas->index <= left.max) {
                mas_dup_state(mas, &left);
@@ -2225,13 +2233,14 @@ static inline int mas_split(struct ma_state *mas, unsigned char slot,
        }
 
        // Free the full node, this may have happened in _mas_replace
-       if (old_parent != full) {
+       if (old_parent != full) {  // not root?
                if (!active)
                        mas_push_node(mas, full);
                else
                        mte_free(full);
        }
 
+       //mt_dump(mas->tree);
        return split;
 }
 
@@ -2394,7 +2403,7 @@ static inline int __mas_add(struct ma_state *mas, void *entry,
        }
 
        ret = mas_ma_cp(mas, 0, &cp, NULL, mn, mas_type, mn_min, entry_cnt, entry,
-                       append ? entry_cnt : 0);
+                       append ? entry_cnt : 0, active);
 
        mn->parent = mas_mn(mas)->parent;
        // FIXME: Propagate gaps.
@@ -2481,13 +2490,19 @@ static inline int _mas_add(struct ma_state *mas, void *entry, bool overwrite,
        // At this point, the we can perform the add.
 
        // spans node means we will replace the tree.
-       if (mas->last > mas->max)
+       if (mas->last > mas->max) {
+               //printk("Spans node %p (%lu - %lu) vs %lu - %lu\n", mas_mn(mas),
+               //              mas->min, mas->max, mas->index, mas->last);
                return mas_replace_tree(mas, entry);
+       }
 
        if (!mte_is_leaf(mas->node)) {
                // An allocation failed previously during a rebalance.  There
                // is no way to know how broken things are, so try to rebuild
                // the tree.
+               printk("Allocation failed previously\n");
+               printk("%ld-%ld landed at %p[%u]\n", mas->index, mas->last,
+                               mas_mn(mas), mas_get_slot(mas));
                mas_reset(mas);
                mas_first_node(mas, ULONG_MAX);
                return mas_replace_tree(mas, entry);
@@ -2504,9 +2519,9 @@ static inline int _mas_add(struct ma_state *mas, void *entry, bool overwrite,
        new_end = _mas_add_slot_cnt(mas, slot, min, max) - coalesce;
        if (new_end > slot_cnt) {
                mas_split(mas, slot, active, old_end, entry);
-               if (mas_is_err(mas)) {
+               if (mas_is_err(mas))
                        return 0;
-               }
+
                return old_end - new_end;
        }
 
@@ -2542,7 +2557,7 @@ static inline void ma_inactive_insert(struct ma_state *mas, void *entry)
        // Restart search for where to insert.
        mas->node = MAS_START;
        mas_start(mas);
-       mas_add(mas, entry, false, false);
+       mas_add(mas, entry, true, false);
 }
 static inline void mas_insert(struct ma_state *mas, void *entry)
 {
@@ -2601,8 +2616,7 @@ static inline void mas_root_expand(struct ma_state *mas, void *entry)
        rcu_assign_pointer(mas->tree->ma_root, mte_mk_root(mas->node));
 }
 
-static inline int mas_safe_slot(struct ma_state *mas, unsigned char *slot,
-               int delta);
+static inline int mas_safe_slot(struct ma_state *mas, int *slot, int delta);
 static inline int mas_dead_node(struct ma_state *mas, unsigned long index);
 
 static inline void mas_next_slot(struct ma_state *mas, unsigned long max)
@@ -2734,7 +2748,7 @@ no_entry:
 static inline void mas_prev_node(struct ma_state *mas, unsigned long limit)
 {
        int level;
-       unsigned char slot;
+       int slot;
        unsigned long start_piv;
 
        slot = mas_get_slot(mas);
@@ -2794,7 +2808,7 @@ restart_prev_node:
                        level--;
                        mas->node = mn;
                        slot = mas_data_end(mas, mte_node_type(mn), &last_pivot,
-                                       &coalesce);
+                                       &coalesce) + 1;
                } while (slot-- > 0);
 
 ascend:
@@ -2823,7 +2837,8 @@ static inline unsigned long mas_next_node(struct ma_state *mas,
 restart_next_node:
        level = 0;
        while (1) {
-               unsigned char count, slot;
+               unsigned char count;
+               int slot;
                struct maple_enode *mn;
                unsigned long prev_piv;
 
@@ -2835,12 +2850,10 @@ restart_next_node:
                start_piv = mas_get_safe_pivot(mas, slot);
                level++;
                mas_ascend(mas);
+               //printk("Ascend to %p[%u]\n", mas_mn(mas), slot);
 
-               if (!mas_safe_slot(mas, &slot, 1)) {
-                       if (mte_is_root(mas->node))
-                               goto no_entry;
-                       goto restart_next_node;
-               }
+               if (!mas_safe_slot(mas, &slot, 1))
+                       goto ascend;
 
                if (mas_dead_node(mas, start_piv))
                        goto restart_next_node;
@@ -2848,9 +2861,11 @@ restart_next_node:
                count = mt_slot_count(mas->node);
 
                prev_piv = mas_get_safe_pivot(mas, slot);
+               //printk("while with %p[%u]\n", mas_mn(mas), slot);
 
                while (++slot < count) {
                        unsigned long pivot = mas_get_safe_pivot(mas, slot);
+                       //printk("Checking %p[%u]\n", mas_mn(mas), slot);
 
                        if (prev_piv > max)
                                goto no_entry;
@@ -2881,9 +2896,11 @@ restart_next_node:
                        count = mt_slot_count(mas->node);
                }
 
+ascend:
                if (mte_is_root(mas->node))
                        goto no_entry;
                mas_set_slot(mas, mte_parent_slot(mas->node));
+               //printk("Set parent slot to %u from %p\n", mas_get_slot(mas), mas_mn(mas));
        }
 
 no_entry:
@@ -3044,6 +3061,7 @@ retry:
                        goto next_node;
 
                if (!mte_is_leaf(mas->node) || !mas_get_slot(mas)) {
+                       //printk("Get first entry\n");
                        *range_start = mas_first_entry(mas, limit);
                        if (mas_is_none(mas)) {
                                mas->node = last_node;
@@ -3058,9 +3076,11 @@ retry:
                        return NULL;
 
 next_node:
+               //printk("Next node from %p\n", mas_mn(mas));
                p_slot = mte_parent_slot(mas->node);
                mas_set_slot(mas, p_slot);
                mas_next_node(mas, limit);
+               //printk("Next node is %p\n", mas->node);
                mas_set_slot(mas, 0);
        }
 
@@ -3091,13 +3111,16 @@ static inline void *_mas_next(struct ma_state *mas, unsigned long limit,
                return NULL;
 
        if (!mas->node || mas_is_start(mas)) {// First run.
+               //printk("First run\n");
                *range_start = 0;
                mas_start(mas);
+               //printk("start returned %p %p\n", mas->node, mas_mn(mas));
                entry = mas_range_load(mas, range_start, &range_max);
        }
 
        if (entry)
                return entry;
+       //printk("__mas_next with %p\n", mas_mn(mas));
 
        return __mas_next(mas, limit, range_start);
 }
@@ -3261,6 +3284,8 @@ static inline int mas_cp_append(struct ma_state *mas, struct ma_state *src,
        dst.index = src->min;
        dst.max = src->max;
        while (slot <= count ) {
+//             printk("\t%s: %p[%u]/%u to %p[%u]\n", __func__, mas_mn(src),
+//                     slot, count, mas_mn(&dst), dst_cnt);
                void *entry = mte_get_rcu_slot(src->node, slot);
                dst.last = mas_get_safe_pivot(src, slot);
                if (mt_is_empty(entry) && dst.last != ULONG_MAX)
@@ -3270,9 +3295,9 @@ static inline int mas_cp_append(struct ma_state *mas, struct ma_state *src,
 
                dst_cnt = mas_ma_cp(src, 0, &dst, NULL, mas_mn(&dst), mas_type,
                                dst.min, slot,
-                               entry, dst_cnt);
+                               entry, dst_cnt, false);
 next:
-               dst.index = dst.last+1;
+               dst.index = dst.last + 1;
                slot++;
        }
        if (retry) {
@@ -3299,27 +3324,22 @@ static inline bool mas_coalesce(struct ma_state *mas, unsigned char l_end_slot,
                struct ma_cp *cp)
 {
        struct maple_node *mn;
-       bool ret = false;
+       bool free_left = false;
 
        MA_STATE(dst, mas->tree, mas->index, mas->last);
        // it is possible that all of the right node can be appended to the
-       // left
-       if (total_slots + 1 - l_end_slot < mt_slots[l_type] - l_end_slot) {
-               mas_cp_append(mas, r_mas, p_mas, l_end_slot, r_end_slot, false);
-               mte_set_rcu_slot(p_mas->node, mte_parent_slot(r_mas->node),
-                               XA_SKIP_ENTRY);
-               mte_free(r_mas->node);
-               goto done;
-       }
+       // left.
+       if (total_slots + 1 - l_end_slot < mt_slots[l_type] - l_end_slot)
+               goto use_left;
 
-       mas_node_cnt(mas, 1); // Try to allocate.
+       mas_node_cnt(mas, 1); // ensure we have a node, or allocate one.
        if (mas_is_err(mas)) {
                // Allocation failed, we could try to append as much
                // as possible here?
                return false;
        }
 
-
+       free_left = true;
        mn = mas_next_alloc(mas);
        mas_dup_state(&dst, mas);
        mn->parent = mas_mn(mas)->parent;
@@ -3330,15 +3350,18 @@ static inline bool mas_coalesce(struct ma_state *mas, unsigned char l_end_slot,
                l_end_slot++;
        }
        mas->node = dst.node;
-       // FIXME: Broken.
-       mas_cp_append(mas, r_mas, p_mas, l_end_slot, r_end_slot, true);
-       ret = true;
-done:
+
+use_left:
+       mas_cp_append(mas, r_mas, p_mas, l_end_slot, r_end_slot, false);
+
        if (!mte_is_leaf(mas->node))
                mte_adopt_children(mas->node);
 
        mte_set_pivot(p_mas->node, mte_parent_slot(mas->node), r_mas->max);
-       return ret;
+       mte_set_rcu_slot(p_mas->node, mte_parent_slot(r_mas->node),
+                       XA_SKIP_ENTRY);
+       mte_free(r_mas->node);
+       return free_left;
 }
 
 /** Private
@@ -3464,6 +3487,7 @@ done:
                mte_adopt_children(mas->node);
        if (free)
                mas_replace(mas);
+       //mt_dump(mas->tree);
        // Check parent for rebalancing.
        mas_dup_state(mas, &p_mas);
        goto start;
@@ -3844,7 +3868,7 @@ static inline bool _mas_walk(struct ma_state *mas)
  * Skip any slots that have special values.
  * If the limit of the slot is hit, then return false.
  */
-static inline int mas_safe_slot(struct ma_state *mas, unsigned char *slot,
+static inline int mas_safe_slot(struct ma_state *mas, int *slot,
                int delta)
 {
        unsigned char max = mt_slot_count(mas->node);
@@ -3852,7 +3876,14 @@ static inline int mas_safe_slot(struct ma_state *mas, unsigned char *slot,
        if (0 > delta)
                limit = 0;
        while (*slot != limit) {
-               if (!mt_is_empty(mte_get_rcu_slot(mas->node, *slot + delta)))
+               void *entry;
+               //printk("Checking safe slot %d\n", *slot + delta);
+               if (!mas_get_safe_pivot(mas, (*slot) + delta))
+                       return false;
+
+               entry = mte_get_rcu_slot(mas->node, (*slot) + delta);
+               //printk("slot type %u %p[%u] has %p\n", mte_node_type(mas->node), mas_mn(mas), *slot + delta, entry);
+               if (!mt_is_empty(entry))
                        return true;
                *slot += delta;
        }
@@ -3992,9 +4023,9 @@ static inline int mas_build_replacement(struct ma_state *mas, void *new_entry,
        struct maple_enode *last = NULL;
        unsigned long new_index, new_last;
        unsigned long r_index, r_last;
+       struct maple_tree new_tree = MTREE_INIT(name, mas->tree->ma_flags);
        void *entry;
 
-       DEFINE_MTREE(new_tree);
        MA_STATE(new_mas, &new_tree, 0, 0);
 
 
@@ -4002,6 +4033,7 @@ static inline int mas_build_replacement(struct ma_state *mas, void *new_entry,
                return 0;
        node_cnt += 3; // Room for an extra split.
 
+       //printk("Getting %ld nodes\n", node_cnt);
        mas_node_cnt(mas, node_cnt);
        if (mas_is_err(mas))
                return 0;
@@ -4021,6 +4053,7 @@ static inline int mas_build_replacement(struct ma_state *mas, void *new_entry,
        mas_reset(mas);
        mas->index = 0;
        mas->last = 0;
+       //printk("Start left\n");
        mas_for_each(mas, entry, new_index - 1) {
                new_mas.index = mas->index;
                new_mas.last = mas_get_safe_pivot(mas, mas_get_slot(mas));
@@ -4028,9 +4061,11 @@ static inline int mas_build_replacement(struct ma_state *mas, void *new_entry,
                        BUG_ON(1);
                ma_inactive_insert(&new_mas, entry);
                if (mas_is_err(&new_mas)) {
+                       //mt_dump(new_mas.tree);
                        goto error;
                }
        }
+       //printk("Done\n");
 
        // Insert the new value.
        new_mas.index = new_index;
@@ -4045,12 +4080,12 @@ static inline int mas_build_replacement(struct ma_state *mas, void *new_entry,
         * - new_mas.last goes beyond anything right now (no entries)
         * - new_mas.last cuts a range
         * - new_mas.last ends in a null
-        * - new_mas.last has a sequentially next value (48)
+        * - new_mas.last has a sequentially next value
         */
 
        mas_reset(mas);
-       mas->index = new_last+1;
-       mas->last = new_last+1;
+       mas->index = new_last + 1;
+       mas->last = new_last + 1;
        _mas_range_walk(mas, &r_index, &r_last);
 
        if (mas_get_slot(mas) == MAPLE_NODE_SLOTS)
@@ -4069,6 +4104,8 @@ static inline int mas_build_replacement(struct ma_state *mas, void *new_entry,
                }
        }
 
+       //printk("Start right from %lu\n", mas->index);
+       //mt_dump(new_mas.tree);
        mas_for_each(mas, entry, ULONG_MAX) {
                if (mas->index < new_index)
                        continue;
@@ -4079,6 +4116,7 @@ static inline int mas_build_replacement(struct ma_state *mas, void *new_entry,
                if (mas_is_err(&new_mas))
                        goto error;
        }
+       //printk("Done\n");
 
 skip_right:
 
@@ -4094,7 +4132,7 @@ skip_right:
 error:
        if (new_mas.tree)
                mte_destroy_walk(new_mas.tree->ma_root);
-       printk("Failed on %lu-%lu\n", mas->index, mas->last);
+       //printk("Failed on %lu-%lu\n", mas->index, mas->last);
        mt_dump(mas->tree);
        BUG_ON(1);
        return 0;
@@ -4928,6 +4966,8 @@ void mt_dump_arange64(void *entry, unsigned long min, unsigned long max,
                        mt_dump_entry(node->slot[i], first, last, depth + 1);
                else if (xa_is_skip(node->slot[i]))
                        mt_dump_entry(node->slot[i], first, last, depth + 1);
+               else if (xa_is_retry(node->slot[i]))
+                       mt_dump_entry(node->slot[i], first, last, depth + 1);
                else if (node->slot[i])
                        mt_dump_node(node->slot[i], first, last, depth + 1);