]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
maple_tree: Add header file
authorMatthew Wilcox <willy@infradead.org>
Wed, 19 Dec 2018 19:40:16 +0000 (14:40 -0500)
committerLiam R. Howlett <Liam.Howlett@Oracle.com>
Fri, 30 Oct 2020 18:54:58 +0000 (14:54 -0400)
Signed-off-by: Matthew Wilcox <willy@infradead.org>
include/linux/maple_tree.h [new file with mode: 0644]
lib/Makefile
lib/maple_tree.c [new file with mode: 0644]

diff --git a/include/linux/maple_tree.h b/include/linux/maple_tree.h
new file mode 100644 (file)
index 0000000..0436255
--- /dev/null
@@ -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 <Liam.Howlett@Oracle.com>
+ *         Matthew Wilcox <willy@infradead.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/rcupdate.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/xarray.h>
+
+/*
+ * 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
index ce45af50983a2a5e35823dbd1e632aa425ab3560..df9c73b60c8d4d1eb24838add3e4acb4253ffe7f 100644 (file)
@@ -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 (file)
index 0000000..5afbb2c
--- /dev/null
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Maple Tree implementation
+ * Copyright (c) 2018 Oracle Corporation
+ * Authors: Liam R. Howlett <Liam.Howlett@Oracle.com>
+ *         Matthew Wilcox <willy@infradead.org>
+ */
+
+#include <linux/maple_tree.h>