Skip to content

Commit b803b42

Browse files
author
Matthew Wilcox
committed
xarray: Add XArray iterators
The xa_for_each iterator allows the user to efficiently walk a range of the array, executing the loop body once for each entry in that range that matches the filter. This commit also includes xa_find() and xa_find_after() which are helper functions for xa_for_each() but may also be useful in their own right. In the xas family of functions, we have xas_for_each(), xas_find(), xas_next_entry(), xas_for_each_tagged(), xas_find_tagged(), xas_next_tagged() and xas_pause(). Signed-off-by: Matthew Wilcox <willy@infradead.org>
1 parent 41aec91 commit b803b42

File tree

3 files changed

+640
-0
lines changed

3 files changed

+640
-0
lines changed

include/linux/xarray.h

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,10 @@ void *xa_cmpxchg(struct xarray *, unsigned long index,
280280
bool xa_get_mark(struct xarray *, unsigned long index, xa_mark_t);
281281
void xa_set_mark(struct xarray *, unsigned long index, xa_mark_t);
282282
void xa_clear_mark(struct xarray *, unsigned long index, xa_mark_t);
283+
void *xa_find(struct xarray *xa, unsigned long *index,
284+
unsigned long max, xa_mark_t) __attribute__((nonnull(2)));
285+
void *xa_find_after(struct xarray *xa, unsigned long *index,
286+
unsigned long max, xa_mark_t) __attribute__((nonnull(2)));
283287

284288
/**
285289
* xa_init() - Initialise an empty XArray.
@@ -364,6 +368,35 @@ static inline int xa_insert(struct xarray *xa, unsigned long index,
364368
return -EEXIST;
365369
}
366370

371+
/**
372+
* xa_for_each() - Iterate over a portion of an XArray.
373+
* @xa: XArray.
374+
* @entry: Entry retrieved from array.
375+
* @index: Index of @entry.
376+
* @max: Maximum index to retrieve from array.
377+
* @filter: Selection criterion.
378+
*
379+
* Initialise @index to the lowest index you want to retrieve from the
380+
* array. During the iteration, @entry will have the value of the entry
381+
* stored in @xa at @index. The iteration will skip all entries in the
382+
* array which do not match @filter. You may modify @index during the
383+
* iteration if you want to skip or reprocess indices. It is safe to modify
384+
* the array during the iteration. At the end of the iteration, @entry will
385+
* be set to NULL and @index will have a value less than or equal to max.
386+
*
387+
* xa_for_each() is O(n.log(n)) while xas_for_each() is O(n). You have
388+
* to handle your own locking with xas_for_each(), and if you have to unlock
389+
* after each iteration, it will also end up being O(n.log(n)). xa_for_each()
390+
* will spin if it hits a retry entry; if you intend to see retry entries,
391+
* you should use the xas_for_each() iterator instead. The xas_for_each()
392+
* iterator will expand into more inline code than xa_for_each().
393+
*
394+
* Context: Any context. Takes and releases the RCU lock.
395+
*/
396+
#define xa_for_each(xa, entry, index, max, filter) \
397+
for (entry = xa_find(xa, &index, max, filter); entry; \
398+
entry = xa_find_after(xa, &index, max, filter))
399+
367400
#define xa_trylock(xa) spin_trylock(&(xa)->xa_lock)
368401
#define xa_lock(xa) spin_lock(&(xa)->xa_lock)
369402
#define xa_unlock(xa) spin_unlock(&(xa)->xa_lock)
@@ -835,13 +868,16 @@ static inline bool xas_retry(struct xa_state *xas, const void *entry)
835868

836869
void *xas_load(struct xa_state *);
837870
void *xas_store(struct xa_state *, void *entry);
871+
void *xas_find(struct xa_state *, unsigned long max);
838872

839873
bool xas_get_mark(const struct xa_state *, xa_mark_t);
840874
void xas_set_mark(const struct xa_state *, xa_mark_t);
841875
void xas_clear_mark(const struct xa_state *, xa_mark_t);
876+
void *xas_find_marked(struct xa_state *, unsigned long max, xa_mark_t);
842877
void xas_init_marks(const struct xa_state *);
843878

844879
bool xas_nomem(struct xa_state *, gfp_t);
880+
void xas_pause(struct xa_state *);
845881

846882
/**
847883
* xas_reload() - Refetch an entry from the xarray.
@@ -914,4 +950,133 @@ static inline void xas_set_update(struct xa_state *xas, xa_update_node_t update)
914950
xas->xa_update = update;
915951
}
916952

953+
/**
954+
* xas_next_entry() - Advance iterator to next present entry.
955+
* @xas: XArray operation state.
956+
* @max: Highest index to return.
957+
*
958+
* xas_next_entry() is an inline function to optimise xarray traversal for
959+
* speed. It is equivalent to calling xas_find(), and will call xas_find()
960+
* for all the hard cases.
961+
*
962+
* Return: The next present entry after the one currently referred to by @xas.
963+
*/
964+
static inline void *xas_next_entry(struct xa_state *xas, unsigned long max)
965+
{
966+
struct xa_node *node = xas->xa_node;
967+
void *entry;
968+
969+
if (unlikely(xas_not_node(node) || node->shift ||
970+
xas->xa_offset != (xas->xa_index & XA_CHUNK_MASK)))
971+
return xas_find(xas, max);
972+
973+
do {
974+
if (unlikely(xas->xa_index >= max))
975+
return xas_find(xas, max);
976+
if (unlikely(xas->xa_offset == XA_CHUNK_MASK))
977+
return xas_find(xas, max);
978+
entry = xa_entry(xas->xa, node, xas->xa_offset + 1);
979+
if (unlikely(xa_is_internal(entry)))
980+
return xas_find(xas, max);
981+
xas->xa_offset++;
982+
xas->xa_index++;
983+
} while (!entry);
984+
985+
return entry;
986+
}
987+
988+
/* Private */
989+
static inline unsigned int xas_find_chunk(struct xa_state *xas, bool advance,
990+
xa_mark_t mark)
991+
{
992+
unsigned long *addr = xas->xa_node->marks[(__force unsigned)mark];
993+
unsigned int offset = xas->xa_offset;
994+
995+
if (advance)
996+
offset++;
997+
if (XA_CHUNK_SIZE == BITS_PER_LONG) {
998+
if (offset < XA_CHUNK_SIZE) {
999+
unsigned long data = *addr & (~0UL << offset);
1000+
if (data)
1001+
return __ffs(data);
1002+
}
1003+
return XA_CHUNK_SIZE;
1004+
}
1005+
1006+
return find_next_bit(addr, XA_CHUNK_SIZE, offset);
1007+
}
1008+
1009+
/**
1010+
* xas_next_marked() - Advance iterator to next marked entry.
1011+
* @xas: XArray operation state.
1012+
* @max: Highest index to return.
1013+
* @mark: Mark to search for.
1014+
*
1015+
* xas_next_marked() is an inline function to optimise xarray traversal for
1016+
* speed. It is equivalent to calling xas_find_marked(), and will call
1017+
* xas_find_marked() for all the hard cases.
1018+
*
1019+
* Return: The next marked entry after the one currently referred to by @xas.
1020+
*/
1021+
static inline void *xas_next_marked(struct xa_state *xas, unsigned long max,
1022+
xa_mark_t mark)
1023+
{
1024+
struct xa_node *node = xas->xa_node;
1025+
unsigned int offset;
1026+
1027+
if (unlikely(xas_not_node(node) || node->shift))
1028+
return xas_find_marked(xas, max, mark);
1029+
offset = xas_find_chunk(xas, true, mark);
1030+
xas->xa_offset = offset;
1031+
xas->xa_index = (xas->xa_index & ~XA_CHUNK_MASK) + offset;
1032+
if (xas->xa_index > max)
1033+
return NULL;
1034+
if (offset == XA_CHUNK_SIZE)
1035+
return xas_find_marked(xas, max, mark);
1036+
return xa_entry(xas->xa, node, offset);
1037+
}
1038+
1039+
/*
1040+
* If iterating while holding a lock, drop the lock and reschedule
1041+
* every %XA_CHECK_SCHED loops.
1042+
*/
1043+
enum {
1044+
XA_CHECK_SCHED = 4096,
1045+
};
1046+
1047+
/**
1048+
* xas_for_each() - Iterate over a range of an XArray.
1049+
* @xas: XArray operation state.
1050+
* @entry: Entry retrieved from the array.
1051+
* @max: Maximum index to retrieve from array.
1052+
*
1053+
* The loop body will be executed for each entry present in the xarray
1054+
* between the current xas position and @max. @entry will be set to
1055+
* the entry retrieved from the xarray. It is safe to delete entries
1056+
* from the array in the loop body. You should hold either the RCU lock
1057+
* or the xa_lock while iterating. If you need to drop the lock, call
1058+
* xas_pause() first.
1059+
*/
1060+
#define xas_for_each(xas, entry, max) \
1061+
for (entry = xas_find(xas, max); entry; \
1062+
entry = xas_next_entry(xas, max))
1063+
1064+
/**
1065+
* xas_for_each_marked() - Iterate over a range of an XArray.
1066+
* @xas: XArray operation state.
1067+
* @entry: Entry retrieved from the array.
1068+
* @max: Maximum index to retrieve from array.
1069+
* @mark: Mark to search for.
1070+
*
1071+
* The loop body will be executed for each marked entry in the xarray
1072+
* between the current xas position and @max. @entry will be set to
1073+
* the entry retrieved from the xarray. It is safe to delete entries
1074+
* from the array in the loop body. You should hold either the RCU lock
1075+
* or the xa_lock while iterating. If you need to drop the lock, call
1076+
* xas_pause() first.
1077+
*/
1078+
#define xas_for_each_marked(xas, entry, max, mark) \
1079+
for (entry = xas_find_marked(xas, max, mark); entry; \
1080+
entry = xas_next_marked(xas, max, mark))
1081+
9171082
#endif /* _LINUX_XARRAY_H */

0 commit comments

Comments
 (0)