maple_tree: add mas_next_range() and mas_find_range() interfaces
Some users of the maple tree may want to move to the next range in the tree, even if it stores a NULL. This family of function provides that functionality by advancing one slot at a time and returning the result, while mas_contiguous() will iterate over the range and stop on encountering the first NULL. Link: https://lkml.kernel.org/r/20230518145544.1722059-29-Liam.Howlett@oracle.com Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com> Cc: David Binderman <dcb314@hotmail.com> Cc: Peng Zhang <zhangpeng.00@bytedance.com> Cc: Sergey Senozhatsky <senozhatsky@chromium.org> Cc: Vernon Yang <vernon2gm@gmail.com> Cc: Wei Yang <richard.weiyang@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
fff4a58cc0
commit
6169b55319
@ -455,6 +455,7 @@ void *mas_erase(struct ma_state *mas);
|
|||||||
int mas_store_gfp(struct ma_state *mas, void *entry, gfp_t gfp);
|
int mas_store_gfp(struct ma_state *mas, void *entry, gfp_t gfp);
|
||||||
void mas_store_prealloc(struct ma_state *mas, void *entry);
|
void mas_store_prealloc(struct ma_state *mas, void *entry);
|
||||||
void *mas_find(struct ma_state *mas, unsigned long max);
|
void *mas_find(struct ma_state *mas, unsigned long max);
|
||||||
|
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);
|
||||||
int mas_preallocate(struct ma_state *mas, gfp_t gfp);
|
int mas_preallocate(struct ma_state *mas, gfp_t gfp);
|
||||||
bool mas_is_err(struct ma_state *mas);
|
bool mas_is_err(struct ma_state *mas);
|
||||||
@ -467,6 +468,7 @@ int mas_expected_entries(struct ma_state *mas, unsigned long nr_entries);
|
|||||||
|
|
||||||
void *mas_prev(struct ma_state *mas, unsigned long min);
|
void *mas_prev(struct ma_state *mas, unsigned long min);
|
||||||
void *mas_next(struct ma_state *mas, unsigned long max);
|
void *mas_next(struct ma_state *mas, unsigned long max);
|
||||||
|
void *mas_next_range(struct ma_state *mas, unsigned long max);
|
||||||
|
|
||||||
int mas_empty_area(struct ma_state *mas, unsigned long min, unsigned long max,
|
int mas_empty_area(struct ma_state *mas, unsigned long min, unsigned long max,
|
||||||
unsigned long size);
|
unsigned long size);
|
||||||
@ -528,7 +530,6 @@ static inline void mas_reset(struct ma_state *mas)
|
|||||||
#define mas_for_each(__mas, __entry, __max) \
|
#define mas_for_each(__mas, __entry, __max) \
|
||||||
while (((__entry) = mas_find((__mas), (__max))) != NULL)
|
while (((__entry) = mas_find((__mas), (__max))) != NULL)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mas_set_range() - Set up Maple Tree operation state for a different index.
|
* mas_set_range() - Set up Maple Tree operation state for a different index.
|
||||||
* @mas: Maple Tree operation state.
|
* @mas: Maple Tree operation state.
|
||||||
|
212
lib/maple_tree.c
212
lib/maple_tree.c
@ -4793,13 +4793,10 @@ again:
|
|||||||
*/
|
*/
|
||||||
static inline void *mas_next_entry(struct ma_state *mas, unsigned long limit)
|
static inline void *mas_next_entry(struct ma_state *mas, unsigned long limit)
|
||||||
{
|
{
|
||||||
void *entry = NULL;
|
|
||||||
|
|
||||||
if (mas->last >= limit)
|
if (mas->last >= limit)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
entry = mas_next_slot(mas, limit, false);
|
return mas_next_slot(mas, limit, false);
|
||||||
return entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -5880,6 +5877,34 @@ int mas_expected_entries(struct ma_state *mas, unsigned long nr_entries)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mas_expected_entries);
|
EXPORT_SYMBOL_GPL(mas_expected_entries);
|
||||||
|
|
||||||
|
static inline bool mas_next_setup(struct ma_state *mas, unsigned long max,
|
||||||
|
void **entry)
|
||||||
|
{
|
||||||
|
bool was_none = mas_is_none(mas);
|
||||||
|
|
||||||
|
if (mas_is_none(mas) || mas_is_paused(mas))
|
||||||
|
mas->node = MAS_START;
|
||||||
|
|
||||||
|
if (mas_is_start(mas))
|
||||||
|
*entry = mas_walk(mas); /* Retries on dead nodes handled by mas_walk */
|
||||||
|
|
||||||
|
if (mas_is_ptr(mas)) {
|
||||||
|
*entry = NULL;
|
||||||
|
if (was_none && mas->index == 0) {
|
||||||
|
mas->index = mas->last = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
mas->index = 1;
|
||||||
|
mas->last = ULONG_MAX;
|
||||||
|
mas->node = MAS_NONE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mas_is_none(mas))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mas_next() - Get the next entry.
|
* mas_next() - Get the next entry.
|
||||||
* @mas: The maple state
|
* @mas: The maple state
|
||||||
@ -5893,30 +5918,39 @@ EXPORT_SYMBOL_GPL(mas_expected_entries);
|
|||||||
*/
|
*/
|
||||||
void *mas_next(struct ma_state *mas, unsigned long max)
|
void *mas_next(struct ma_state *mas, unsigned long max)
|
||||||
{
|
{
|
||||||
bool was_none = mas_is_none(mas);
|
void *entry = NULL;
|
||||||
|
|
||||||
if (mas_is_none(mas) || mas_is_paused(mas))
|
if (mas_next_setup(mas, max, &entry))
|
||||||
mas->node = MAS_START;
|
return entry;
|
||||||
|
|
||||||
if (mas_is_start(mas))
|
/* Retries on dead nodes handled by mas_next_slot */
|
||||||
mas_walk(mas); /* Retries on dead nodes handled by mas_walk */
|
return mas_next_slot(mas, max, false);
|
||||||
|
|
||||||
if (mas_is_ptr(mas)) {
|
|
||||||
if (was_none && mas->index == 0) {
|
|
||||||
mas->index = mas->last = 0;
|
|
||||||
return mas_root(mas);
|
|
||||||
}
|
|
||||||
mas->index = 1;
|
|
||||||
mas->last = ULONG_MAX;
|
|
||||||
mas->node = MAS_NONE;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retries on dead nodes handled by mas_next_entry */
|
|
||||||
return mas_next_entry(mas, max);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mas_next);
|
EXPORT_SYMBOL_GPL(mas_next);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mas_next_range() - Advance the maple state to the next range
|
||||||
|
* @mas: The maple state
|
||||||
|
* @max: The maximum index to check.
|
||||||
|
*
|
||||||
|
* Sets @mas->index and @mas->last to the range.
|
||||||
|
* Must hold rcu_read_lock or the write lock.
|
||||||
|
* Can return the zero entry.
|
||||||
|
*
|
||||||
|
* Return: The next entry or %NULL
|
||||||
|
*/
|
||||||
|
void *mas_next_range(struct ma_state *mas, unsigned long max)
|
||||||
|
{
|
||||||
|
void *entry = NULL;
|
||||||
|
|
||||||
|
if (mas_next_setup(mas, max, &entry))
|
||||||
|
return entry;
|
||||||
|
|
||||||
|
/* Retries on dead nodes handled by mas_next_slot */
|
||||||
|
return mas_next_slot(mas, max, true);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mas_next_range);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mt_next() - get the next value in the maple tree
|
* mt_next() - get the next value in the maple tree
|
||||||
* @mt: The maple tree
|
* @mt: The maple tree
|
||||||
@ -6025,6 +6059,64 @@ void mas_pause(struct ma_state *mas)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mas_pause);
|
EXPORT_SYMBOL_GPL(mas_pause);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mas_find_setup() - Internal function to set up mas_find*().
|
||||||
|
* @mas: The maple state
|
||||||
|
* @max: The maximum index
|
||||||
|
* @entry: Pointer to the entry
|
||||||
|
*
|
||||||
|
* Returns: True if entry is the answer, false otherwise.
|
||||||
|
*/
|
||||||
|
static inline bool mas_find_setup(struct ma_state *mas, unsigned long max,
|
||||||
|
void **entry)
|
||||||
|
{
|
||||||
|
*entry = NULL;
|
||||||
|
|
||||||
|
if (unlikely(mas_is_none(mas))) {
|
||||||
|
if (unlikely(mas->last >= max))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
mas->index = mas->last;
|
||||||
|
mas->node = MAS_START;
|
||||||
|
} else if (unlikely(mas_is_paused(mas))) {
|
||||||
|
if (unlikely(mas->last >= max))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
mas->node = MAS_START;
|
||||||
|
mas->index = ++mas->last;
|
||||||
|
} else if (unlikely(mas_is_ptr(mas)))
|
||||||
|
goto ptr_out_of_range;
|
||||||
|
|
||||||
|
if (unlikely(mas_is_start(mas))) {
|
||||||
|
/* First run or continue */
|
||||||
|
if (mas->index > max)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
*entry = mas_walk(mas);
|
||||||
|
if (*entry)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(!mas_searchable(mas))) {
|
||||||
|
if (unlikely(mas_is_ptr(mas)))
|
||||||
|
goto ptr_out_of_range;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mas->index == max)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ptr_out_of_range:
|
||||||
|
mas->node = MAS_NONE;
|
||||||
|
mas->index = 1;
|
||||||
|
mas->last = ULONG_MAX;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mas_find() - On the first call, find the entry at or after mas->index up to
|
* mas_find() - On the first call, find the entry at or after mas->index up to
|
||||||
* %max. Otherwise, find the entry after mas->index.
|
* %max. Otherwise, find the entry after mas->index.
|
||||||
@ -6039,60 +6131,40 @@ EXPORT_SYMBOL_GPL(mas_pause);
|
|||||||
*/
|
*/
|
||||||
void *mas_find(struct ma_state *mas, unsigned long max)
|
void *mas_find(struct ma_state *mas, unsigned long max)
|
||||||
{
|
{
|
||||||
if (unlikely(mas_is_none(mas))) {
|
void *entry = NULL;
|
||||||
if (unlikely(mas->last >= max))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
mas->index = mas->last;
|
if (mas_find_setup(mas, max, &entry))
|
||||||
mas->node = MAS_START;
|
return entry;
|
||||||
}
|
|
||||||
|
|
||||||
if (unlikely(mas_is_paused(mas))) {
|
|
||||||
if (unlikely(mas->last >= max))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
mas->node = MAS_START;
|
|
||||||
mas->index = ++mas->last;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (unlikely(mas_is_ptr(mas)))
|
|
||||||
goto ptr_out_of_range;
|
|
||||||
|
|
||||||
if (unlikely(mas_is_start(mas))) {
|
|
||||||
/* First run or continue */
|
|
||||||
void *entry;
|
|
||||||
|
|
||||||
if (mas->index > max)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
entry = mas_walk(mas);
|
|
||||||
if (entry)
|
|
||||||
return entry;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unlikely(!mas_searchable(mas))) {
|
|
||||||
if (unlikely(mas_is_ptr(mas)))
|
|
||||||
goto ptr_out_of_range;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mas->index == max)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Retries on dead nodes handled by mas_next_slot */
|
/* Retries on dead nodes handled by mas_next_slot */
|
||||||
return mas_next_slot(mas, max, false);
|
return mas_next_slot(mas, max, false);
|
||||||
|
|
||||||
ptr_out_of_range:
|
|
||||||
mas->node = MAS_NONE;
|
|
||||||
mas->index = 1;
|
|
||||||
mas->last = ULONG_MAX;
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mas_find);
|
EXPORT_SYMBOL_GPL(mas_find);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mas_find_range() - On the first call, find the entry at or after
|
||||||
|
* mas->index up to %max. Otherwise, advance to the next slot mas->index.
|
||||||
|
* @mas: The maple state
|
||||||
|
* @max: The maximum value to check.
|
||||||
|
*
|
||||||
|
* Must hold rcu_read_lock or the write lock.
|
||||||
|
* If an entry exists, last and index are updated accordingly.
|
||||||
|
* May set @mas->node to MAS_NONE.
|
||||||
|
*
|
||||||
|
* Return: The entry or %NULL.
|
||||||
|
*/
|
||||||
|
void *mas_find_range(struct ma_state *mas, unsigned long max)
|
||||||
|
{
|
||||||
|
void *entry;
|
||||||
|
|
||||||
|
if (mas_find_setup(mas, max, &entry))
|
||||||
|
return entry;
|
||||||
|
|
||||||
|
/* Retries on dead nodes handled by mas_next_slot */
|
||||||
|
return mas_next_slot(mas, max, true);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mas_find_range);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mas_find_rev: On the first call, find the first non-null entry at or below
|
* mas_find_rev: On the first call, find the first non-null entry at or below
|
||||||
* mas->index down to %min. Otherwise find the first non-null entry below
|
* mas->index down to %min. Otherwise find the first non-null entry below
|
||||||
|
Loading…
x
Reference in New Issue
Block a user