Skip to content

Commit 01cca62

Browse files
howlettakpm00
authored andcommitted
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/[email protected] Signed-off-by: Liam R. Howlett <[email protected]> Cc: David Binderman <[email protected]> Cc: Peng Zhang <[email protected]> Cc: Sergey Senozhatsky <[email protected]> Cc: Vernon Yang <[email protected]> Cc: Wei Yang <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent ca7a610 commit 01cca62

File tree

2 files changed

+137
-50
lines changed

2 files changed

+137
-50
lines changed

include/linux/maple_tree.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ void *mas_erase(struct ma_state *mas);
455455
int mas_store_gfp(struct ma_state *mas, void *entry, gfp_t gfp);
456456
void mas_store_prealloc(struct ma_state *mas, void *entry);
457457
void *mas_find(struct ma_state *mas, unsigned long max);
458+
void *mas_find_range(struct ma_state *mas, unsigned long max);
458459
void *mas_find_rev(struct ma_state *mas, unsigned long min);
459460
int mas_preallocate(struct ma_state *mas, gfp_t gfp);
460461
bool mas_is_err(struct ma_state *mas);
@@ -467,6 +468,7 @@ int mas_expected_entries(struct ma_state *mas, unsigned long nr_entries);
467468

468469
void *mas_prev(struct ma_state *mas, unsigned long min);
469470
void *mas_next(struct ma_state *mas, unsigned long max);
471+
void *mas_next_range(struct ma_state *mas, unsigned long max);
470472

471473
int mas_empty_area(struct ma_state *mas, unsigned long min, unsigned long max,
472474
unsigned long size);
@@ -528,6 +530,19 @@ static inline void mas_reset(struct ma_state *mas)
528530
#define mas_for_each(__mas, __entry, __max) \
529531
while (((__entry) = mas_find((__mas), (__max))) != NULL)
530532

533+
/**
534+
* mas_contiguous() - Iterate over a contiguous range of the maple tree.
535+
* @__mas: Maple Tree operation state (maple_state)
536+
* @__entry: Entry retrieved from the tree
537+
* @__max: maximum index to retrieve from the tree
538+
*
539+
* When returned, mas->index and mas->last will hold the entire range of the
540+
* entry. The loop will terminate on the first NULL encountered.
541+
*
542+
* Note: may return the zero entry.
543+
*/
544+
#define mas_contiguous(__mas, __entry, __max) \
545+
while (((__entry) = mas_find_range((__mas), (__max))) != NULL)
531546

532547
/**
533548
* mas_set_range() - Set up Maple Tree operation state for a different index.

lib/maple_tree.c

Lines changed: 122 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4793,13 +4793,10 @@ static void *mas_next_slot(struct ma_state *mas, unsigned long max, bool empty)
47934793
*/
47944794
static inline void *mas_next_entry(struct ma_state *mas, unsigned long limit)
47954795
{
4796-
void *entry = NULL;
4797-
47984796
if (mas->last >= limit)
47994797
return NULL;
48004798

4801-
entry = mas_next_slot(mas, limit, false);
4802-
return entry;
4799+
return mas_next_slot(mas, limit, false);
48034800
}
48044801

