From: Matthew Wilcox Date: Wed, 19 Dec 2018 19:40:16 +0000 (-0500) Subject: maple_tree: Add header file X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=e55840d7da9d85dbe8d6447647ea206cebdcd8ba;p=users%2Fjedix%2Flinux-maple.git maple_tree: Add header file Signed-off-by: Matthew Wilcox --- diff --git a/include/linux/maple_tree.h b/include/linux/maple_tree.h new file mode 100644 index 000000000000..04362554799d --- /dev/null +++ b/include/linux/maple_tree.h @@ -0,0 +1,204 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +#ifndef _LINUX_MAPLE_TREE_H +#define _LINUX_MAPLE_TREE_H +/* + * Maple Tree - An RCU-safe adaptive tree for storing ranges + * Copyright (c) 2018 Oracle + * Authors: Liam R. Howlett + * Matthew Wilcox + */ + +#include +#include +#include +#include +#include + +/* + * Allocated nodes are mutable until they have been inserted into the tree, + * at which time they cannot change their type until they have been removed + * from the tree and an RCU grace period has passed. + * + * Removed nodes have their ->parent set to point to themselves. RCU readers + * check ->parent before relying on the value that they loaded from the + * slots array. This lets us reuse the slots array for the RCU head. + * + * Nodes in the tree point to their parent unless bit 0 is set. + */ +#ifdef CONFIG_64BIT +#define MAPLE_NODE_SLOTS 15 /* 128 bytes including ->parent */ +#define MAPLE_RANGE64_SLOTS 8 /* 128 bytes */ +#define MAPLE_RANGE32_SLOTS 10 /* 124 bytes */ +#define MAPLE_RANGE16_SLOTS 12 /* 126 bytes */ +#define MAPLE_SPARSE64_SLOTS 7 /* 120 bytes */ +#define MAPLE_SPARSE32_SLOTS 10 /* 128 bytes */ +#define MAPLE_SPARSE21_SLOTS 11 /* 128 bytes */ +#define MAPLE_SPARSE16_SLOTS 12 /* 128 bytes */ +#define MAPLE_SPARSE9_SLOTS 13 /* 127 bytes */ +#define MAPLE_SPARSE6_SLOTS 14 /* 128 bytes */ +#else +/* Need to do corresponding calculations for 32-bit kernels */ +#endif + +/* + * We can be more cache-efficient if we interleave pivots and slots. + * Code will be more complex, though. + */ +struct maple_range_64 { + struct maple_node *parent; + void __rcu *slot[MAPLE_RANGE64_SLOTS]; + u64 pivot[MAPLE_RANGE64_SLOTS - 1]; +}; + +struct maple_range_32 { + struct maple_node *parent; + void __rcu *slot[MAPLE_RANGE32_SLOTS]; + u32 pivot[MAPLE_RANGE32_SLOTS - 1]; +}; + +struct maple_range_16 { + struct maple_node *parent; + void __rcu *slot[MAPLE_RANGE16_SLOTS]; + u16 pivot[MAPLE_RANGE16_SLOTS - 1]; +}; + +struct maple_sparse_64 { + struct maple_node *parent; + void __rcu *slot[MAPLE_SPARSE64_SLOTS]; + u64 pivot[MAPLE_SPARSE64_SLOTS]; +}; + +struct maple_sparse_32 { + struct maple_node *parent; + void __rcu *slot[MAPLE_SPARSE32_SLOTS]; + u32 pivot[MAPLE_SPARSE32_SLOTS]; +}; + +struct maple_sparse_21 { + struct maple_node *parent; + void __rcu *slot[MAPLE_SPARSE21_SLOTS]; + u64 pivot[(MAPLE_SPARSE21_SLOTS + 2) / 3]; +}; + +struct maple_sparse_16 { + struct maple_node *parent; + void __rcu *slot[MAPLE_SPARSE16_SLOTS]; + u16 pivot[MAPLE_SPARSE16_SLOTS]; +}; + +struct maple_sparse_9 { + struct maple_node *parent; + void __rcu *slot[MAPLE_SPARSE9_SLOTS]; + u64 pivot[(MAPLE_SPARSE9_SLOTS + 6) / 7]; +}; + +struct maple_sparse_6 { + struct maple_node *parent; + void __rcu *slot[MAPLE_SPARSE6_SLOTS]; + u64 pivot; /* Use a bitmap for pivots */ +}; + +struct maple_node { + union { + struct { + struct maple_node *parent; + void __rcu *slot[MAPLE_NODE_SLOTS]; + }; + struct maple_range_64 mr64; + struct maple_range_32 mr32; + struct maple_range_16 mr16; + struct maple_sparse_64 ms64; + struct maple_sparse_32 ms32; + struct maple_sparse_21 ms21; + struct maple_sparse_16 ms16; + struct maple_sparse_9 ms9; + struct maple_sparse_6 ms6; + }; +}; + +struct maple_tree { + spinlock_t ma_lock; + unsigned int ma_flags; + void __rcu * ma_root; +}; + +#define MTREE_INIT(name, flags) { \ + .ma_lock = __SPIN_LOCK_UNLOCKED(name.ma_lock), \ + .ma_flags = flags, \ + .ma_root = NULL, \ +} + +#define DEFINE_MTREE(name) \ + struct maple_tree name = MTREE_INIT(name, 0) + +#define mtree_lock(mt) spin_lock(&mt->lock); +#define mtree_unlock(mt) spin_unlock(&mt->lock); + +void mtree_init(struct maple_tree *); +void *mtree_load(struct maple_tree *, unsigned long index); +int mtree_insert(struct maple_tree *, unsigned long index, void *entry, gfp_t); +int mtree_insert_range(struct maple_tree *, unsigned long first, + unsigned long last, void *entry, gfp_t); +int mtree_erase(struct maple_tree *, unsigned long index); + +/** + * mtree_empty() - Determine if a tree has any present entries. + * @mt: Maple Tree. + * + * Context: Any context. + * Return: %true if the tree contains only NULL pointers. + */ +static inline bool mtree_empty(const struct maple_tree *mt) +{ + return mt->ma_root == NULL; +} + +/* Advanced API */ + +struct ma_state { + struct maple_tree *tree; /* The tree we're operating in */ + unsigned long index; /* The index we're operating on */ + unsigned long last; /* The last index we're operating on */ + struct maple_node *node; /* The node containing this entry */ + unsigned long min; /* The minimum index of this node */ + unsigned long max; /* The maximum index of this node */ + struct maple_node *alloc; /* Allocated nodes for this operation */ +}; + +/* + * Special values for ma_state.node. + * MAS_START means we have not searched the tree. + * MAS_ROOT means we have searched the tree and the entry we found lives + * in the root of the tree (ie it has index 0, length 1 and is the only + * entry in the tree). + * MAS_NONE means we have searched the tree and there is no node in the + * tree for this entry. For example, we searched for index 1 in an empty + * tree. Or we have a tree which points to a full leaf node and we + * searched for an entry which is larger than can be contained in that + * leaf node. + * MA_ERROR represents an errno. After dropping the lock and attempting + * to resolve the error, the walk would have to be restarted from the + * top of the tree as the tree may have been modified. + */ +#define MAS_START ((struct maple_node *)1UL) +#define MAS_ROOT ((struct maple_node *)5UL) +#define MAS_NONE ((struct maple_node *)9UL) +#define MA_ERROR(err) ((struct maple_node *)(((unsigned long)err << 2) | 2UL)) + +#define MA_STATE(name, tree, first, last) \ + struct ma_state name = { \ + .tree = tree, \ + .index = first, \ + .last = last, \ + .node = MAS_START, \ + .min = 0, \ + .max = ULONG_MAX, \ + } + +void *mas_walk(struct ma_state *); +void *mas_store(struct ma_state *, void *entry); +void *mas_find(struct ma_state *, unsigned long max); + +bool mas_nomem(struct ma_state *, gfp_t); +void mas_pause(struct ma_state *); +#endif diff --git a/lib/Makefile b/lib/Makefile index ce45af50983a..df9c73b60c8d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -32,7 +32,8 @@ KCSAN_SANITIZE_random32.o := n lib-y := ctype.o string.o vsprintf.o cmdline.o \ rbtree.o radix-tree.o timerqueue.o xarray.o \ - idr.o extable.o sha1.o irq_regs.o argv_split.o \ + maple_tree.o idr.o extable.o \ + sha1.o irq_regs.o argv_split.o \ flex_proportions.o ratelimit.o show_mem.o \ is_single_threaded.o plist.o decompress.o kobject_uevent.o \ earlycpio.o seq_buf.o siphash.o dec_and_lock.o \ diff --git a/lib/maple_tree.c b/lib/maple_tree.c new file mode 100644 index 000000000000..5afbb2cca6e7 --- /dev/null +++ b/lib/maple_tree.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Maple Tree implementation + * Copyright (c) 2018 Oracle Corporation + * Authors: Liam R. Howlett + * Matthew Wilcox + */ + +#include