]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
maple_tree: Split support
authorLiam R. Howlett <Liam.Howlett@Oracle.com>
Fri, 18 Jan 2019 15:55:38 +0000 (10:55 -0500)
committerLiam R. Howlett <Liam.Howlett@Oracle.com>
Fri, 30 Oct 2020 18:55:17 +0000 (14:55 -0400)
Initial split support.  Walks up the tree splitting as necessary to
support the addition of a node.

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

index 8176228b60f454a35b8f07a87388cbb640a96dd9..3de603ee86310e3857513c645edafa4808982639 100644 (file)
@@ -171,9 +171,27 @@ void mtree_destroy(struct maple_tree *);
  */
 static inline bool mtree_empty(const struct maple_tree *mt)
 {
-       return mt->ma_root == NULL;
+       return rcu_dereference(mt->ma_root) == NULL;
 }
 
+struct ma_cp {
+       struct maple_node *src;
+       struct maple_node *dst;
+       unsigned char src_start;
+       unsigned char src_end;
+       unsigned char dst_start;
+       unsigned char dst_end;
+};
+#define MA_CP(name, snode, dnode, sstart, send)                         \
+       struct ma_cp name = {                                           \
+               .src = snode,                                           \
+               .dst = dnode,                                           \
+               .src_start = sstart,                                    \
+               .src_end = send,                                        \
+               .dst_start = 0,                                         \
+               .dst_end = MAPLE_RANGE64_SLOTS - 1                      \
+       }
+
 /* Advanced API */
 
 struct ma_state {
index d0a8f127a8ee76168cb5ef805209587716d86b47..76096601e097ede055b0d3f6ba77f10ba7f80374 100644 (file)
@@ -42,6 +42,11 @@ static inline bool mt_is_leaf(const void *entry)
        return mt_node_type(entry) < maple_range_16;
 }
 