48054802
/*
@@ -5880,43 +5877,80 @@ int mas_expected_entries(struct ma_state *mas, unsigned long nr_entries)
58805877
}
58815878
EXPORT_SYMBOL_GPL(mas_expected_entries);
58825879

5883-
/**
5884-
* mas_next() - Get the next entry.
5885-
* @mas: The maple state
5886-
* @max: The maximum index to check.
5887-
*
5888-
* Returns the next entry after @mas->index.
5889-
* Must hold rcu_read_lock or the write lock.
5890-
* Can return the zero entry.
5891-
*
5892-
* Return: The next entry or %NULL
5893-
*/
5894-
void *mas_next(struct ma_state *mas, unsigned long max)
5880+
static inline bool mas_next_setup(struct ma_state *mas, unsigned long max,
5881+
void **entry)
58955882
{
58965883
bool was_none = mas_is_none(mas);
58975884

58985885
if (mas_is_none(mas) || mas_is_paused(mas))
58995886
mas->node = MAS_START;
59005887

59015888
if (mas_is_start(mas))
5902-
mas_walk(mas); /* Retries on dead nodes handled by mas_walk */
5889+
*entry = mas_walk(mas); /* Retries on dead nodes handled by mas_walk */
59035890

59045891
if (mas_is_ptr(mas)) {
5892+
*entry = NULL;
59055893
if (was_none && mas->index == 0) {
59065894
mas->index = mas->last = 0;
5907-
return mas_root(mas);
5895+
return true;
59085896
}
59095897
mas->index = 1;
59105898
mas->last = ULONG_MAX;
59115899
mas->node = MAS_NONE;
5912-
return NULL;
5900+
return true;
59135901
}
59145902

5915-
/* Retries on dead nodes handled by mas_next_entry */
5916-
return mas_next_entry(mas, max);
5903+
if (mas_is_none(mas))
5904+
return true;
5905+
return false;
5906+
}
5907+
5908+
/**
5909+
* mas_next() - Get the next entry.
5910+
* @mas: The maple state
5911+
* @max: The maximum index to check.
5912+
*
5913+
* Returns the next entry after @mas->index.
5914+
* Must hold rcu_read_lock or the write lock.
5915+
* Can return the zero entry.
5916+
*
5917+
* Return: The next entry or %NULL
5918+
*/
5919+
void *mas_next(struct ma_state *mas, unsigned long max)
5920+
{
5921+
void *entry = NULL;
5922+
5923+
if (mas_next_setup(mas, max, &entry))
5924+
return entry;
5925+
5926+
/* Retries on dead nodes handled by mas_next_slot */
5927+
return mas_next_slot(mas, max, false);
59175928
}
59185929
EXPORT_SYMBOL_GPL(mas_next);
59195930

5931+
/**
5932+
* mas_next_range() - Advance the maple state to the next range
5933+
* @mas: The maple state
5934+
* @max: The maximum index to check.
5935+
*
5936+
* Sets @mas->index and @mas->last to the range.
5937+
* Must hold rcu_read_lock or the write lock.
5938+
* Can return the zero entry.
5939+
*
5940+
* Return: The next entry or %NULL
5941+
*/
5942+
void *mas_next_range(struct ma_state *mas, unsigned long max)
5943+
{
5944+
void *entry = NULL;
5945+
5946+
if (mas_next_setup(mas, max, &entry))
5947+
return entry;
5948+
5949+
/* Retries on dead nodes handled by mas_next_slot */
5950+
return mas_next_slot(mas, max, true);
5951+
}
5952+
EXPORT_SYMBOL_GPL(mas_next_range);
5953+
59205954
/**
59215955
* mt_next() - get the next value in the maple tree
59225956
* @mt: The maple tree
@@ -6026,73 +6060,111 @@ void mas_pause(struct ma_state *mas)
60266060
EXPORT_SYMBOL_GPL(mas_pause);
60276061

60286062
/**
6029-
* mas_find() - On the first call, find the entry at or after mas->index up to
6030-
* %max. Otherwise, find the entry after mas->index.
6063+
* mas_find_setup() - Internal function to set up mas_find*().
60316064
* @mas: The maple state
6032-
* @max: The maximum value to check.
6033-
*
6034-
* Must hold rcu_read_lock or the write lock.
6035-
* If an entry exists, last and index are updated accordingly.
6036-
* May set @mas->node to MAS_NONE.
6065+
* @max: The maximum index
6066+
* @entry: Pointer to the entry
60376067
*
6038-
* Return: The entry or %NULL.
6068+
* Returns: True if entry is the answer, false otherwise.
60396069
*/
6040-
void *mas_find(struct ma_state *mas, unsigned long max)
6070+
static inline bool mas_find_setup(struct ma_state *mas, unsigned long max,
6071+
void **entry)
60416072
{
6073+
*entry = NULL;
6074+
60426075
if (unlikely(mas_is_none(mas))) {
60436076
if (unlikely(mas->last >= max))
6044-
return NULL;
6077+
return true;
60456078

60466079
mas->index = mas->last;
60476080
mas->node = MAS_START;
6048-
}
6049-
6050-
if (unlikely(mas_is_paused(mas))) {
6081+
} else if (unlikely(mas_is_paused(mas))) {
60516082
if (unlikely(mas->last >= max))
6052-
return NULL;
6083+
return true;
60536084

60546085
mas->node = MAS_START;
60556086
mas->index = ++mas->last;
6056-
}
6057-
6058-
6059-
if (unlikely(mas_is_ptr(mas)))
6087+
} else if (unlikely(mas_is_ptr(mas)))
60606088
goto ptr_out_of_range;
60616089

