Commit 067311d3 authored by Liam R. Howlett's avatar Liam R. Howlett Committed by Andrew Morton

maple_tree: separate ma_state node from status

The maple tree node is overloaded to keep status as well as the active
node.  This, unfortunately, results in a re-walk on underflow or overflow.
Since the maple state has room, the status can be placed in its own enum
in the structure.  Once an underflow/overflow is detected, certain modes
can restore the status to active and others may need to re-walk just that
one node to see the entry.

The status being an enum has the benefit of detecting unhandled status in
switch statements.

[Liam.Howlett@oracle.com: fix comments about MAS_*]
  Link: https://lkml.kernel.org/r/20231106154124.614247-1-Liam.Howlett@oracle.com
[Liam.Howlett@oracle.com: update forking to separate maple state and node]
  Link: https://lkml.kernel.org/r/20231106154551.615042-1-Liam.Howlett@oracle.com
[Liam.Howlett@oracle.com: fix mas_prev() state separation code]
  Link: https://lkml.kernel.org/r/20231207193319.4025462-1-Liam.Howlett@oracle.com
Link: https://lkml.kernel.org/r/20231101171629.3612299-9-Liam.Howlett@oracle.comSigned-off-by: default avatarLiam R. Howlett <Liam.Howlett@oracle.com>
Cc: Peng Zhang <zhangpeng.00@bytedance.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 271f61a8
...@@ -349,6 +349,36 @@ static inline bool mtree_empty(const struct maple_tree *mt) ...@@ -349,6 +349,36 @@ static inline bool mtree_empty(const struct maple_tree *mt)
/* Advanced API */ /* Advanced API */
/*
* Maple State Status
* ma_active means the maple state is pointing to a node and offset and can
* continue operating on the tree.
* ma_start means we have not searched the tree.
* ma_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).
* ma_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_pause means the data within the maple state may be stale, restart the
* operation
* ma_overflow means the search has reached the upper limit of the search
* ma_underflow means the search has reached the lower limit of the search
* ma_error means there was an error, check the node for the error number.
*/
enum maple_status {
ma_active,
ma_start,
ma_root,
ma_none,
ma_pause,
ma_overflow,
ma_underflow,
ma_error,
};
/* /*
* The maple state is defined in the struct ma_state and is used to keep track * The maple state is defined in the struct ma_state and is used to keep track
* of information during operations, and even between operations when using the * of information during operations, and even between operations when using the
...@@ -381,6 +411,13 @@ static inline bool mtree_empty(const struct maple_tree *mt) ...@@ -381,6 +411,13 @@ static inline bool mtree_empty(const struct maple_tree *mt)
* When returning a value the maple state index and last respectively contain * When returning a value the maple state index and last respectively contain
* the start and end of the range for the entry. Ranges are inclusive in the * the start and end of the range for the entry. Ranges are inclusive in the
* Maple Tree. * Maple Tree.
*
* The status of the state is used to determine how the next action should treat
* the state. For instance, if the status is ma_start then the next action
* should start at the root of the tree and walk down. If the status is
* ma_pause then the node may be stale data and should be discarded. If the
* status is ma_overflow, then the last action hit the upper limit.
*
*/ */
struct ma_state { struct ma_state {
struct maple_tree *tree; /* The tree we're operating in */ struct maple_tree *tree; /* The tree we're operating in */
...@@ -390,6 +427,7 @@ struct ma_state { ...@@ -390,6 +427,7 @@ struct ma_state {
unsigned long min; /* The minimum index of this node - implied pivot min */ unsigned long min; /* The minimum index of this node - implied pivot min */
unsigned long max; /* The maximum index of this node - implied pivot max */ unsigned long max; /* The maximum index of this node - implied pivot max */
struct maple_alloc *alloc; /* Allocated nodes for this operation */ struct maple_alloc *alloc; /* Allocated nodes for this operation */
enum maple_status status; /* The status of the state (active, start, none, etc) */
unsigned char depth; /* depth of tree descent during write */ unsigned char depth; /* depth of tree descent during write */
unsigned char offset; unsigned char offset;
unsigned char mas_flags; unsigned char mas_flags;
...@@ -416,28 +454,12 @@ struct ma_wr_state { ...@@ -416,28 +454,12 @@ struct ma_wr_state {
spin_lock_nested(&((mas)->tree->ma_lock), subclass) spin_lock_nested(&((mas)->tree->ma_lock), subclass)
#define mas_unlock(mas) spin_unlock(&((mas)->tree->ma_lock)) #define mas_unlock(mas) spin_unlock(&((mas)->tree->ma_lock))
/* /*
* Special values for ma_state.node. * 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 * MA_ERROR represents an errno. After dropping the lock and attempting
* to resolve the error, the walk would have to be restarted from the * to resolve the error, the walk would have to be restarted from the
* top of the tree as the tree may have been modified. * top of the tree as the tree may have been modified.
*/ */
#define MAS_START ((struct maple_enode *)1UL)
#define MAS_ROOT ((struct maple_enode *)5UL)
#define MAS_NONE ((struct maple_enode *)9UL)
#define MAS_PAUSE ((struct maple_enode *)17UL)
#define MAS_OVERFLOW ((struct maple_enode *)33UL)
#define MAS_UNDERFLOW ((struct maple_enode *)65UL)
#define MA_ERROR(err) \ #define MA_ERROR(err) \
((struct maple_enode *)(((unsigned long)err << 2) | 2UL)) ((struct maple_enode *)(((unsigned long)err << 2) | 2UL))
...@@ -446,7 +468,8 @@ struct ma_wr_state { ...@@ -446,7 +468,8 @@ struct ma_wr_state {
.tree = mt, \ .tree = mt, \
.index = first, \ .index = first, \
.last = end, \ .last = end, \
.node = MAS_START, \ .node = NULL, \
.status = ma_start, \
.min = 0, \ .min = 0, \
.max = ULONG_MAX, \ .max = ULONG_MAX, \
.alloc = NULL, \ .alloc = NULL, \
...@@ -477,7 +500,6 @@ void *mas_find_range(struct ma_state *mas, unsigned long max); ...@@ -477,7 +500,6 @@ void *mas_find_range(struct ma_state *mas, unsigned long max);
void *mas_find_rev(struct ma_state *mas, unsigned long min); void *mas_find_rev(struct ma_state *mas, unsigned long min);
void *mas_find_range_rev(struct ma_state *mas, unsigned long max); void *mas_find_range_rev(struct ma_state *mas, unsigned long max);
int mas_preallocate(struct ma_state *mas, void *entry, gfp_t gfp); int mas_preallocate(struct ma_state *mas, void *entry, gfp_t gfp);
bool mas_is_err(struct ma_state *mas);
bool mas_nomem(struct ma_state *mas, gfp_t gfp); bool mas_nomem(struct ma_state *mas, gfp_t gfp);
void mas_pause(struct ma_state *mas); void mas_pause(struct ma_state *mas);
...@@ -506,28 +528,18 @@ static inline void mas_init(struct ma_state *mas, struct maple_tree *tree, ...@@ -506,28 +528,18 @@ static inline void mas_init(struct ma_state *mas, struct maple_tree *tree,
mas->tree = tree; mas->tree = tree;
mas->index = mas->last = addr; mas->index = mas->last = addr;
mas->max = ULONG_MAX; mas->max = ULONG_MAX;
mas->node = MAS_START; mas->status = ma_start;
mas->node = NULL;
} }
/* Checks if a mas has not found anything */ static inline bool mas_is_active(struct ma_state *mas)
static inline bool mas_is_none(const struct ma_state *mas)
{
return mas->node == MAS_NONE;
}
/* Checks if a mas has been paused */
static inline bool mas_is_paused(const struct ma_state *mas)
{ {
return mas->node == MAS_PAUSE; return mas->status == ma_active;
} }
/* Check if the mas is pointing to a node or not */ static inline bool mas_is_err(struct ma_state *mas)
static inline bool mas_is_active(struct ma_state *mas)
{ {
if ((unsigned long)mas->node >= MAPLE_RESERVED_RANGE) return mas->status == ma_error;
return true;
return false;
} }
/** /**
...@@ -540,9 +552,10 @@ static inline bool mas_is_active(struct ma_state *mas) ...@@ -540,9 +552,10 @@ static inline bool mas_is_active(struct ma_state *mas)
* *
* Context: Any context. * Context: Any context.
*/ */
static inline void mas_reset(struct ma_state *mas) static __always_inline void mas_reset(struct ma_state *mas)
{ {
mas->node = MAS_START; mas->status = ma_start;
mas->node = NULL;
} }
/** /**
...@@ -716,7 +729,7 @@ static inline void __mas_set_range(struct ma_state *mas, unsigned long start, ...@@ -716,7 +729,7 @@ static inline void __mas_set_range(struct ma_state *mas, unsigned long start,
static inline static inline
void mas_set_range(struct ma_state *mas, unsigned long start, unsigned long last) void mas_set_range(struct ma_state *mas, unsigned long start, unsigned long last)
{ {
mas->node = MAS_START; mas_reset(mas);
__mas_set_range(mas, start, last); __mas_set_range(mas, start, last);
} }
......
...@@ -1071,7 +1071,8 @@ struct vma_iterator { ...@@ -1071,7 +1071,8 @@ struct vma_iterator {
.mas = { \ .mas = { \
.tree = &(__mm)->mm_mt, \ .tree = &(__mm)->mm_mt, \
.index = __addr, \ .index = __addr, \
.node = MAS_START, \ .node = NULL, \
.status = ma_start, \
}, \ }, \
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -1163,13 +1163,13 @@ static inline void vma_iter_store(struct vma_iterator *vmi, ...@@ -1163,13 +1163,13 @@ static inline void vma_iter_store(struct vma_iterator *vmi,
{ {
#if defined(CONFIG_DEBUG_VM_MAPLE_TREE) #if defined(CONFIG_DEBUG_VM_MAPLE_TREE)
if (MAS_WARN_ON(&vmi->mas, vmi->mas.node != MAS_START && if (MAS_WARN_ON(&vmi->mas, vmi->mas.status != ma_start &&
vmi->mas.index > vma->vm_start)) { vmi->mas.index > vma->vm_start)) {
pr_warn("%lx > %lx\n store vma %lx-%lx\n into slot %lx-%lx\n", pr_warn("%lx > %lx\n store vma %lx-%lx\n into slot %lx-%lx\n",
vmi->mas.index, vma->vm_start, vma->vm_start, vmi->mas.index, vma->vm_start, vma->vm_start,
vma->vm_end, vmi->mas.index, vmi->mas.last); vma->vm_end, vmi->mas.index, vmi->mas.last);
} }
if (MAS_WARN_ON(&vmi->mas, vmi->mas.node != MAS_START && if (MAS_WARN_ON(&vmi->mas, vmi->mas.status != ma_start &&
vmi->mas.last < vma->vm_start)) { vmi->mas.last < vma->vm_start)) {
pr_warn("%lx < %lx\nstore vma %lx-%lx\ninto slot %lx-%lx\n", pr_warn("%lx < %lx\nstore vma %lx-%lx\ninto slot %lx-%lx\n",
vmi->mas.last, vma->vm_start, vma->vm_start, vma->vm_end, vmi->mas.last, vma->vm_start, vma->vm_start, vma->vm_end,
...@@ -1177,7 +1177,7 @@ static inline void vma_iter_store(struct vma_iterator *vmi, ...@@ -1177,7 +1177,7 @@ static inline void vma_iter_store(struct vma_iterator *vmi,
} }
#endif #endif
if (vmi->mas.node != MAS_START && if (vmi->mas.status != ma_start &&
((vmi->mas.index > vma->vm_start) || (vmi->mas.last < vma->vm_start))) ((vmi->mas.index > vma->vm_start) || (vmi->mas.last < vma->vm_start)))
vma_iter_invalidate(vmi); vma_iter_invalidate(vmi);
...@@ -1188,7 +1188,7 @@ static inline void vma_iter_store(struct vma_iterator *vmi, ...@@ -1188,7 +1188,7 @@ static inline void vma_iter_store(struct vma_iterator *vmi,
static inline int vma_iter_store_gfp(struct vma_iterator *vmi, static inline int vma_iter_store_gfp(struct vma_iterator *vmi,
struct vm_area_struct *vma, gfp_t gfp) struct vm_area_struct *vma, gfp_t gfp)
{ {
if (vmi->mas.node != MAS_START && if (vmi->mas.status != ma_start &&
((vmi->mas.index > vma->vm_start) || (vmi->mas.last < vma->vm_start))) ((vmi->mas.index > vma->vm_start) || (vmi->mas.last < vma->vm_start)))
vma_iter_invalidate(vmi); vma_iter_invalidate(vmi);
......
...@@ -118,6 +118,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) ...@@ -118,6 +118,7 @@ static noinline void __init check_new_node(struct maple_tree *mt)
MT_BUG_ON(mt, mas.alloc == NULL); MT_BUG_ON(mt, mas.alloc == NULL);
MT_BUG_ON(mt, mas.alloc->slot[0] == NULL); MT_BUG_ON(mt, mas.alloc->slot[0] == NULL);
mas_push_node(&mas, mn); mas_push_node(&mas, mn);
mas_reset(&mas);
mas_nomem(&mas, GFP_KERNEL); /* free */ mas_nomem(&mas, GFP_KERNEL); /* free */
mtree_unlock(mt); mtree_unlock(mt);
...@@ -141,7 +142,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) ...@@ -141,7 +142,7 @@ static noinline void __init check_new_node(struct maple_tree *mt)
mn->parent = ma_parent_ptr(mn); mn->parent = ma_parent_ptr(mn);
ma_free_rcu(mn); ma_free_rcu(mn);
mas.node = MAS_START; mas.status = ma_start;
mas_nomem(&mas, GFP_KERNEL); mas_nomem(&mas, GFP_KERNEL);
/* Allocate 3 nodes, will fail. */ /* Allocate 3 nodes, will fail. */
mas_node_count(&mas, 3); mas_node_count(&mas, 3);
...@@ -158,6 +159,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) ...@@ -158,6 +159,7 @@ static noinline void __init check_new_node(struct maple_tree *mt)
/* Ensure we counted 3. */ /* Ensure we counted 3. */
MT_BUG_ON(mt, mas_allocated(&mas) != 3); MT_BUG_ON(mt, mas_allocated(&mas) != 3);
/* Free. */ /* Free. */
mas_reset(&mas);
mas_nomem(&mas, GFP_KERNEL); mas_nomem(&mas, GFP_KERNEL);
/* Set allocation request to 1. */ /* Set allocation request to 1. */
...@@ -272,6 +274,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) ...@@ -272,6 +274,7 @@ static noinline void __init check_new_node(struct maple_tree *mt)
ma_free_rcu(mn); ma_free_rcu(mn);
MT_BUG_ON(mt, mas_allocated(&mas) != i - j - 1); MT_BUG_ON(mt, mas_allocated(&mas) != i - j - 1);
} }
mas_reset(&mas);
MT_BUG_ON(mt, mas_nomem(&mas, GFP_KERNEL)); MT_BUG_ON(mt, mas_nomem(&mas, GFP_KERNEL));
} }
...@@ -294,6 +297,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) ...@@ -294,6 +297,7 @@ static noinline void __init check_new_node(struct maple_tree *mt)
smn = smn->slot[0]; /* next. */ smn = smn->slot[0]; /* next. */
} }
MT_BUG_ON(mt, mas_allocated(&mas) != total); MT_BUG_ON(mt, mas_allocated(&mas) != total);
mas_reset(&mas);
mas_nomem(&mas, GFP_KERNEL); /* Free. */ mas_nomem(&mas, GFP_KERNEL); /* Free. */
MT_BUG_ON(mt, mas_allocated(&mas) != 0); MT_BUG_ON(mt, mas_allocated(&mas) != 0);
...@@ -441,7 +445,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) ...@@ -441,7 +445,7 @@ static noinline void __init check_new_node(struct maple_tree *mt)
mas.node = MA_ERROR(-ENOMEM); mas.node = MA_ERROR(-ENOMEM);
mas_node_count(&mas, 10); /* Request */ mas_node_count(&mas, 10); /* Request */
mas_nomem(&mas, GFP_KERNEL); /* Fill request */ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
mas.node = MAS_START; mas.status = ma_start;
MT_BUG_ON(mt, mas_allocated(&mas) != 10); MT_BUG_ON(mt, mas_allocated(&mas) != 10);
mas_destroy(&mas); mas_destroy(&mas);
...@@ -452,7 +456,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) ...@@ -452,7 +456,7 @@ static noinline void __init check_new_node(struct maple_tree *mt)
mas.node = MA_ERROR(-ENOMEM); mas.node = MA_ERROR(-ENOMEM);
mas_node_count(&mas, 10 + MAPLE_ALLOC_SLOTS - 1); /* Request */ mas_node_count(&mas, 10 + MAPLE_ALLOC_SLOTS - 1); /* Request */
mas_nomem(&mas, GFP_KERNEL); /* Fill request */ mas_nomem(&mas, GFP_KERNEL); /* Fill request */
mas.node = MAS_START; mas.status = ma_start;
MT_BUG_ON(mt, mas_allocated(&mas) != 10 + MAPLE_ALLOC_SLOTS - 1); MT_BUG_ON(mt, mas_allocated(&mas) != 10 + MAPLE_ALLOC_SLOTS - 1);
mas_destroy(&mas); mas_destroy(&mas);
...@@ -941,7 +945,7 @@ static inline bool mas_tree_walk(struct ma_state *mas, unsigned long *range_min, ...@@ -941,7 +945,7 @@ static inline bool mas_tree_walk(struct ma_state *mas, unsigned long *range_min,
ret = mas_descend_walk(mas, range_min, range_max); ret = mas_descend_walk(mas, range_min, range_max);
if (unlikely(mte_dead_node(mas->node))) { if (unlikely(mte_dead_node(mas->node))) {
mas->node = MAS_START; mas->status = ma_start;
goto retry; goto retry;
} }
...@@ -961,10 +965,10 @@ static inline void *mas_range_load(struct ma_state *mas, ...@@ -961,10 +965,10 @@ static inline void *mas_range_load(struct ma_state *mas,
unsigned long index = mas->index; unsigned long index = mas->index;
if (mas_is_none(mas) || mas_is_paused(mas)) if (mas_is_none(mas) || mas_is_paused(mas))
mas->node = MAS_START; mas->status = ma_start;
retry: retry:
if (mas_tree_walk(mas, range_min, range_max)) if (mas_tree_walk(mas, range_min, range_max))
if (unlikely(mas->node == MAS_ROOT)) if (unlikely(mas->status == ma_root))
return mas_root(mas); return mas_root(mas);
if (likely(mas->offset != MAPLE_NODE_SLOTS)) if (likely(mas->offset != MAPLE_NODE_SLOTS))
...@@ -35337,7 +35341,7 @@ static void mas_dfs_preorder(struct ma_state *mas) ...@@ -35337,7 +35341,7 @@ static void mas_dfs_preorder(struct ma_state *mas)
unsigned char end, slot = 0; unsigned char end, slot = 0;
unsigned long *pivots; unsigned long *pivots;
if (mas->node == MAS_START) { if (mas->status == ma_start) {
mas_start(mas); mas_start(mas);
return; return;
} }
...@@ -35374,7 +35378,7 @@ static void mas_dfs_preorder(struct ma_state *mas) ...@@ -35374,7 +35378,7 @@ static void mas_dfs_preorder(struct ma_state *mas)
return; return;
done: done:
mas->node = MAS_NONE; mas->status = ma_none;
} }
...@@ -35833,7 +35837,7 @@ static noinline void __init check_nomem(struct maple_tree *mt) ...@@ -35833,7 +35837,7 @@ static noinline void __init check_nomem(struct maple_tree *mt)
mas_store(&ms, &ms); /* insert 1 -> &ms, fails. */ mas_store(&ms, &ms); /* insert 1 -> &ms, fails. */
MT_BUG_ON(mt, ms.node != MA_ERROR(-ENOMEM)); MT_BUG_ON(mt, ms.node != MA_ERROR(-ENOMEM));
mas_nomem(&ms, GFP_KERNEL); /* Node allocated in here. */ mas_nomem(&ms, GFP_KERNEL); /* Node allocated in here. */
MT_BUG_ON(mt, ms.node != MAS_START); MT_BUG_ON(mt, ms.status != ma_start);
mtree_unlock(mt); mtree_unlock(mt);
MT_BUG_ON(mt, mtree_insert(mt, 2, mt, GFP_KERNEL) != 0); MT_BUG_ON(mt, mtree_insert(mt, 2, mt, GFP_KERNEL) != 0);
mtree_lock(mt); mtree_lock(mt);
...@@ -35952,7 +35956,7 @@ static int __init compare_tree(struct maple_tree *mt_a, struct maple_tree *mt_b) ...@@ -35952,7 +35956,7 @@ static int __init compare_tree(struct maple_tree *mt_a, struct maple_tree *mt_b)
if (mas_is_ptr(&mas_a) || mas_is_ptr(&mas_b)) { if (mas_is_ptr(&mas_a) || mas_is_ptr(&mas_b)) {
if (!(mas_is_ptr(&mas_a) && mas_is_ptr(&mas_b))) { if (!(mas_is_ptr(&mas_a) && mas_is_ptr(&mas_b))) {
pr_err("One is MAS_ROOT and the other is not.\n"); pr_err("One is ma_root and the other is not.\n");
return -1; return -1;
} }
return 0; return 0;
...@@ -35961,7 +35965,7 @@ static int __init compare_tree(struct maple_tree *mt_a, struct maple_tree *mt_b) ...@@ -35961,7 +35965,7 @@ static int __init compare_tree(struct maple_tree *mt_a, struct maple_tree *mt_b)
while (!mas_is_none(&mas_a) || !mas_is_none(&mas_b)) { while (!mas_is_none(&mas_a) || !mas_is_none(&mas_b)) {
if (mas_is_none(&mas_a) || mas_is_none(&mas_b)) { if (mas_is_none(&mas_a) || mas_is_none(&mas_b)) {
pr_err("One is MAS_NONE and the other is not.\n"); pr_err("One is ma_none and the other is not.\n");
return -1; return -1;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment