lib/generic-radix-tree.c: Add peek_prev()
This patch adds genradix_peek_prev(), genradix_iter_rewind(), and genradix_for_each_reverse(), for iterating backwards over a generic radix tree. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
9492261ff2
commit
73badee428
@ -117,6 +117,11 @@ static inline size_t __idx_to_offset(size_t idx, size_t obj_size)
|
|||||||
|
|
||||||
#define __genradix_cast(_radix) (typeof((_radix)->type[0]) *)
|
#define __genradix_cast(_radix) (typeof((_radix)->type[0]) *)
|
||||||
#define __genradix_obj_size(_radix) sizeof((_radix)->type[0])
|
#define __genradix_obj_size(_radix) sizeof((_radix)->type[0])
|
||||||
|
#define __genradix_objs_per_page(_radix) \
|
||||||
|
(PAGE_SIZE / sizeof((_radix)->type[0]))
|
||||||
|
#define __genradix_page_remainder(_radix) \
|
||||||
|
(PAGE_SIZE % sizeof((_radix)->type[0]))
|
||||||
|
|
||||||
#define __genradix_idx_to_offset(_radix, _idx) \
|
#define __genradix_idx_to_offset(_radix, _idx) \
|
||||||
__idx_to_offset(_idx, __genradix_obj_size(_radix))
|
__idx_to_offset(_idx, __genradix_obj_size(_radix))
|
||||||
|
|
||||||
@ -180,7 +185,25 @@ void *__genradix_iter_peek(struct genradix_iter *, struct __genradix *, size_t);
|
|||||||
#define genradix_iter_peek(_iter, _radix) \
|
#define genradix_iter_peek(_iter, _radix) \
|
||||||
(__genradix_cast(_radix) \
|
(__genradix_cast(_radix) \
|
||||||
__genradix_iter_peek(_iter, &(_radix)->tree, \
|
__genradix_iter_peek(_iter, &(_radix)->tree, \
|
||||||
PAGE_SIZE / __genradix_obj_size(_radix)))
|
__genradix_objs_per_page(_radix)))
|
||||||
|
|
||||||
|
void *__genradix_iter_peek_prev(struct genradix_iter *, struct __genradix *,
|
||||||
|
size_t, size_t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* genradix_iter_peek_prev - get first entry at or below iterator's current
|
||||||
|
* position
|
||||||
|
* @_iter: a genradix_iter
|
||||||
|
* @_radix: genradix being iterated over
|
||||||
|
*
|
||||||
|
* If no more entries exist at or below @_iter's current position, returns NULL
|
||||||
|
*/
|
||||||
|
#define genradix_iter_peek_prev(_iter, _radix) \
|
||||||
|
(__genradix_cast(_radix) \
|
||||||
|
__genradix_iter_peek_prev(_iter, &(_radix)->tree, \
|
||||||
|
__genradix_objs_per_page(_radix), \
|
||||||
|
__genradix_obj_size(_radix) + \
|
||||||
|
__genradix_page_remainder(_radix)))
|
||||||
|
|
||||||
static inline void __genradix_iter_advance(struct genradix_iter *iter,
|
static inline void __genradix_iter_advance(struct genradix_iter *iter,
|
||||||
size_t obj_size)
|
size_t obj_size)
|
||||||
@ -203,6 +226,25 @@ static inline void __genradix_iter_advance(struct genradix_iter *iter,
|
|||||||
#define genradix_iter_advance(_iter, _radix) \
|
#define genradix_iter_advance(_iter, _radix) \
|
||||||
__genradix_iter_advance(_iter, __genradix_obj_size(_radix))
|
__genradix_iter_advance(_iter, __genradix_obj_size(_radix))
|
||||||
|
|
||||||
|
static inline void __genradix_iter_rewind(struct genradix_iter *iter,
|
||||||
|
size_t obj_size)
|
||||||
|
{
|
||||||
|
if (iter->offset == 0 ||
|
||||||
|
iter->offset == SIZE_MAX) {
|
||||||
|
iter->offset = SIZE_MAX;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((iter->offset & (PAGE_SIZE - 1)) == 0)
|
||||||
|
iter->offset -= PAGE_SIZE % obj_size;
|
||||||
|
|
||||||
|
iter->offset -= obj_size;
|
||||||
|
iter->pos--;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define genradix_iter_rewind(_iter, _radix) \
|
||||||
|
__genradix_iter_rewind(_iter, __genradix_obj_size(_radix))
|
||||||
|
|
||||||
#define genradix_for_each_from(_radix, _iter, _p, _start) \
|
#define genradix_for_each_from(_radix, _iter, _p, _start) \
|
||||||
for (_iter = genradix_iter_init(_radix, _start); \
|
for (_iter = genradix_iter_init(_radix, _start); \
|
||||||
(_p = genradix_iter_peek(&_iter, _radix)) != NULL; \
|
(_p = genradix_iter_peek(&_iter, _radix)) != NULL; \
|
||||||
@ -220,6 +262,23 @@ static inline void __genradix_iter_advance(struct genradix_iter *iter,
|
|||||||
#define genradix_for_each(_radix, _iter, _p) \
|
#define genradix_for_each(_radix, _iter, _p) \
|
||||||
genradix_for_each_from(_radix, _iter, _p, 0)
|
genradix_for_each_from(_radix, _iter, _p, 0)
|
||||||
|
|
||||||
|
#define genradix_last_pos(_radix) \
|
||||||
|
(SIZE_MAX / PAGE_SIZE * __genradix_objs_per_page(_radix) - 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* genradix_for_each_reverse - iterate over entry in a genradix, reverse order
|
||||||
|
* @_radix: genradix to iterate over
|
||||||
|
* @_iter: a genradix_iter to track current position
|
||||||
|
* @_p: pointer to genradix entry type
|
||||||
|
*
|
||||||
|
* On every iteration, @_p will point to the current entry, and @_iter.pos
|
||||||
|
* will be the current entry's index.
|
||||||
|
*/
|
||||||
|
#define genradix_for_each_reverse(_radix, _iter, _p) \
|
||||||
|
for (_iter = genradix_iter_init(_radix, genradix_last_pos(_radix));\
|
||||||
|
(_p = genradix_iter_peek_prev(&_iter, _radix)) != NULL;\
|
||||||
|
genradix_iter_rewind(&_iter, _radix))
|
||||||
|
|
||||||
int __genradix_prealloc(struct __genradix *, size_t, gfp_t);
|
int __genradix_prealloc(struct __genradix *, size_t, gfp_t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
#include <linux/atomic.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/generic-radix-tree.h>
|
#include <linux/generic-radix-tree.h>
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
@ -212,6 +213,64 @@ restart:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__genradix_iter_peek);
|
EXPORT_SYMBOL(__genradix_iter_peek);
|
||||||
|
|
||||||
|
void *__genradix_iter_peek_prev(struct genradix_iter *iter,
|
||||||
|
struct __genradix *radix,
|
||||||
|
size_t objs_per_page,
|
||||||
|
size_t obj_size_plus_page_remainder)
|
||||||
|
{
|
||||||
|
struct genradix_root *r;
|
||||||
|
struct genradix_node *n;
|
||||||
|
unsigned level, i;
|
||||||
|
|
||||||
|
if (iter->offset == SIZE_MAX)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
restart:
|
||||||
|
r = READ_ONCE(radix->root);
|
||||||
|
if (!r)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
n = genradix_root_to_node(r);
|
||||||
|
level = genradix_root_to_depth(r);
|
||||||
|
|
||||||
|
if (ilog2(iter->offset) >= genradix_depth_shift(level)) {
|
||||||
|
iter->offset = genradix_depth_size(level);
|
||||||
|
iter->pos = (iter->offset >> PAGE_SHIFT) * objs_per_page;
|
||||||
|
|
||||||
|
iter->offset -= obj_size_plus_page_remainder;
|
||||||
|
iter->pos--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (level) {
|
||||||
|
level--;
|
||||||
|
|
||||||
|
i = (iter->offset >> genradix_depth_shift(level)) &
|
||||||
|
(GENRADIX_ARY - 1);
|
||||||
|
|
||||||
|
while (!n->children[i]) {
|
||||||
|
size_t objs_per_ptr = genradix_depth_size(level);
|
||||||
|
|
||||||
|
iter->offset = round_down(iter->offset, objs_per_ptr);
|
||||||
|
iter->pos = (iter->offset >> PAGE_SHIFT) * objs_per_page;
|
||||||
|
|
||||||
|
if (!iter->offset)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
iter->offset -= obj_size_plus_page_remainder;
|
||||||
|
iter->pos--;
|
||||||
|
|
||||||
|
if (!i)
|
||||||
|
goto restart;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = n->children[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return &n->data[iter->offset & (PAGE_SIZE - 1)];
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(__genradix_iter_peek_prev);
|
||||||
|
|
||||||
static void genradix_free_recurse(struct genradix_node *n, unsigned level)
|
static void genradix_free_recurse(struct genradix_node *n, unsigned level)
|
||||||
{
|
{
|
||||||
if (level) {
|
if (level) {
|
||||||
|
Loading…
Reference in New Issue
Block a user