60626090
if (unlikely(mas_is_start(mas))) {
60636091
/* First run or continue */
6064-
void *entry;
6065-
60666092
if (mas->index > max)
6067-
return NULL;
6093+
return true;
60686094

6069-
entry = mas_walk(mas);
6070-
if (entry)
6071-
return entry;
6095+
*entry = mas_walk(mas);
6096+
if (*entry)
6097+
return true;
60726098

60736099
}
60746100

60756101
if (unlikely(!mas_searchable(mas))) {
60766102
if (unlikely(mas_is_ptr(mas)))
60776103
goto ptr_out_of_range;
60786104

6079-
return NULL;
6105+
return true;
60806106
}
60816107

60826108
if (mas->index == max)
6083-
return NULL;
6109+
return true;
60846110

6085-
/* Retries on dead nodes handled by mas_next_slot */
6086-
return mas_next_slot(mas, max, false);
6111+
return false;
60876112

60886113
ptr_out_of_range:
60896114
mas->node = MAS_NONE;
60906115
mas->index = 1;
60916116
mas->last = ULONG_MAX;
6092-
return NULL;
6117+
return true;
6118+
}
6119+
6120+
/**
6121+
* mas_find() - On the first call, find the entry at or after mas->index up to
6122+
* %max. Otherwise, find the entry after mas->index.
6123+
* @mas: The maple state
6124+
* @max: The maximum value to check.
6125+
*
6126+
* Must hold rcu_read_lock or the write lock.
6127+
* If an entry exists, last and index are updated accordingly.
6128+
* May set @mas->node to MAS_NONE.
6129+
*
6130+
* Return: The entry or %NULL.
6131+
*/
6132+
void *mas_find(struct ma_state *mas, unsigned long max)
6133+
{
6134+
void *entry = NULL;
6135+
6136+
if (mas_find_setup(mas, max, &entry))
6137+
return entry;
6138+
6139+
/* Retries on dead nodes handled by mas_next_slot */
6140+
return mas_next_slot(mas, max, false);
60936141
}
60946142
EXPORT_SYMBOL_GPL(mas_find);
60956143

6144+
/**
6145+
* mas_find_range() - On the first call, find the entry at or after
6146+
* mas->index up to %max. Otherwise, advance to the next slot mas->index.
6147+
* @mas: The maple state
6148+
* @max: The maximum value to check.
6149+
*
6150+
* Must hold rcu_read_lock or the write lock.
6151+
* If an entry exists, last and index are updated accordingly.
6152+
* May set @mas->node to MAS_NONE.
6153+
*
6154+
* Return: The entry or %NULL.
6155+
*/
6156+
void *mas_find_range(struct ma_state *mas, unsigned long max)
6157+
{
6158+
void *entry;
6159+
6160+
if (mas_find_setup(mas, max, &entry))
6161+
return entry;
6162+
6163+
/* Retries on dead nodes handled by mas_next_slot */
6164+
return mas_next_slot(mas, max, true);
6165+
}
6166+
EXPORT_SYMBOL_GPL(mas_find_range);
6167+
60966168
/**
60976169
* mas_find_rev: On the first call, find the first non-null entry at or below
60986170
* mas->index down to %min. Otherwise find the first non-null entry below

0 commit comments

Comments
 (0)