+static inline enum maple_type mt_node_hole(const void *entry)
+{
+       return (unsigned long)entry & 4;
+
+}
 static inline bool mt_is_reserved(const void *entry)
 {
        return ((unsigned long)entry < 4096) && xa_is_internal(entry);
@@ -108,32 +113,33 @@ static inline unsigned int mt_slot_shift(struct maple_node *node)
 static inline void mt_set_parent(struct maple_node *node,
                                 struct maple_node *parent, short slot)
 {
-       unsigned int bitmask = mt_slot_mask(node);
-       unsigned int slot_shift = mt_slot_shift(node);
+       unsigned long bitmask = mt_slot_mask(node);
+       unsigned long slot_shift = mt_slot_shift(node);
        unsigned long val = (unsigned long) parent;
 
        BUG_ON(slot > MAPLE_NODE_SLOTS); // Only 4 bits to use.
        val &= ~bitmask; // Remove any old slot number.
        val |= (slot << slot_shift); // Set the slot.
-       node->parent = (struct maple_node *)val;
+       mt_to_node(node)->parent = (struct maple_node *)val;
 }
 
 static inline unsigned int mt_parent_slot(struct maple_node *node)
 {
        unsigned int bitmask = mt_slot_mask(node);
        unsigned int slot_shift = mt_slot_shift(node);
-       unsigned long val = (unsigned long) node->parent;
+       unsigned long val = (unsigned long) mt_to_node(node)->parent;
 
        return (val & bitmask) >> slot_shift;
 }
 
 static inline void *mt_parent(struct maple_node *node)
 {
-       unsigned int bitmask = mt_slot_mask(node) | 7;
+       unsigned long bitmask = mt_slot_mask(node) | 7;
 
-       return (void *)((unsigned long)(node->parent) & ~bitmask);
+       return (void *)((unsigned long)(mt_to_node(node)->parent) & ~bitmask);
 
 }
+
 static inline struct maple_node *ma_get_alloc(const struct ma_state *ms)
 {
        return (struct maple_node *)((unsigned long)ms->alloc & ~0x7F);
@@ -178,6 +184,24 @@ static inline bool ma_is_root(struct maple_node *node)
                return true;
        return false;
 }
+
+static inline void ma_encoded_parent(struct ma_state *mas)
+{
+       struct maple_node *parent, *gparent;
+       unsigned char slot;
+
+       if (ma_is_root(mt_to_node(mas->node)->parent)) {
+               mas->node = rcu_dereference(mas->tree->ma_root);
+               return;
+       }
+
+       parent = mt_parent(mas->node);
+       gparent = mt_parent(parent);
+       slot = mt_parent_slot(parent);
+       mas->node = rcu_dereference(gparent->mr64.slot[slot]);
+       return;
+}
+
 static inline struct maple_node *ma_next_alloc(struct ma_state *ms)
 {
        int cnt;
@@ -283,35 +307,34 @@ static struct maple_node *mas_node_cnt(struct ma_state *ms, int count)
        return ms->alloc;
 }
 
-static void *mas_start(struct ma_state *ms)
+static void *mas_start(struct ma_state *mas)
 {
        void *entry;
 
-       if (mas_is_err(ms))
+       if (mas_is_err(mas))
                return NULL;
 
-       if (ms->node == MAS_START) {
-               entry = ms->tree->ma_root;
+       if (mas->node == MAS_START) {
+               entry = mas->tree->ma_root;
                if (!xa_is_node(entry)) {
-                       if (ms->index > 0)
+                       if (mas->index > 0)
                                return NULL;
-                       ms->node = MAS_ROOT;
-                       ma_set_slot(ms, MAPLE_NODE_SLOTS);
+                       mas->node = MAS_ROOT;
+                       ma_set_slot(mas, MAPLE_NODE_SLOTS);
                } else {
                        entry = mt_safe_root(entry);
                }
        } else {
-               entry = ms->node;
+               entry = mas->node;
        }
 
        return entry;
 }
 
-unsigned char ma_data_end_r64(const struct ma_state *ms)
+unsigned char ma_data_end_r64(const struct maple_range_64 *mr64,
+                             unsigned long last)
 {
-       struct maple_range_64 *mr64 = &mt_to_node(ms->node)->mr64;
        unsigned char data_end = 0;
-       unsigned long last = ms->max;
 
        for (data_end = 0; data_end < MAPLE_RANGE64_SLOTS - 1; data_end++) {
                last = mr64->pivot[data_end];
@@ -319,21 +342,131 @@ unsigned char ma_data_end_r64(const struct ma_state *ms)
                        return data_end;
        }
 
-       if (mr64->slot[data_end + 1] != NULL)
+       if (mr64->slot[data_end] != NULL)
                data_end++;
 
        return data_end;
 }
 
+static int ma_calc_split(struct ma_state *mas)
+{
+       int i;
+       struct maple_range_64 *full64 = &mt_to_node(mas->node)->mr64;
+       unsigned long min = mas->min;
+       unsigned long max = min;
+
+       for (i = 3; i < MAPLE_RANGE64_SLOTS - 1; i++) {
+               max = full64->pivot[i];
+               if ((max - min) >= 8)
+                       break;
+       }
+       return i;
+}
+void ma_copy(struct ma_state *mas, struct ma_cp *cp)
+{
+       struct maple_range_64 *src64 = &cp->src->mr64;
+       struct maple_range_64 *dst64;
+       unsigned char sloc = cp->src_start; // src location
+       unsigned char dloc = cp->dst_start; // dst location
+
+       if (!cp->dst) {
+               /* Allocate a new node */
+               mas_node_cnt(mas, 1);
+               if (mas_is_err(mas))
+                       return;
+               cp->dst = ma_next_alloc(mas);
+       }
+
+       dst64 = &cp->dst->mr64;
+       while (sloc <= cp->src_end &&
+                       dloc <= cp->dst_end) {
+
+               if (sloc != 0 && sloc < MAPLE_RANGE64_SLOTS - 2 &&
+                   src64->pivot[sloc] == 0)
+                       break;
+
+               if (sloc < MAPLE_RANGE64_SLOTS - 1 &&
+                   dloc < MAPLE_RANGE64_SLOTS - 1)
+                       dst64->pivot[dloc] = src64->pivot[sloc];
+               else if (dloc > MAPLE_RANGE64_SLOTS - 1)
+                       dst64->pivot[dloc] = mas->max;
+
+               RCU_INIT_POINTER(dst64->slot[dloc], src64->slot[sloc]);
+
+               /* Increment counters */
+               sloc++;
+               dloc++;
+       }
+       cp->dst_start = dloc;
+}
+static int ma_cp_data_64(struct ma_state *mas, struct maple_node *left,
+                         struct maple_node *right, int off)
+{
+
+       int split = ma_calc_split(mas);
+
+       MA_CP(cp, mt_to_node(mas->node), left, off, split);
+       ma_copy(mas, &cp);
+       cp.src_start = split + 1;
+       cp.src_end = MAPLE_RANGE64_SLOTS - 1;
+       cp.dst = right;
+       cp.dst_start = 0;
+       ma_copy(mas, &cp);
+       return split;
+}
+
+static void ma_adopt_children(struct maple_node *parent)
+{
+
+       struct maple_range_64 *p64 = &parent->mr64;
+       struct maple_node *child;
+       unsigned char slot;
+
+       for (slot = 0; slot < MAPLE_RANGE64_SLOTS; slot++) {
+               if (slot != 0 && slot < MAPLE_RANGE64_SLOTS - 1 &&
+                   p64->pivot[slot] == 0)
+                       break;
+
+               child = p64->slot[slot];
+               if (child)
+                       mt_set_parent(child, parent, slot);
+       }
+}
+
 /* Private
- *
- * Splitting is done in a lazy-fashion.  As such, the parent may not have room
- * for two entries and will require splitting itself.  Rinse & repeat.
+ * Replace mn with mas->node in the tree
  */
-static int ma_split(struct ma_state *mas, unsigned char slot,
-                    unsigned char num)
+void mt_replace(struct ma_state *mas)
 {
-       return 0;
+       struct maple_node *mn = mt_to_node(mas->node);
+       struct maple_node *parent;
+       struct maple_range_64 *p64;
+       unsigned char slot = mt_parent_slot(mn);
+       struct maple_node *prev;
+
+       if (ma_is_root(mas->node)) {
+               prev = mas->tree->ma_root;
+       } else {
+               parent = mt_parent(mas->node);
+               p64 = &parent->mr64;
+               prev = p64->slot[slot];
+       }
+
+       if (prev == mn)
+               return;
+
+       if (!mt_is_leaf(mas->node))
+               ma_adopt_children(mn);
+
+       if (ma_is_root(mas->node)) {
+               mn->parent = (struct maple_node *)
+                             ((unsigned long)mas->tree | MA_ROOT_PARENT);
+               rcu_assign_pointer(mas->tree->ma_root, mt_mk_root(mas->node));
+       } else {
+               rcu_assign_pointer(parent->slot[slot], mas->node);
+       }
+
+       mt_free(mt_to_node(prev));
 }
 /* Private
  *
@@ -346,27 +479,246 @@ static int ma_split(struct ma_state *mas, unsigned char slot,
 static struct maple_range_64 *mas_partial_copy(struct ma_state *mas,
                                               unsigned char end)
 {
-       struct maple_node *smn = mt_to_node(mas->node);
-       struct maple_range_64 *src = &smn->mr64;
-       struct maple_range_64 *dst = NULL;
-       struct maple_node *dmn;
-       int i = 0;
-       /* Allocate a new node */
-       mas_node_cnt(mas, 1);
+       MA_CP(cp, mt_to_node(mas->node), NULL, 0, end);
+       ma_copy(mas, &cp);
        if (mas_is_err(mas))
                return NULL;
+       mas->node = mt_mk_node(cp.dst, mt_node_type(mas->node));
+       cp.dst->parent = cp.src->parent;
+       return &cp.dst->mr64;
+}
+
+static void ma_link(struct maple_node *new, struct maple_node *parent,
+               unsigned char slot, unsigned long pivot, enum maple_type type)
+{
+       struct maple_range_64 *p64 = &parent->mr64;
+       struct maple_node *new_enc = mt_mk_node(new, type);
+
+       mt_set_parent(new, parent, slot);
+       p64->pivot[slot] = pivot;
+       RCU_INIT_POINTER(p64->slot[slot], new_enc);
+       if (!mt_is_leaf(new_enc))
+               ma_adopt_children(new);
+
+}
+static int ma_split(struct ma_state *mas, unsigned char slot,
+                    unsigned char num, int depth)
+{
+       struct maple_node *enc_full = mas->node; // Encoded full node.
+       struct maple_node *full = mt_to_node(mas->node);
+       unsigned char split, p_slot = 0, p_end = 0;
+       struct maple_node *old_parent, *new_parent, *left, *right;
+       enum maple_type ctype; // Child type.
+       unsigned long pivot;
+
+       if (ma_is_root(full)) {
+               old_parent = full;
+               mas->node = mt_safe_root(mas->node);
+       } else {
+               old_parent = mt_parent(mas->node);
+               p_end = ma_data_end_r64(&old_parent->mr64, UINT_MAX);
+
+               if (p_end >= MAPLE_RANGE64_SLOTS - 1) {
+                       /* Must split the parent */
+                       unsigned long max = mas->max;
+                       unsigned long min = mas->min;
+
+                       ma_encoded_parent(mas);
+                       p_slot = mt_parent_slot(enc_full);
+                       split = ma_split(mas, p_slot, p_end, 1);
+                       if (mas_is_err(mas))
+                               return 0;
+                       if (split <= p_slot)
+                               p_slot -= split;
+                       // Split will return the parent.
+                       old_parent = mt_to_node(mas->node);
+                       mas->node = old_parent->mr64.slot[p_slot];
+               }
+       }
+
+       enc_full = mas->node;
+       mas_node_cnt(mas, 3);
+       if (mas_is_err(mas))
+               return 0;
+
+       // Allocations.
+       right = ma_next_alloc(mas);
+       left = ma_next_alloc(mas);
+       new_parent = ma_next_alloc(mas);
+
+       // Record the node type for the children types.
+       ctype = mt_node_type(enc_full);
+       // copy the data and calculate the split location.
+       split = ma_cp_data_64(mas, left, right, 0);
+       // Copy the parents information
+       if (!ma_is_root(full)) {
+               // Copy the parent data and leave a hole.
+               p_slot = mt_parent_slot(enc_full);
+               MA_CP(cp, old_parent, new_parent, 0, p_slot);
+               ma_copy(mas, &cp);
+               cp.dst_start += 1;
+               cp.src_start = p_slot + 1;
+               cp.src_end = p_end;
+               ma_copy(mas, &cp);
+               // Update encoded slots in children
+               ma_adopt_children(new_parent);
+       }
+
+       // Copy grand parent to the parent, including slot encoding.
+       new_parent->parent = old_parent->parent;
+       // Set up the link to the right in the new parent
+       if (ma_is_root(full))
+               pivot = ULONG_MAX;
+       else
+               pivot = old_parent->mr64.pivot[p_slot];
+
+       ma_link(right, new_parent, p_slot + 1, pivot, ctype);
+
+       // Set up the link to the left in the new parent
+       if (split < MAPLE_RANGE64_SLOTS - 1)
+               pivot = full->mr64.pivot[split];
+       else
+               pivot = left->mr64.pivot[split - 1];
+
+       ma_link(left, new_parent, p_slot, pivot, ctype);
+
+       // Set up maple state for replacement of node.
+       // Note: old_parent may be the old parent or the full node.
+       if (ma_is_root(old_parent)) {
+               mas->node = mt_mk_node(new_parent, maple_range_64);
+       } else {
+               struct maple_node *gparent = mt_parent(old_parent);
+
+               old_parent = gparent->mr64.slot[mt_parent_slot(old_parent)];
+               mas->node = mt_mk_node(new_parent, mt_node_type(old_parent));
+       }
+       // Replace the parent node & free the old parent.
+       mt_replace(mas);
+
+       // Set up the ma_state for the return.  Point to the correct node for
+       // the insert.
+       if (mas->index <= pivot)
+               mas->node = mt_mk_node(left, ctype);
+       else
+               mas->node = mt_mk_node(right, ctype);
+
+       // Free the full node.
+       mt_free(full);
+       return split;
+}
+/* Private
+ *
+ * Splitting is done in a lazy-fashion.  As such, the parent may not have room
+ * for two entries and will require splitting itself.  Rinse & repeat.
+ *
+ *
+ * If this is root, increase the branch height.
+ * If this is not root, promote the middle item as a pivot to the parent.
+ * Copy 1/2 data to each left & right children.
+ *
+ *
+ */
+static int _ma_split(struct ma_state *mas, unsigned char slot,
+                    unsigned char num, int depth)
+{
+       struct maple_node *full = mas->node;
+       struct maple_node *mn = mt_to_node(mas->node);
+       struct maple_node *old_parent, *new_parent, *left, *right;
+       struct maple_range_64 *nparent64;
+       unsigned char p_slot;
+       unsigned char p_end;
+       unsigned char split;
+
+       if (ma_is_root(full)) {
+               old_parent = mn;
+               mas->node = mt_safe_root(mas->node);
+               p_slot = 0;
+               p_end = 0;
+       } else {
+               old_parent = mt_parent(mn);
+               p_slot = mt_parent_slot(mn);
+               p_end = ma_data_end_r64(&old_parent->mr64, UINT_MAX);
+       }
+
+
+       if (p_end >= MAPLE_RANGE64_SLOTS - 1) {
+               mas->node = mn;
+               ma_encoded_parent(mas);
+               unsigned char split = ma_split(mas, p_slot, p_end, depth + 1);
+               if (mas_is_err(mas))
+                       return 0;
+
+               if (split < slot)
+                       slot -= split;
 
-       dmn = ma_next_alloc(mas);
-       dst = &dmn->mr64;
-       dmn->parent = smn->parent;
-       for (i = 0; i < end;i++)
-       {
-               RCU_INIT_POINTER(dst->slot[i],
-                               src->slot[i]);
-               dst->pivot[i] = src->pivot[i];
+               mn = mt_to_node(mas->node);
+               mas->node = full;
+               old_parent = mt_parent(mn);
+               p_slot = mt_parent_slot(mn);
+               p_end = ma_data_end_r64(&old_parent->mr64, UINT_MAX);
+       }
+
+       mas_node_cnt(mas, 3);
+       if (mas_is_err(mas))
+               return 0;
+
+       new_parent = ma_next_alloc(mas);
+       left = ma_next_alloc(mas);
+       right = ma_next_alloc(mas);
+
+       split = ma_cp_data_64(mas, left, right, 0);
+
+       new_parent->parent = old_parent->parent;
+       nparent64 = &new_parent->mr64;
+
+       if (!ma_is_root(full)) {
+               MA_CP(cp, old_parent, new_parent, 0, p_slot);
+               ma_copy(mas, &cp);
+               cp.dst_start += 1;
+               cp.src_start = p_slot+1;
+               cp.src_end = p_end;
+               ma_copy(mas, &cp);
+       }
+
+       mt_set_parent(left, new_parent, p_slot);
+       if (split >= MAPLE_RANGE64_SLOTS - 1)
+               nparent64->pivot[p_slot] = mn->mr64.pivot[split - 1];
+       else
+               nparent64->pivot[p_slot] = mn->mr64.pivot[split];
+
+       RCU_INIT_POINTER(nparent64->slot[p_slot],
+                       mt_mk_node(left, mt_node_type(full)));
+
+       mt_set_parent(right, new_parent, ++p_slot);
+       nparent64->pivot[p_slot] = mas->max;
+       RCU_INIT_POINTER(nparent64->slot[p_slot],
+                       mt_mk_node(right, mt_node_type(full)));
+
+       if (ma_is_root(old_parent)) {
+               mas->node = mt_mk_node(new_parent, maple_range_64);
+               mas->node = mt_mk_root(mas->node);
+               if (!mt_is_leaf(left)) {
+                       ma_adopt_children(left);
+                       ma_adopt_children(right);
+               }
+       } else {
+               struct maple_node *gparent = mt_parent(old_parent);
+               old_parent = gparent->mr64.slot[mt_parent_slot(old_parent)];
+               mas->node = mt_mk_node(new_parent, mt_node_type(old_parent));
        }
-       mas->node = mt_mk_node(dmn, maple_leaf_64);
-       return dst;
+       mt_replace(mas); // Replace old with new parent & free.
+
+       mas->node = nparent64->slot[p_slot-1];
+       mas->max = nparent64->pivot[p_slot-1];
+       if (split <= slot) {
+               mas->node = nparent64->slot[p_slot];
+               mas->min = nparent64->pivot[p_slot-1];
+               mas->max = nparent64->pivot[p_slot];
+       } else {
+       }
+
+       mt_free(mn); // Free full node.
+       return split;
 }
 /* Private
  *
@@ -381,14 +733,15 @@ static struct maple_range_64 *mas_partial_copy(struct ma_state *mas,
  * 4. Write the entry.
  *
  */
-static int _ma_insert(struct ma_state *ms, void *entry, unsigned char slot)
+static int _ma_insert(struct ma_state *mas, void *entry, unsigned char slot)
 {
-       struct maple_range_64 *mr64 = &mt_to_node(ms->node)->mr64;
+       struct maple_range_64 *mr64 = &mt_to_node(mas->node)->mr64;
+       struct maple_node *p_mn;
        struct maple_range_64 *p_mr64;
-       int o_end = ma_data_end_r64(ms); // Old end
+       int o_end = ma_data_end_r64(mr64, mas->max); // Old end
        int n_end = o_end;               // New end
-       unsigned long max = ms->max;
-       unsigned long min = ms->min;
+       unsigned long max = mas->max;
+       unsigned long min = mas->min;
        int ret = 1;
 
        /* Calculate the range of the slot */
@@ -402,45 +755,59 @@ static int _ma_insert(struct ma_state *ms, void *entry, unsigned char slot)
                min = mr64->pivot[slot - 1];
 
        /* Figure out how many slots are needed for the entry. */
-       if (max != ms->last)
+       if (max != mas->last)
                n_end++;
 
-       if (min != ms->index - 1)
+       if (mas->index && min != mas->index - 1)
                n_end++;
 
        if (n_end > MAPLE_RANGE64_SLOTS -1) {
-               return ma_split(ms, slot, n_end);
-       }
+               unsigned char split = ma_split(mas, slot, o_end, 0);
+               if (mas_is_err(mas))
+                       return 0;
+
 
+               if (split <= slot)
+                       slot -= split;
+
+               n_end -= split;
+               mr64 = &mt_to_node(mas->node)->mr64;
+               o_end = ma_data_end_r64(mr64, mas->max); // Old end is not so old now.
+               if (o_end == 1)
+                       o_end = 0; // This node is empty, append at the start.
+       }
        /* Save the node in case we are not appending. */
        p_mr64 = mr64;
+       p_mn = mt_to_node(mas->node);
 
        /* Creates a new node and copies until slot (inclusively) */
        if (slot == o_end) {
-               /* Appending */
-               o_end = n_end;
+               o_end = n_end; /* Appending */
        } else {
                /* Not appending */
-               mr64 = mas_partial_copy(ms, slot);
+               if (p_mr64 == mr64) {
+                       mr64 = mas_partial_copy(mas, slot);
+                       if (mas_is_err(mas))
+                               return 0;
+               }
+
                o_end = slot;
-               if (mas_is_err(ms))
-                       return 0;
        }
 
-       if (min != ms->index - 1) {
+       if (mas->index && min != mas->index - 1) {
                /* When writing a NULL entry, the order must be reversed to
                 * ensure readers don't get incorrect data on appends
                 */
                /* Write the entry */
                RCU_INIT_POINTER(mr64->slot[++slot], entry);
-               mr64->pivot[slot] = ms->last;
+               mr64->pivot[slot] = mas->last;
                /* Write NULL entry */
                RCU_INIT_POINTER(mr64->slot[--slot], NULL);
                if (o_end == n_end) // Append.
                        wmb();
 
-               mr64->pivot[slot] = ms->index - 1;
-               slot+=2;
+               mr64->pivot[slot] = mas->index - 1;
+               slot += 2;
                ret = 2;
        } else {
                /* Write the entry */
@@ -448,28 +815,28 @@ static int _ma_insert(struct ma_state *ms, void *entry, unsigned char slot)
                if (o_end == n_end) // Append.
                        wmb();
 
-               mr64->pivot[slot++] = ms->last;
+               mr64->pivot[slot++] = mas->last;
        }
 
        /* Skip possible duplicate entry that contains a NULL */
-       if (p_mr64->pivot[o_end] == ms->last)
+       if (o_end != n_end && p_mr64->pivot[o_end] == mas->last)
                o_end++;
 
        /* Copy remainder of node if this isn't an append */
-       for ( ; o_end < n_end; slot++, o_end++) {
-               if(p_mr64->pivot[o_end] == 0)
-                       break;
-               RCU_INIT_POINTER(mr64->slot[slot],
-                               p_mr64->slot[o_end]);
-               if (slot < MAPLE_RANGE64_SLOTS - 1)
-                       mr64->pivot[slot] = p_mr64->pivot[o_end];
-       }
+       MA_CP(cp, p_mn, mt_to_node(mas->node), o_end, MAPLE_RANGE64_SLOTS - 1);
+       cp.dst_start = slot;
+       cp.dst_end = n_end;
+       ma_copy(mas, &cp);
+
+       if (p_mr64 != mr64)
+               mt_replace(mas);
+
        return ret;
 }
 
 static void ma_root_expand(struct ma_state *ms, void *entry)
 {
-       void *r_entry = ms->tree->ma_root;  // root entry
+       void *r_entry = rcu_dereference(ms->tree->ma_root);  // root entry
        struct maple_node *mn;
 
        mas_node_cnt(ms, 1);
@@ -501,8 +868,7 @@ static void mas_update_limits(struct ma_state *ms, unsigned char slot)
        if (mas_is_start(ms))
                return;
 
-       mr64 = &ms->node->mr64;
-
+       mr64 = &mt_to_node(ms->node)->mr64;
        if (slot > 0)
                ms->min = mr64->pivot[slot - 1] + 1;
 
@@ -516,10 +882,10 @@ static void mas_update_limits(struct ma_state *ms, unsigned char slot)
  */
 static int mas_coalesce(struct ma_state *mas)
 {
-       struct maple_node *smn = mt_to_node(mas->node);
-       struct maple_range_64 *src = &smn->mr64;
+       struct maple_node *src_mn = mt_to_node(mas->node);
+       struct maple_range_64 *src = &src_mn->mr64;
        unsigned char s_slot, d_slot = 0;
-       unsigned long last = mas->max;
+       unsigned long last = UINT_MAX;
        struct maple_range_64 *dst = NULL;
        int ret = 0;
 
@@ -554,37 +920,26 @@ static int mas_coalesce(struct ma_state *mas)
                }
        }
 done:
-       if (dst)
+       if (dst) {
                ret = s_slot - d_slot;
-       return ret;
-}
-
-static void ma_adopt_children(struct maple_node *parent)
-{
-
-       struct maple_range_64 *p64 = &parent->mr64;
-       struct maple_node *child;
-       unsigned char slot;
-
-       for (slot = 0; slot < MAPLE_RANGE64_SLOTS; slot++) {
-               if (slot < MAPLE_RANGE64_SLOTS - 1 &&
-                   slot != 0 && p64->pivot[slot] == 0)
-                       break;
-               child = p64->slot[slot];
-               mt_set_parent(child, parent, slot);
+               mas->node = mt_mk_node(mt_to_node(mas->node),
+                                      mt_node_type(mas->node));
+               mt_replace(mas);
        }
+       return ret;
 }
 
 static bool mas_search_slots(struct ma_state *ms, unsigned long val)
 {
        struct maple_range_64 *mr64;
        int i = 0;
+       bool ret = false;
 
        mr64 = &mt_to_node(ms->node)->mr64;
-       for (i = 0; i <= MAPLE_RANGE64_SLOTS - 1; i++) {
+       for (i = 0; i < MAPLE_RANGE64_SLOTS - 1; i++) {
                if (i != 0 && mr64->pivot[i] == 0) {
                        ma_set_slot(ms, MAPLE_NODE_SLOTS);
-                       return false;
+                       return ret;
                }
 
                if (val <= mr64->pivot[i])
@@ -596,36 +951,31 @@ static bool mas_search_slots(struct ma_state *ms, unsigned long val)
                        i++;
        }
 
+       if (mr64->slot[i])
+               ret = true;
+
        ma_set_slot(ms, i);
-       return true;
+       return ret;
 }
-void mas_traverse(struct ma_state *mas)
+
+bool mas_traverse(struct ma_state *mas)
 {
        unsigned char slot = ma_get_slot(mas);
 
-       mas->node = mt_to_node(mas->node)->slot[slot];
        mas_update_limits(mas, slot);
+       if (mt_is_leaf(mas->node))
+               return false;
+       mas->node = mt_to_node(mas->node)->mr64.slot[slot];
+       return true;
 }
 
 bool _mas_walk(struct ma_state *mas)
 {
-       void *p_entry; // Previous entry.
-
        mas->node = mas_start(mas);
-
-       if (mt_is_leaf(mas->node)) {
-               mas_search_slots(mas, mas->index);
-               return true;
-       }
-
        do {
-               p_entry = mas->node;
-               if (!mas_search_slots(mas, mas->index)) {
-                       mas->node = p_entry;
+               if (!mas_search_slots(mas, mas->index))
                        return mt_is_leaf(mas->node);
-               }
-               mas_traverse(mas);
-       } while (!mt_is_leaf(mas->node));
+       } while (mas_traverse(mas));
 
        return true;
 }
@@ -643,58 +993,15 @@ bool ma_reserved(void *entry)
 
        return false;
 }
-/* Private
- * Replace mn with mas->node in the tree
- */
-void mt_may_replace(struct ma_state *mas, void *p_entry, bool leaf)
-{
-       struct maple_node *mn;
-       struct maple_node *pmn = mt_to_node(p_entry);
-
-       /* There is no new node to replace */
-       if (mas->node == p_entry)
-               return;
-
-       mn = mt_to_node(mas->node);
-
-       /* The targeted node was split and is already in the tree */
-       if (mn == mt_parent(pmn))
-               goto in_tree;
-
-       mn->parent = pmn->parent;
-       if (!leaf)
-               ma_adopt_children(mn);
-
-       if (ma_is_root(p_entry)) {
-               mn->parent = (struct maple_node *)
-                             ((unsigned long)mas->tree | MA_ROOT_PARENT);
-               rcu_assign_pointer(mas->tree->ma_root, mt_mk_root(mas->node));
-       } else {
-               struct maple_node *parent = mt_parent(mn->parent);
-               unsigned char slot = mt_parent_slot(mn);
-
-               RCU_INIT_POINTER(parent->slot[slot], mas->node);
-       }
-
-in_tree:
-       mt_free(pmn);
-}
 
 void *ma_insert(struct ma_state *mas, void *entry)
 {
-       void *p_entry; // Previous entry.
        unsigned char slot = MAPLE_NODE_SLOTS;
        struct maple_range_64 *src;
        bool leaf;
 
-
-       if (ma_reserved(entry))
-               mas_set_err(mas, -EINVAL);
-
        mas->node = mas_start(mas);
-
-
-       if (!xa_is_node(mas->tree->ma_root)) {
+       if (!xa_is_node(rcu_dereference(mas->tree->ma_root))) {
                if (mas->last == 0) {
                        if (mas->node != NULL)
                                goto exists;
@@ -715,7 +1022,6 @@ void *ma_insert(struct ma_state *mas, void *entry)
                }
        }
 
-       p_entry = mas->node;
        mas_coalesce(mas);
        if (mas_is_err(mas))
                goto error;
@@ -725,8 +1031,6 @@ void *ma_insert(struct ma_state *mas, void *entry)
        if (mas_is_err(mas))
                goto error;
 
-       /* Replace the node in the tree, if necessary. */
-       mt_may_replace(mas, p_entry, leaf);
        return NULL;
 
 error:
@@ -750,12 +1054,12 @@ void *mas_walk(struct ma_state *mas)
        unsigned char slot = MAPLE_NODE_SLOTS;
        bool leaf = false;
 
-       if (mas->tree->ma_root == NULL)
+       if (rcu_dereference(mas->tree->ma_root) == NULL)
                return NULL;
 
        if (!xa_is_node(mas->tree->ma_root)) {
                if (mas->last == 0)
-                       return mas->tree->ma_root;
+                       return rcu_dereference(mas->tree->ma_root);
                return NULL;
        }
 
@@ -769,7 +1073,7 @@ void *mas_walk(struct ma_state *mas)
        if (leaf == true && slot != MAPLE_NODE_SLOTS) {
                struct maple_range_64 mr = mt_to_node(mas->node)->mr64;
 
-               entry = mr.slot[ma_get_slot(mas)];
+               entry = mr.slot[slot];
        }
        ma_set_slot(mas, 0);
        return entry;
@@ -780,12 +1084,14 @@ void *mas_walk(struct ma_state *mas)
  */
 int ma_erase(struct ma_state *mas)
 {
-       bool leaf = _mas_walk(mas);
-       int slot = ma_get_slot(mas);
-       struct maple_range_64 *mr64 = &mt_to_node(mas->node)->mr64;
+       struct maple_range_64 *mr64;
        unsigned long piv_val;
        int cnt = -EINVAL;
-       void *p_entry; // Previous entry.
+       int slot;
+
+       _mas_walk(mas);
+       slot = ma_get_slot(mas);
+       mr64 = &mt_to_node(mas->node)->mr64;
 
        if (slot == MAPLE_NODE_SLOTS)
                return cnt;
@@ -807,29 +1113,28 @@ int ma_erase(struct ma_state *mas)
                mr64->pivot[slot] = piv_val;
                cnt++;
        }
-       p_entry = mas->node;
+
        mas_coalesce(mas);
        if (mas_is_err(mas))
                goto error;
-
-       mt_may_replace(mas, p_entry, leaf);
-
 error:
        return cnt;
 }
 
-void ma_destroy_walk(struct ma_state *mas)
+void ma_destroy_walk(struct maple_node *enc_mn)
 {
-       struct maple_node *mn = mas->node;
-       unsigned int type = mt_node_type(mas->node);
+       struct maple_node *mn = mt_to_node(enc_mn);
+       unsigned int type = mt_node_type(enc_mn);
        int i;
 
        switch (type) {
        case maple_range_64:
                for (i = 0; i < MAPLE_RANGE64_SLOTS; i++) {
-                       if (i > 0 && mn->mr64.pivot[i] == 0)
+                       if (i > 0 && i < MAPLE_RANGE64_SLOTS - 1 &&
+                           mn->mr64.pivot[i] == 0)
                                break;
-                       ma_destroy_walk(mn->mr64.slot[i]);
+                       if (rcu_dereference(mn->mr64.slot[i]))
+                               ma_destroy_walk(rcu_dereference(mn->mr64.slot[i]));
                }
                break;
        case maple_leaf_64:
@@ -850,7 +1155,7 @@ void mtree_init(struct maple_tree *mt)
 {
        spin_lock_init(&mt->ma_lock);
        mt->ma_flags = 0;
-       mt->ma_root = NULL;
+       rcu_assign_pointer(mt->ma_root, NULL);
 }
 
 EXPORT_SYMBOL(mtree_init);
@@ -858,9 +1163,9 @@ EXPORT_SYMBOL(mtree_init);
 void *mtree_load(struct maple_tree *mt, unsigned long index)
 {
        void *entry;
-       MA_STATE(ms, mt, index, index);
+       MA_STATE(mas, mt, index, index);
        rcu_read_lock();
-       entry = mas_walk(&ms);
+       entry = mas_walk(&mas);
        rcu_read_unlock();
        return entry;
 }
@@ -872,7 +1177,7 @@ int mtree_insert_range(struct maple_tree *mt, unsigned long first,
 
        MA_STATE(ms, mt, first, last);
 
-       if (WARN_ON_ONCE(xa_is_internal(entry)))
+       if (WARN_ON_ONCE(ma_reserved(entry)))
                return -EINVAL;
 
        if (first > last)
@@ -911,13 +1216,13 @@ int mtree_erase(struct maple_tree *mt, unsigned long index)
 
 void mtree_destroy(struct maple_tree *mt)
 {
-       MA_STATE(ms, mt, 0, 0);
        mtree_lock(mt);
-       if (xa_is_node(mt->ma_root)) {
-               ms.node = mt_to_node(mt->ma_root);
-               ma_destroy_walk(&ms);
+       struct maple_node *destroyed = mt->ma_root;
+       rcu_assign_pointer(mt->ma_root, NULL);
+       if (xa_is_node(destroyed)) {
+               ma_destroy_walk(mt_safe_root(destroyed));
        }
-       mt->ma_root = NULL;
+       mt->ma_flags = 0;
        mtree_unlock(mt);
 }
 EXPORT_SYMBOL(mtree_destroy);
index 4da1e1d361802be6d3ddcb3fabf36126ed616c97..73af106a9e4f29d8ce00e1560918da5ebc198d5c 100644 (file)
@@ -219,10 +219,10 @@ static noinline void check_double_insert_leaf(struct maple_tree *mt)
        MT_BUG_ON(mt, !mtree_empty(mt));
 
        i = huge;
-       while (i > 0x80) {
-               check_insert(mt, i, xa_mk_value(i));
+       while (i > 4096) {
+               check_insert(mt, i, i);
                for (j = huge; j >= i; j /= 2) {
-                       check_load(mt, j, xa_mk_value(j));
+                       check_load(mt, j, j);
                        check_load(mt, j+1, NULL);
                }
                i /= 2;
@@ -243,8 +243,9 @@ static int maple_tree_seed(void)
        pr_info("\nTEST STARTING\n\n");
 
        mtree_init(&tree);
-       //check_new_node(&tree);
-       //check_double_insert_leaf(&tree);
+       check_new_node(&tree);
+       check_double_insert_leaf(&tree);
+
        check_load(&tree, set[0], NULL);       // See if 15 -> NULL
 
        check_insert(&tree, set[9], &tree);     // Insert 0
@@ -325,7 +326,7 @@ static int maple_tree_seed(void)
        mt_set_non_kernel(1);
        check_erase(&tree, set[1]);
        check_load(&tree, set[1], NULL);
-       return 0;
+       check_insert(&tree, set[1], &tree);
        check_insert(&tree, set[4], ptr); // 1000 < Should split.
        check_load(&tree, set[0], ptr);
        check_load(&tree, set[1], &tree);