From: Liam R. Howlett Date: Mon, 24 Aug 2020 16:22:12 +0000 (-0400) Subject: maple_tree: Add dup function and testing X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=b8c5d64a27f1b5329c6d9e4fa4391531f809c18d;p=users%2Fjedix%2Flinux-maple.git maple_tree: Add dup function and testing Signed-off-by: Liam R. Howlett --- diff --git a/include/linux/maple_tree.h b/include/linux/maple_tree.h index 5d38c1eb5b24..105731e081e3 100644 --- a/include/linux/maple_tree.h +++ b/include/linux/maple_tree.h @@ -222,8 +222,8 @@ struct maple_tree { #define DEFINE_MTREE(name) \ struct maple_tree name = MTREE_INIT(name, 0) -#define mtree_lock(mt) spin_lock((&mt->ma_lock)) -#define mtree_unlock(mt) spin_unlock((&mt->ma_lock)) +#define mtree_lock(mt) spin_lock((&(mt)->ma_lock)) +#define mtree_unlock(mt) spin_unlock((&(mt)->ma_lock)) struct ma_topiary { struct maple_enode *head; @@ -332,6 +332,7 @@ static inline bool mas_is_none(struct ma_state *mas) return mas->node == MAS_NONE; } +void mas_dup_tree(struct ma_state *oldmas, struct ma_state *mas); /* This finds an empty area from the highest address to the lowest. * AKA "Topdown" version, */ diff --git a/lib/maple_tree.c b/lib/maple_tree.c index 6895076e6212..2ad26104f18f 100644 --- a/lib/maple_tree.c +++ b/lib/maple_tree.c @@ -104,7 +104,7 @@ unsigned char mt_min_slots[] = { }; #define mt_min_slot_cnt(x) mt_min_slots[mte_node_type(x)] -#define MAPLE_BIG_NODE_SLOTS (MAPLE_NODE_SLOTS * 2 + 1) +#define MAPLE_BIG_NODE_SLOTS (MAPLE_RANGE64_SLOTS* 2 + 1) struct maple_big_node { struct maple_pnode *parent; @@ -1036,7 +1036,6 @@ static inline struct maple_node *mas_node_cnt(struct ma_state *mas, int count) int allocated = mas_get_alloc_cnt(mas); BUG_ON(count > 127); - if (allocated < count) { mas_set_alloc_req(mas, count - allocated); mas_node_node(mas, GFP_NOWAIT | __GFP_NOWARN); @@ -2935,12 +2934,13 @@ static inline bool __mas_walk(struct ma_state *mas, unsigned long *range_min, next = mas_get_rcu_slot(mas, mas_get_slot(mas)); + if (unlikely(mt_is_empty(next))) + return false; + // Traverse. mas->depth++; mas->max = *range_max; mas->min = *range_min; - if (unlikely(mt_is_empty(next))) - return false; mas->node = next; mas_set_slot(mas, 0); @@ -4288,6 +4288,21 @@ retry: return entry; } +static inline void mas_bfs_preorder(struct ma_state *mas) +{ + + if (mas_is_start(mas)) { + mas_start(mas); + return; + } + + if (mte_is_leaf(mas->node) && mte_is_root(mas->node)) { + mas->node = MAS_NONE; + return; + } + +} +/* mas limits not adjusted */ static inline void mas_dfs_preorder(struct ma_state *mas) { @@ -4330,6 +4345,147 @@ walk_up: return; } +static inline struct maple_enode *mas_dup_node(struct ma_state *oldmas, + struct ma_state *mas) +{ + struct maple_enode *enode= mt_mk_node(ma_mnode_ptr(mas_next_alloc(mas)), + mte_node_type(oldmas->node)); + memcpy(mte_to_node(enode), mas_mn(oldmas), sizeof(struct maple_node)); + return enode; +} +static inline void mas_dup_alloc(struct ma_state *mas, int *node_cnt) +{ + + int alloc_cnt = min(*node_cnt, 127); + /* Allocate nodes for new tree. Maximum will be 16 ** height */ + *node_cnt -= alloc_cnt; + mas_node_cnt(mas, alloc_cnt); + if (mas_is_err(mas)) + return; +} + +static inline void mas_dup_children(struct ma_state *mas, int *node_cnt) +{ + struct maple_node *child; + struct maple_enode *oldchild, *echild; + unsigned char slot, end; + int allocated = mas_get_alloc_cnt(mas); + + end = mas_data_end(mas) + 1; + if (allocated < end) { + mas->span_enode = mas->node; + *node_cnt += allocated; + mas_dup_alloc(mas, node_cnt); + if (mas_is_err(mas)) + return; + mas->span_enode = NULL; + } + + + for(slot = 0; slot < end; slot++) { + oldchild = mas_get_rcu_slot(mas, slot); + if (!oldchild) + return; + + child = mas_next_alloc(mas); + echild = mt_mk_node(child, mte_node_type(oldchild)); + mte_set_rcu_slot(mas->node, slot, echild); + memcpy(child, mte_to_node(oldchild), sizeof(struct maple_node)); + } +} + +static inline bool mas_dup_advance(struct ma_state *oldmas, + struct ma_state *mas) +{ + mas_dfs_preorder(oldmas); + mas_dfs_preorder(mas); + + if (mas_is_none(oldmas)) + return false; + + return true; +} + +static inline void mas_dup_tree_start(struct ma_state *oldmas, + struct ma_state *mas, + int *node_cnt) +{ + if (mas->alloc) + goto allocated; + + // Get first node (root) + if (mas_is_start(oldmas)) // get the root. + mas_dfs_preorder(oldmas); + + *node_cnt = mas_data_end(oldmas) + 1; + *node_cnt *= 1 << (4 * (oldmas->tree->ma_height - 2)); // assume all other levels full. + (*node_cnt)++; + + mas_dup_alloc(mas, node_cnt); + if (mas_is_err(mas)) + return; + +allocated: + + mas->node = mas_dup_node(oldmas, mas); + mas_dup_children(mas, node_cnt); + mas_adopt_children(mas, mas->node); + mte_to_node(mas->node)->parent = ma_parent_ptr( + ((unsigned long)mas->tree | MA_ROOT_PARENT)); + rcu_assign_pointer(mas->tree->ma_root, mte_mk_root(mas->node)); +} +void _mas_dup_tree(struct ma_state *oldmas, struct ma_state *mas, int *node_cnt) +{ + if (!xa_is_node(oldmas->tree->ma_root)) { + mas->tree->ma_root = oldmas->tree->ma_root; + return; + } + + if (mas->span_enode) { + mas->node = mas->span_enode; + mas->span_enode= NULL; + goto retry_dup_children; + } + + if (mas_is_start(mas)) + mas_dup_tree_start(oldmas, mas, node_cnt); + + if (mas_is_err(mas)) + return; + + if (mte_is_leaf(oldmas->node)) + return; + + while(mas_dup_advance(oldmas, mas)) { + if (mte_is_leaf(oldmas->node)) + continue; + +retry_dup_children: + mas_dup_children(mas, node_cnt); + if (mas_is_err(mas)) + return; + + mas_adopt_children(mas, mas->node); + } + mas_nomem(mas, GFP_KERNEL); + +} +void mas_dup_tree(struct ma_state *oldmas, struct ma_state *mas) +{ + int node_cnt = 0; + + if (!oldmas->tree->ma_root) // empty tree. + return; + + mtree_lock(mas->tree); +retry: + _mas_dup_tree(oldmas, mas, &node_cnt); + if (mas_nomem(mas, GFP_KERNEL)) + goto retry; + + mtree_unlock(mas->tree); +} + /* Interface */ void __init maple_tree_init(void) { diff --git a/lib/test_maple_tree.c b/lib/test_maple_tree.c index 86b79f9c019b..327660914d67 100644 --- a/lib/test_maple_tree.c +++ b/lib/test_maple_tree.c @@ -32086,6 +32086,22 @@ static void check_dfs_preorder(struct maple_tree *mt) MT_BUG_ON(mt, count != 72); } +static void check_dup_tree(struct maple_tree *oldmt) +{ + unsigned long i, max = 10000; + + MA_STATE(oldmas, oldmt, 0, 0); + DEFINE_MTREE(mt); + MA_STATE(mas, &mt, 0, 0); + + check_seq(oldmt, max, false); + mas_dup_tree(&oldmas, &mas); + for (i = 0; i <= max; i++) + check_index_load(&mt, i); + + check_load(&mt, max + 1, NULL); + mtree_destroy(&mt); +} static DEFINE_MTREE(tree); static int maple_tree_seed(void) @@ -32104,6 +32120,10 @@ static int maple_tree_seed(void) check_dfs_preorder(&tree); mtree_destroy(&tree); + mtree_init(&tree, 0); + check_dup_tree(&tree); + mtree_destroy(&tree); + /* Test ranges (store and insert) */ mtree_init(&tree, 0); check_ranges(&tree);