[maple_leaf_16] = (1UL << 16) - 1,
[maple_leaf_32] = UINT_MAX,
[maple_leaf_64] = ULONG_MAX,
+ [maple_aleaf_64] = ULONG_MAX,
[maple_range_16] = (1UL << 16) - 1,
[maple_range_32] = UINT_MAX,
[maple_range_64] = ULONG_MAX,
+ [maple_arange_64] = ULONG_MAX,
};
#define mt_node_max(x) mt_max[mt_node_type(x)]
[maple_leaf_16] = MAPLE_RANGE16_SLOTS,
[maple_leaf_32] = MAPLE_RANGE32_SLOTS,
[maple_leaf_64] = MAPLE_RANGE64_SLOTS,
+ [maple_aleaf_64] = MAPLE_ARANGE64_SLOTS,
[maple_range_16] = MAPLE_RANGE16_SLOTS,
[maple_range_32] = MAPLE_RANGE32_SLOTS,
[maple_range_64] = MAPLE_RANGE64_SLOTS,
+ [maple_arange_64] = MAPLE_ARANGE64_SLOTS,
};
#define mt_slot_count(x) mt_slots[mt_node_type(x)]
unsigned char mt_pivots[] = {
[maple_leaf_16] = MAPLE_RANGE16_SLOTS - 1,
[maple_leaf_32] = MAPLE_RANGE32_SLOTS - 1,
[maple_leaf_64] = MAPLE_RANGE64_SLOTS - 1,
+ [maple_aleaf_64] = MAPLE_ARANGE64_SLOTS - 1,
[maple_range_16] = MAPLE_RANGE16_SLOTS - 1,
[maple_range_32] = MAPLE_RANGE32_SLOTS - 1,
[maple_range_64] = MAPLE_RANGE64_SLOTS - 1,
+ [maple_arange_64] = MAPLE_ARANGE64_SLOTS - 1,
};
#define mt_pivot_count(x) mt_pivots[mt_node_type(x)]
// Functions
return false;
}
+static inline bool mt_is_alloc(struct maple_tree *mt)
+{
+ return (mt->ma_flags & MAPLE_ALLOC_RANGE);
+}
+
static inline unsigned int mt_parent_shift(unsigned long parent)
{
if (!(parent & 2))
return 3;
}
-static inline enum maple_type mt_parent_enum(struct maple_node *node)
+static inline enum maple_type mt_parent_range_enum(unsigned long parent)
{
- unsigned long parent = (unsigned long) mt_to_node(node)->parent;
- unsigned long slot_shift = mt_parent_shift(parent);
-
- parent &= (1 << slot_shift ) - 1;
switch (parent) {
case 6:
return maple_range_64;
return maple_dense;
}
+static inline enum maple_type mt_parent_alloc_enum(unsigned long parent)
+{
+ switch (parent) {
+ case 6:
+ return maple_arange_64;
+ }
+ return maple_dense;
+}
+
+static inline enum maple_type mt_parent_enum(struct ma_state *mas,
+ struct maple_node *node)
+{
+ unsigned long parent = (unsigned long) mt_to_node(node)->parent;
+ unsigned long slot_shift = mt_parent_shift(parent);
+
+ parent &= (1 << slot_shift ) - 1;
+ if (mt_is_alloc(mas->tree))
+ return mt_parent_alloc_enum(parent);
+ return mt_parent_range_enum(parent);
+}
+
/* Private
*
* Type is encoded in the node->parent
* bit 0: 1 = root, 0 otherwise
* bit 1: 0 = range 16, 1 otherwise
- * bit 2: 0 = range 32, 1 = range 64 | lowest bit of range_16's slot.
+ * bit 2: 0 = range 32, 1 = [a]range 64 | lowest bit of range_16's slot.
*
* Slot number is encoded in the node->parent
* range_16, slot number is encoded in bits 2-6
* range_32, slot number is encoded in bits 3-6
- * range_64, slot number is encoded in bits 3-6
+ * [a]range_64, slot number is encoded in bits 3-6
*/
static inline void mt_set_parent(struct maple_node *node,
struct maple_node *parent, unsigned char slot)
switch (mt_node_type(parent)) {
case maple_range_64:
+ case maple_arange_64:
type |= 4;
/* fallthrough */
case maple_range_32:
unsigned char slot, enum maple_type type)
{
switch (type) {
+ case maple_arange_64:
+ case maple_aleaf_64:
+ return mt_to_node(mn)->ma64.pivot[slot];
case maple_range_64:
case maple_leaf_64:
return mt_to_node(mn)->mr64.pivot[slot];
case maple_leaf_64:
(&mt_to_node(mn)->mr64)->pivot[slot] = val;
break;
+ case maple_arange_64:
+ case maple_aleaf_64:
+ (&mt_to_node(mn)->ma64)->pivot[slot] = val;
case maple_dense:
break;
case maple_sparse_6:
- mt_to_node(mn)->ms6.pivot = val;
+ (&mt_to_node(mn)->ms6)->pivot = val;
break;
case maple_sparse_9:
- mt_to_node(mn)->ms9.pivot[slot] = val;
+ (&mt_to_node(mn)->ms9)->pivot[slot] = val;
break;
case maple_sparse_16:
- mt_to_node(mn)->ms16.pivot[slot] = val;
+ (&mt_to_node(mn)->ms16)->pivot[slot] = val;
break;
case maple_sparse_21:
- mt_to_node(mn)->ms21.pivot[slot] = val;
+ (&mt_to_node(mn)->ms21)->pivot[slot] = val;
break;
case maple_sparse_32:
- mt_to_node(mn)->ms32.pivot[slot] = val;
+ (&mt_to_node(mn)->ms32)->pivot[slot] = val;
break;
case maple_sparse_64:
- mt_to_node(mn)->ms64.pivot[slot] = val;
+ (&mt_to_node(mn)->ms64)->pivot[slot] = val;
break;
case maple_range_16:
case maple_leaf_16:
- mt_to_node(mn)->mr16.pivot[slot] = val;
+ (&mt_to_node(mn)->mr16)->pivot[slot] = val;
break;
case maple_range_32:
case maple_leaf_32:
- mt_to_node(mn)->mr32.pivot[slot] = val;
+ (&mt_to_node(mn)->mr32)->pivot[slot] = val;
break;
}
return;
default:
case maple_dense:
return rcu_dereference(mt_to_node(mn)->slot[slot]);
+ case maple_arange_64:
+ case maple_aleaf_64:
+ return rcu_dereference(mt_to_node(mn)->ma64.slot[slot]);
case maple_sparse_6:
return rcu_dereference(mt_to_node(mn)->ms6.slot[slot]);
case maple_sparse_9:
case maple_leaf_64:
RCU_INIT_POINTER(mt_to_node(mn)->mr64.slot[slot], val);
break;
+ case maple_arange_64:
+ case maple_aleaf_64:
+ RCU_INIT_POINTER(mt_to_node(mn)->ma64.slot[slot], val);
+ break;
}
}
static inline void ma_cp_rcu_slot(struct maple_node *dst,
case maple_dense:
rcu_assign_pointer(mt_to_node(mn)->slot[slot], val);
break;
+ case maple_arange_64:
+ case maple_aleaf_64:
+ rcu_assign_pointer(mt_to_node(mn)->ma64.slot[slot], val);
+ break;
case maple_sparse_6:
rcu_assign_pointer(mt_to_node(mn)->ms6.slot[slot], val);
break;
break;
}
}
+
+static inline unsigned long ma_get_gap(const struct maple_node *mn,
+ unsigned char gap, enum maple_type type)
+{
+ switch (type) {
+ case maple_arange_64:
+ return mt_to_node(mn)->ma64.gap[gap];
+ default:
+ return 0;
+ }
+}
+static inline void ma_set_gap(const struct maple_node *mn,
+ unsigned char gap, unsigned long val)
+{
+ enum maple_type type = mt_node_type(mn);
+ switch (type) {
+ default:
+ break;
+ case maple_arange_64:
+ mt_to_node(mn)->ma64.gap[gap] = val;
+ break;
+ }
+}
+static inline void ma_cp_gap(struct maple_node *dst,
+ unsigned char dloc, struct maple_node *src, unsigned long sloc)
+{
+ ma_set_gap(dst, dloc, ma_get_gap(src, sloc, mt_node_type(src)));
+}
+
static inline void mas_update_limits(struct ma_state *ms, unsigned char slot,
enum maple_type type)
{
gparent = mt_parent(parent);
slot = mt_parent_slot(parent);
- mas->node = mt_mk_node(gparent, mt_parent_enum(parent));
+ mas->node = mt_mk_node(gparent, mt_parent_enum(mas, parent));
ma_set_slot(mas, slot);
- mas_update_limits(mas, slot, mt_parent_enum(parent));
+ mas_update_limits(mas, slot, mt_parent_enum(mas, parent));
mas->node = ma_get_rcu_slot(gparent, slot);
return;
}
struct maple_node **left, struct maple_node **right)
{
char i, j;
- unsigned long min = mas->max;
+ unsigned long min = mas->min;
unsigned long max = min;
enum maple_type type = mt_node_type(mas->node);
unsigned long pivot_cnt = mt_pivots[type];
+ unsigned long half = mt_slots[type] / 2;
unsigned char data_end = ma_data_end(mas->node, type);
*left = ma_next_alloc(mas);
}
*right = ma_next_alloc(mas);
- if (i >= 4) {
+ if (i >= half) {
*left = mt_mk_node(*left, maple_dense);
*right = mt_mk_node(*right, type);
return i;
}
} while (j > 0);
- if (data_end - j >= 4) {
+ if (data_end - j >= half) {
*left = mt_mk_node(*left, type);
*right = mt_mk_node(*right, maple_dense);
return j;
*right = mt_mk_node(*right, type);
}
- return i > 2 ? i : 3;
+ return i > 2 ? i : half - 1;
}
-static inline void ma_linear_cp(struct ma_state *mas, struct ma_cp *cp)
+static inline void ma_dense_cp(struct ma_state *mas, struct ma_cp *cp)
{
unsigned char sloc = cp->src_start; // src location
unsigned char pivot_cnt = mt_pivot_count(cp->src);
- unsigned char slot;
- unsigned long min = ma_get_pivot(cp->src, sloc);
+ unsigned long min, piv;
+ void *ptr;
+
+ if (!sloc) {
+ min = mas->min;
+ }
+ else {
+ min = ma_get_pivot(cp->src, sloc - 1) + 1;
+ }
+
+ piv = min;
while (sloc <= cp->src_end) {
- unsigned long piv;
+ unsigned long end;
+ unsigned char slot, end_slot;
+
+ ptr = ma_get_rcu_slot(cp->src, sloc);
if (sloc < pivot_cnt) {
- piv = ma_get_pivot(cp->src, sloc);
- if (sloc != 0 && !piv)
- break;
- slot = piv - min;
+ end = ma_get_pivot(cp->src, sloc);
} else {
- // Last slot.
- slot = mas->max - min;
- if (!ma_get_rcu_slot(cp->src, sloc))
+ if (!ptr)
break;
+ end = mas->max;
+ }
+
+ slot = piv - min;
+ end_slot = end - min;
+ for ( ; slot <= end_slot; slot++) {
+ ma_set_rcu_slot(cp->dst, slot, ptr);
}
- ma_cp_rcu_slot(cp->dst, slot, cp->src, sloc);
+
+ piv = end + 1;
sloc++;
}
}
+
static inline void ma_copy(struct ma_state *mas, struct ma_cp *cp)
{
unsigned char sloc = cp->src_start; // src location
enum maple_type type = mt_node_type(cp->src);
unsigned char pivot_cnt = mt_pivots[type];
- if (cp->dst) {
- if (!mt_pivot_count(cp->dst)) {
- ma_linear_cp(mas, cp);
- return;
- }
- } else {
+ if (!cp->dst) {
/* Allocate a new node */
mas_node_cnt(mas, 1);
cp->dst = mt_mk_node(cp->dst, type);
}
+ if (!mt_pivot_count(cp->dst)) {
+ ma_dense_cp(mas, cp);
+ return;
+ }
+
while (sloc <= cp->src_end &&
- dloc <= cp->dst_end) {
+ dloc <= cp->dst_end) {
if (sloc != 0 && sloc < pivot_cnt &&
- ma_get_pivot(cp->src, sloc) == 0)
+ ma_get_pivot(cp->src, sloc) == 0)
break;
if (dloc < pivot_cnt) {
if (sloc < pivot_cnt)
ma_cp_pivot(cp->dst, dloc, cp->src, sloc);
else if (dloc > 0 &&
- ma_get_pivot(cp->dst, dloc - 1) != mas->max)
+ ma_get_pivot(cp->dst, dloc - 1) != mas->max)
ma_set_pivot(cp->dst, dloc, mas->max);
}
+ if (mt_is_alloc(mas->tree))
+ ma_cp_gap(cp->dst, dloc, cp->src, sloc);
ma_cp_rcu_slot(cp->dst, dloc++, cp->src, sloc++);
}
cp->dst_start = dloc;
{
MA_CP(cp, mas->node, left, 0, split);
- if (!ma_get_rcu_slot(mas->node, split))
- cp.src_end--;
ma_copy(mas, &cp);
cp.src_start = split + 1;
if (ma_is_root(mas->node)) {
prev = mas->tree->ma_root;
} else {
- enum maple_type ptype = mt_parent_enum(mas->node);
+ enum maple_type ptype = mt_parent_enum(mas, mas->node);
parent = mt_parent(mas->node);
slot = mt_parent_slot(mas->node);
prev = ma_get_rcu_slot(mt_mk_node(parent, ptype), slot);
if (ma_is_root(mas->node)) {
old_parent = full;
- ptype = maple_range_64;
+ if(mt_is_alloc(mas->tree))
+ ptype = maple_arange_64;
+ else
+ ptype = maple_range_64;
p_slot = 0;
mas->max = mt_max[ptype];
} else {
if (right) {
// Set up the link to the right in the new parent
- if (mt_node_type(right) == maple_dense)
+ if (mt_node_type(right) == maple_dense) {
pivot = ma_get_pivot(mas->node, split)
+ mt_node_max(right) - 1;
- else if (ma_is_root(full))
+ }
+ else if (ma_is_root(full)) {
pivot = mt_node_max(mas->node);
- else
+ }
+ else {
pivot = ma_get_pivot(old_parent, p_slot);
+ }
ma_link(right, new_parent, p_slot + 1, pivot, ptype);
}
// Free the full node.
if (old_parent != full)
mt_free(mt_to_node(full));
+
return split;
}
+static inline enum maple_type ma_ptype_leaf(struct ma_state *mas) {
+ enum maple_type pt = mt_node_type(mas->node);
+
+ switch (pt) {
+ case maple_arange_64:
+ return maple_aleaf_64;
+ case maple_range_64:
+ default:
+ return maple_leaf_64;
+ }
+}
+/* Private
+ *
+ * When inserting into non-leaf nodes in _ma_insert, a type is needed.
+ *
+ * Try to determine that type here.
+ */
+static inline enum maple_type ma_determine_type(struct ma_state *mas,
+ unsigned long min, unsigned char slot)
+{
+ struct maple_node *sibling;
+ unsigned char sibling_slot = slot;
+ enum maple_type stype, mt = ma_ptype_leaf(mas);;
+
+ if (slot > 0)
+ sibling_slot -= 1;
+ else
+ sibling_slot += 1;
+ sibling = ma_get_rcu_slot(mas->node, sibling_slot);
+ if (!sibling)
+ return mt;
+
+ stype = mt_node_type(sibling);
+ if (mt_max[stype] >= min - mas->index)
+ return stype;
+
+ return mt;
+}
+
/* Private
*
* Insert entry into a node.
p_mn = mas->node;
if (!mt_is_leaf(mas->node)) {
- struct maple_node *leaf, *sibling;
- unsigned char sibling_slot = slot;
- enum maple_type mt = maple_leaf_64;
+ struct maple_node *leaf;
+ enum maple_type mt;
unsigned long o_min = mas->min;
unsigned long o_max = mas->max;
+ if (mt_is_alloc(mas->tree))
+ mt = maple_aleaf_64;
+
mas_node_cnt(mas, 1);
if (mas_is_err(mas))
return 0;
- if (slot > 0)
- sibling_slot -= 1;
- else
- sibling_slot += 1;
-
- sibling = ma_get_rcu_slot(mas->node, sibling_slot);
- if (sibling)
- mt = mt_node_type(sibling);
+ mt = ma_determine_type(mas, min, slot);
leaf = mt_mk_node(ma_next_alloc(mas), mt);
mt_set_parent(leaf, mas->node, slot);
mas->node = leaf;
- mas->min = min;
+ mas->min = mas->index;
mas->max = max;
_ma_insert(mas, entry, 0);
mas->min = o_min;
/* Figure out if this is an append or not.
* Appending does not need to create a new node. */
- if (slot - 1 == o_end) {
+ if (o_end == 0 || slot - 1 == o_end) {
o_end = n_end; /* Appending */
} else {
/* Not appending */
{
void *r_entry = rcu_dereference(ms->tree->ma_root); // root entry
struct maple_node *mn;
+ enum maple_type mt = maple_leaf_64;
mas_node_cnt(ms, 1);
if (mas_is_err(ms))
return;
mn = ma_next_alloc(ms);
- ms->node = mt_mk_node(mn, maple_leaf_64);
+ if (mt_is_alloc(ms->tree))
+ mt = maple_aleaf_64;
+ ms->node = mt_mk_node(mn, mt);
mn->parent = (struct maple_node*)
((unsigned long)ms->tree | MA_ROOT_PARENT);
return entry;
}
+unsigned long mas_walk_next(struct ma_state *mas)
+{
+ return 0;
+}
/* Private
* Find an entry and erase the entire range
*/
case maple_range_16:
case maple_range_32:
case maple_range_64:
+ case maple_arange_64:
for (i = 0; i < slot_cnt; i++) {
if (i > 0 && i < slot_cnt - 1 &&
ma_get_pivot(mn, i) == 0)
sizeof(struct maple_node), sizeof(struct maple_node),
SLAB_PANIC | SLAB_RECLAIM_ACCOUNT, NULL);
}
-void mtree_init(struct maple_tree *mt)
+void mtree_init(struct maple_tree *mt, unsigned int ma_flags)
{
spin_lock_init(&mt->ma_lock);
- mt->ma_flags = 0;
+ mt->ma_flags = ma_flags;
rcu_assign_pointer(mt->ma_root, NULL);
}
return mtree_insert_range(mt, index, index, entry, gfp);
}
EXPORT_SYMBOL(mtree_insert);
+
+int mtree_alloc_range(struct maple_tree *mt, void *startp,
+ void *ptr, unsigned long size, unsigned long min,
+ unsigned long max, gfp_t gfp)
+{
+ int ret = 0;
+
+
+ return ret;
+}
+
+int mtree_next(struct maple_tree *mt, unsigned long index, unsigned long *next)
+{
+ int ret = -ENOENT;
+ MA_STATE(mas, mt, index, index);
+ rcu_read_lock();
+ *next = mas_walk_next(&mas);
+ rcu_read_unlock();
+
+ if (*next)
+ return 0;
+ return ret;
+
+}
int mtree_erase(struct maple_tree *mt, unsigned long index)
{
int ret = -EINVAL;
{
mtree_lock(mt);
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));
first = last + 1;
}
}
+void mt_dump_arange64(void *entry, unsigned long min, unsigned long max,
+ unsigned int depth)
+{
+ struct maple_arange_64 *node = &mt_to_node(entry)->ma64;
+ bool leaf = mt_is_leaf(entry);
+ unsigned long first = min;
+ int i;
+
+ pr_cont(" contents: ");
+ for (i = 0; i < MAPLE_ARANGE64_SLOTS; i++)
+ pr_cont("%lu ", node->gap[i]);
+ pr_cont(" | ");
+ for (i = 0; i < MAPLE_ARANGE64_SLOTS - 1; i++)
+ pr_cont("%p %lu ", node->slot[i], node->pivot[i]);
+ pr_cont("%p\n", node->slot[i]);
+ for (i = 0; i < MAPLE_ARANGE64_SLOTS; i++) {
+ unsigned long last = max;
+
+ if (i < (MAPLE_ARANGE64_SLOTS - 1))
+ last = node->pivot[i];
+ else if (node->slot[i] == NULL)
+ break;
+ if (last == 0 && i > 0)
+ break;
+ if (leaf)
+ mt_dump_entry(node->slot[i], first, last);
+ else if (node->slot[i])
+ mt_dump_node(node->slot[i], first, last, depth + 1);
+
+ if (last == max)
+ break;
+ if (last > max) {
+ pr_err("node %p last (%lu) > max (%lu) at pivot %d!\n", node, last, max, i);
+ break;
+ }
+ first = last + 1;
+ }
+}
void mt_dump_node(void *entry, unsigned long min, unsigned long max,
unsigned int depth)
case maple_range_64:
mt_dump_range64(entry, min, max, depth);
break;
+ case maple_arange_64:
+ case maple_aleaf_64:
+ mt_dump_arange64(entry, min, max, depth);
+ break;
+
default:
pr_cont(" UNKNOWN TYPE\n");
}