From: Liam R. Howlett <Liam.Howlett@oracle.com> Date: Tue, 22 Mar 2022 16:37:31 +0000 (-0400) Subject: maple_tree: Reduce mas_split() memory usage X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=1f2c541a306c89f68f6040bbc5db7af707bf792d;p=users%2Fjedix%2Flinux-maple.git maple_tree: Reduce mas_split() memory usage Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com> --- diff --git a/lib/maple_tree.c b/lib/maple_tree.c index e1743803c851..75f7be445dbb 100644 --- a/lib/maple_tree.c +++ b/lib/maple_tree.c @@ -146,6 +146,18 @@ struct maple_subtree_state { struct maple_big_node *bn; }; +struct maple_split_state { + struct maple_enode *l_node; + struct maple_enode *r_node; + unsigned char offset; + struct ma_state *l; /* New left side of subtree */ + struct ma_state *m; /* New middle of subtree (rare) */ + struct ma_state *r; /* New right side of subtree */ + struct ma_topiary *free; /* nodes to be freed */ + struct ma_topiary *destroy; /* Nodes to be destroyed (walked and freed) */ + struct maple_big_node *bn; +}; + /* Functions */ static inline struct maple_node *mt_alloc_one(gfp_t gfp) { @@ -2650,7 +2662,7 @@ static inline void mab_set_b_end(struct maple_big_node *b_node, } /* - * mas_set_split_parent() - combine_then_separate helper function. Sets the parent + * mte_set_split_parent() - combine_then_separate helper function. Sets the parent * of @mas->node to either @left or @right, depending on @slot and @split * * @mas - the maple state with the node that needs a parent @@ -2659,18 +2671,18 @@ static inline void mab_set_b_end(struct maple_big_node *b_node, * @slot - the slot the mas->node was placed * @split - the split location between @left and @right */ -static inline void mas_set_split_parent(struct ma_state *mas, +static inline void mte_set_split_parent(struct maple_enode *enode, struct maple_enode *left, struct maple_enode *right, unsigned char *slot, unsigned char split) { - if (mas_is_none(mas)) + if (enode == MAS_NONE) return; if ((*slot) <= split) - mte_set_parent(mas->node, left, *slot); + mte_set_parent(enode, left, *slot); else if (right) - mte_set_parent(mas->node, right, (*slot) - split - 1); + mte_set_parent(enode, right, (*slot) - split - 1); (*slot)++; } @@ -2730,13 +2742,13 @@ static inline void mast_set_split_parents(struct maple_subtree_state *mast, slot = mast->l->offset; mte_mid_split_check(&l, &r, right, slot, &split, mid_split); - mas_set_split_parent(mast->l, l, r, &slot, split); + mte_set_split_parent(mast->l->node, l, r, &slot, split); mte_mid_split_check(&l, &r, right, slot, &split, mid_split); - mas_set_split_parent(mast->m, l, r, &slot, split); + mte_set_split_parent(mast->m->node, l, r, &slot, split); mte_mid_split_check(&l, &r, right, slot, &split, mid_split); - mas_set_split_parent(mast->r, l, r, &slot, split); + mte_set_split_parent(mast->r->node, l, r, &slot, split); } /* @@ -3276,107 +3288,102 @@ done: /* * mas_split_final_node() - Split the final node in a subtree operation. - * @mast: the maple subtree state + * @mss: the maple subtree state * @mas: The maple state * @height: The height of the tree in case it's a new root. */ -static inline bool mas_split_final_node(struct maple_subtree_state *mast, +static inline bool mas_split_final_node(struct maple_split_state *mss, struct ma_state *mas, int height) { struct maple_enode *ancestor; if (mte_is_root(mas->node)) { if (mt_is_alloc(mas->tree)) - mast->bn->type = maple_arange_64; + mss->bn->type = maple_arange_64; else - mast->bn->type = maple_range_64; + mss->bn->type = maple_range_64; mas->depth = height; } /* * Only a single node is used here, could be root. * The Big_node data should just fit in a single node. */ - ancestor = mas_new_ma_node(mas, mast->bn); - mte_set_parent(mast->l->node, ancestor, mast->l->offset); - mte_set_parent(mast->r->node, ancestor, mast->r->offset); + ancestor = mas_new_ma_node(mas, mss->bn); + mte_set_parent(mss->l->node, ancestor, mss->l->offset); + mte_set_parent(mss->r->node, ancestor, mss->r->offset); mte_to_node(ancestor)->parent = mas_mn(mas)->parent; - mast->l->node = ancestor; - mab_mas_cp(mast->bn, 0, mt_slots[mast->bn->type] - 1, mast->l, true); - mas->offset = mast->bn->b_end - 1; + mss->l->node = ancestor; + mab_mas_cp(mss->bn, 0, mt_slots[mss->bn->type] - 1, mss->l, true); + mas->offset = mss->bn->b_end - 1; return true; } /* - * mast_fill_bnode() - Copy data into the big node in the subtree state - * @mast: The maple subtree state + * mss_fill_bnode() - Copy data into the big node in the subtree state + * @mss: The maple split state * @mas: the maple state * @skip: The number of entries to skip for new nodes insertion. */ -static inline void mast_fill_bnode(struct maple_subtree_state *mast, - struct ma_state *mas, - unsigned char skip) +static inline void mss_fill_bnode(struct maple_split_state *mss, + struct ma_state *mas, unsigned char skip) { bool cp = true; struct maple_enode *old = mas->node; unsigned char split; - memset(mast->bn->gap, 0, sizeof(unsigned long) * ARRAY_SIZE(mast->bn->gap)); - memset(mast->bn->slot, 0, sizeof(unsigned long) * ARRAY_SIZE(mast->bn->slot)); - memset(mast->bn->pivot, 0, sizeof(unsigned long) * ARRAY_SIZE(mast->bn->pivot)); - mast->bn->b_end = 0; - + memset(mss->bn, 0, sizeof(struct maple_big_node)); if (mte_is_root(mas->node)) { cp = false; } else { mas_ascend(mas); - mat_add(mast->free, old); + mat_add(mss->free, old); mas->offset = mte_parent_slot(mas->node); } - if (cp && mast->l->offset) - mas_mab_cp(mas, 0, mast->l->offset - 1, mast->bn, 0); + if (cp && mss->l->offset) + mas_mab_cp(mas, 0, mss->l->offset - 1, mss->bn, 0); - split = mast->bn->b_end; - mab_set_b_end(mast->bn, mast->l, mast->l->node); - mast->r->offset = mast->bn->b_end; - mab_set_b_end(mast->bn, mast->r, mast->r->node); - if (mast->bn->pivot[mast->bn->b_end - 1] == mas->max) + split = mss->bn->b_end; + mab_set_b_end(mss->bn, mss->l, mss->l->node); + mss->r->offset = mss->bn->b_end; + mab_set_b_end(mss->bn, mss->r, mss->r->node); + if (mss->bn->pivot[mss->bn->b_end - 1] == mas->max) cp = false; if (cp) mas_mab_cp(mas, split + skip, mt_slot_count(mas->node) - 1, - mast->bn, mast->bn->b_end); + mss->bn, mss->bn->b_end); - mast->bn->b_end--; - mast->bn->type = mte_node_type(mas->node); + mss->bn->b_end--; + mss->bn->type = mte_node_type(mas->node); } /* - * mast_split_data() - Split the data in the subtree state big node into regular + * mss_split_data() - Split the data in the subtree state big node into regular * nodes. - * @mast: The maple subtree state + * @mss: The maple split state * @mas: The maple state * @split: The location to split the big node */ -static inline void mast_split_data(struct maple_subtree_state *mast, +static inline void mss_split_data(struct maple_split_state *mss, struct ma_state *mas, unsigned char split) { unsigned char p_slot; - mab_mas_cp(mast->bn, 0, split, mast->l, true); - mte_set_pivot(mast->r->node, 0, mast->r->max); - mab_mas_cp(mast->bn, split + 1, mast->bn->b_end, mast->r, false); - mast->l->offset = mte_parent_slot(mas->node); - mast->l->max = mast->bn->pivot[split]; - mast->r->min = mast->l->max + 1; + mab_mas_cp(mss->bn, 0, split, mss->l, true); + mte_set_pivot(mss->r->node, 0, mss->r->max); + mab_mas_cp(mss->bn, split + 1, mss->bn->b_end, mss->r, false); + mss->l->offset = mte_parent_slot(mas->node); + mss->l->max = mss->bn->pivot[split]; + mss->r->min = mss->l->max + 1; if (mte_is_leaf(mas->node)) return; - p_slot = mast->orig_l->offset; - mas_set_split_parent(mast->orig_l, mast->l->node, mast->r->node, + p_slot = mss->offset; + mte_set_split_parent(mss->l_node, mss->l->node, mss->r->node, &p_slot, split); - mas_set_split_parent(mast->orig_r, mast->l->node, mast->r->node, + mte_set_split_parent(mss->r_node, mss->l->node, mss->r->node, &p_slot, split); } @@ -3393,14 +3400,14 @@ static inline void mast_split_data(struct maple_subtree_state *mast, * Return: True if pushed, false otherwise. */ static inline bool mas_push_data(struct ma_state *mas, int height, - struct maple_subtree_state *mast, bool left) + struct maple_split_state *mss, bool left) { - unsigned char slot_total = mast->bn->b_end; + unsigned char slot_total = mss->bn->b_end; unsigned char end, space, split; MA_STATE(tmp_mas, mas->tree, mas->index, mas->last); tmp_mas = *mas; - tmp_mas.depth = mast->l->depth; + tmp_mas.depth = mss->l->depth; if (left && !mas_prev_sibling(&tmp_mas)) return false; @@ -3411,7 +3418,7 @@ static inline bool mas_push_data(struct ma_state *mas, int height, slot_total += end; space = 2 * mt_slot_count(mas->node) - 2; /* -2 instead of -1 to ensure there isn't a triple split */ - if (ma_is_leaf(mast->bn->type)) + if (ma_is_leaf(mss->bn->type)) space--; if (mas->max == ULONG_MAX) @@ -3420,39 +3427,39 @@ static inline bool mas_push_data(struct ma_state *mas, int height, if (slot_total >= space) return false; - /* Get the data; Fill mast->bn */ - mast->bn->b_end++; + /* Get the data; Fill mss->bn */ + mss->bn->b_end++; if (left) { - mab_shift_right(mast->bn, end + 1); - mas_mab_cp(&tmp_mas, 0, end, mast->bn, 0); - mast->bn->b_end = slot_total + 1; + mab_shift_right(mss->bn, end + 1); + mas_mab_cp(&tmp_mas, 0, end, mss->bn, 0); + mss->bn->b_end = slot_total + 1; } else { - mas_mab_cp(&tmp_mas, 0, end, mast->bn, mast->bn->b_end); + mas_mab_cp(&tmp_mas, 0, end, mss->bn, mss->bn->b_end); } - /* Configure mast for splitting of mast->bn */ - split = mt_slots[mast->bn->type] - 2; + /* Configure mss for splitting of mss->bn */ + split = mt_slots[mss->bn->type] - 2; if (left) { /* Switch mas to prev node */ - mat_add(mast->free, mas->node); + mat_add(mss->free, mas->node); *mas = tmp_mas; - /* Start using mast->l for the left side. */ - tmp_mas.node = mast->l->node; - *mast->l = tmp_mas; + /* Start using mss->l for the left side. */ + tmp_mas.node = mss->l->node; + *mss->l = tmp_mas; } else { - mat_add(mast->free, tmp_mas.node); - tmp_mas.node = mast->r->node; - *mast->r = tmp_mas; + mat_add(mss->free, tmp_mas.node); + tmp_mas.node = mss->r->node; + *mss->r = tmp_mas; split = slot_total - split; } - split = mab_no_null_split(mast->bn, split, mt_slots[mast->bn->type]); + split = mab_no_null_split(mss->bn, split, mt_slots[mss->bn->type]); /* Update parent slot for split calculation. */ if (left) - mast->orig_l->offset += end + 1; + mss->offset += end + 1; - mast_split_data(mast, mas, split); - mast_fill_bnode(mast, mas, 2); - mas_split_final_node(mast, mas, height + 1); + mss_split_data(mss, mas, split); + mss_fill_bnode(mss, mas, 2); + mas_split_final_node(mss, mas, height + 1); return true; } @@ -3465,9 +3472,10 @@ static inline bool mas_push_data(struct ma_state *mas, int height, static int mas_split(struct ma_state *mas, struct maple_big_node *b_node) { - struct maple_subtree_state mast; + struct maple_split_state mss; int height = 0; unsigned char mid_split, split = 0; + unsigned long prev_l_min; /* * Splitting is handled differently from any other B-tree; the Maple @@ -3488,8 +3496,6 @@ static int mas_split(struct ma_state *mas, struct maple_big_node *b_node) */ MA_STATE(l_mas, mas->tree, mas->index, mas->last); MA_STATE(r_mas, mas->tree, mas->index, mas->last); - MA_STATE(prev_l_mas, mas->tree, mas->index, mas->last); - MA_STATE(prev_r_mas, mas->tree, mas->index, mas->last); MA_TOPIARY(mat, mas->tree); trace_ma_op(__func__, mas); @@ -3499,16 +3505,18 @@ static int mas_split(struct ma_state *mas, struct maple_big_node *b_node) if (mas_is_err(mas)) return 0; - mast.l = &l_mas; - mast.r = &r_mas; - mast.orig_l = &prev_l_mas; - mast.orig_r = &prev_r_mas; - mast.free = &mat; - mast.bn = b_node; + mss.l = &l_mas; + mss.r = &r_mas; + mss.l_node = mas->node; + mss.r_node = mas->node; + mss.offset = mas->offset; + prev_l_min = mas->min; + mss.free = &mat; + mss.bn = b_node; while (height++ <= mas->depth) { if (mt_slots[b_node->type] > b_node->b_end) { - mas_split_final_node(&mast, mas, height); + mas_split_final_node(&mss, mas, height); break; } @@ -3523,29 +3531,30 @@ static int mas_split(struct ma_state *mas, struct maple_big_node *b_node) * is a significant savings. */ /* Try to push left. */ - if (mas_push_data(mas, height, &mast, true)) + if (mas_push_data(mas, height, &mss, true)) break; /* Try to push right. */ - if (mas_push_data(mas, height, &mast, false)) + if (mas_push_data(mas, height, &mss, false)) break; - split = mab_calc_split(mas, b_node, &mid_split, prev_l_mas.min); - mast_split_data(&mast, mas, split); + split = mab_calc_split(mas, b_node, &mid_split, prev_l_min); + mss_split_data(&mss, mas, split); /* * Usually correct, mab_mas_cp in the above call overwrites * r->max. */ - mast.r->max = mas->max; - mast_fill_bnode(&mast, mas, 1); - prev_l_mas = *mast.l; - prev_r_mas = *mast.r; + mss.r->max = mas->max; + mss_fill_bnode(&mss, mas, 1); + mss.l_node = mss.l->node; + mss.r_node = mss.r->node; + mss.offset = mss.l->offset; } /* Set the original node as dead */ - mat_add(mast.free, mas->node); + mat_add(mss.free, mas->node); mas->node = l_mas.node; - mas_wmb_replace(mas, mast.free, NULL); + mas_wmb_replace(mas, mss.free, NULL); mtree_range_walk(mas); return 1; }