Skip to content

Commit 9b89a03

Browse files
author
Matthew Wilcox
committed
xarray: Add XArray marks
XArray marks are like the radix tree tags, only slightly more strongly typed. They are renamed in order to distinguish them from tagged pointers. This commit adds the basic get/set/clear operations. Signed-off-by: Matthew Wilcox <willy@infradead.org>
1 parent ad3d6c7 commit 9b89a03

File tree

7 files changed

+445
-13
lines changed

7 files changed

+445
-13
lines changed

include/linux/xarray.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <linux/bug.h>
1313
#include <linux/compiler.h>
14+
#include <linux/gfp.h>
1415
#include <linux/kconfig.h>
1516
#include <linux/kernel.h>
1617
#include <linux/rcupdate.h>
@@ -197,6 +198,20 @@ static inline int xa_err(void *entry)
197198
return 0;
198199
}
199200

201+
typedef unsigned __bitwise xa_mark_t;
202+
#define XA_MARK_0 ((__force xa_mark_t)0U)
203+
#define XA_MARK_1 ((__force xa_mark_t)1U)
204+
#define XA_MARK_2 ((__force xa_mark_t)2U)
205+
#define XA_PRESENT ((__force xa_mark_t)8U)
206+
#define XA_MARK_MAX XA_MARK_2
207+
208+
/*
209+
* Values for xa_flags. The radix tree stores its GFP flags in the xa_flags,
210+
* and we remain compatible with that.
211+
*/
212+
#define XA_FLAGS_MARK(mark) ((__force gfp_t)((1U << __GFP_BITS_SHIFT) << \
213+
(__force unsigned)(mark)))
214+
200215
/**
201216
* struct xarray - The anchor of the XArray.
202217
* @xa_lock: Lock that protects the contents of the XArray.
@@ -252,6 +267,9 @@ struct xarray {
252267

253268
void xa_init_flags(struct xarray *, gfp_t flags);
254269
void *xa_load(struct xarray *, unsigned long index);
270+
bool xa_get_mark(struct xarray *, unsigned long index, xa_mark_t);
271+
void xa_set_mark(struct xarray *, unsigned long index, xa_mark_t);
272+
void xa_clear_mark(struct xarray *, unsigned long index, xa_mark_t);
255273

256274
/**
257275
* xa_init() - Initialise an empty XArray.
@@ -278,6 +296,19 @@ static inline bool xa_empty(const struct xarray *xa)
278296
return xa->xa_head == NULL;
279297
}
280298

299+
/**
300+
* xa_marked() - Inquire whether any entry in this array has a mark set
301+
* @xa: Array
302+
* @mark: Mark value
303+
*
304+
* Context: Any context.
305+
* Return: %true if any entry has this mark set.
306+
*/
307+
static inline bool xa_marked(const struct xarray *xa, xa_mark_t mark)
308+
{
309+
return xa->xa_flags & XA_FLAGS_MARK(mark);
310+
}
311+
281312
#define xa_trylock(xa) spin_trylock(&(xa)->xa_lock)
282313
#define xa_lock(xa) spin_lock(&(xa)->xa_lock)
283314
#define xa_unlock(xa) spin_unlock(&(xa)->xa_lock)
@@ -290,6 +321,12 @@ static inline bool xa_empty(const struct xarray *xa)
290321
#define xa_unlock_irqrestore(xa, flags) \
291322
spin_unlock_irqrestore(&(xa)->xa_lock, flags)
292323

324+
/*
325+
* Versions of the normal API which require the caller to hold the xa_lock.
326+
*/
327+
void __xa_set_mark(struct xarray *, unsigned long index, xa_mark_t);
328+
void __xa_clear_mark(struct xarray *, unsigned long index, xa_mark_t);
329+
293330
/* Everything below here is the Advanced API. Proceed with caution. */
294331

295332
/*
@@ -388,6 +425,22 @@ static inline void *xa_entry_locked(const struct xarray *xa,
388425
lockdep_is_held(&xa->xa_lock));
389426
}
390427

428+
/* Private */
429+
static inline struct xa_node *xa_parent(const struct xarray *xa,
430+
const struct xa_node *node)
431+
{
432+
return rcu_dereference_check(node->parent,
433+
lockdep_is_held(&xa->xa_lock));
434+
}
435+
436+
/* Private */
437+
static inline struct xa_node *xa_parent_locked(const struct xarray *xa,
438+
const struct xa_node *node)
439+
{
440+
return rcu_dereference_protected(node->parent,
441+
lockdep_is_held(&xa->xa_lock));
442+
}
443+
391444
/* Private */
392445
static inline struct xa_node *xa_to_node(const void *entry)
393446
{
@@ -588,6 +641,12 @@ static inline bool xas_valid(const struct xa_state *xas)
588641
return !xas_invalid(xas);
589642
}
590643

644+
/* True if the pointer is something other than a node */
645+
static inline bool xas_not_node(struct xa_node *node)
646+
{
647+
return ((unsigned long)node & 3) || !node;
648+
}
649+
591650
/**
592651
* xas_reset() - Reset an XArray operation state.
593652
* @xas: XArray operation state.
@@ -625,6 +684,10 @@ static inline bool xas_retry(struct xa_state *xas, const void *entry)
625684

626685
void *xas_load(struct xa_state *);
627686

687+
bool xas_get_mark(const struct xa_state *, xa_mark_t);
688+
void xas_set_mark(const struct xa_state *, xa_mark_t);
689+
void xas_clear_mark(const struct xa_state *, xa_mark_t);
690+
628691
/**
629692
* xas_reload() - Refetch an entry from the xarray.
630693
* @xas: XArray operation state.

lib/test_xarray.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,45 @@ static noinline void check_xa_load(struct xarray *xa)
6767
XA_BUG_ON(xa, !xa_empty(xa));
6868
}
6969

70+
static noinline void check_xa_mark_1(struct xarray *xa, unsigned long index)
71+
{
72+
/* NULL elements have no marks set */
73+
XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));
74+
xa_set_mark(xa, index, XA_MARK_0);
75+
XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));
76+
77+
/* Storing a pointer will not make a mark appear */
78+
XA_BUG_ON(xa, xa_store_index(xa, index, GFP_KERNEL) != NULL);
79+
XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));
80+
xa_set_mark(xa, index, XA_MARK_0);
81+
XA_BUG_ON(xa, !xa_get_mark(xa, index, XA_MARK_0));
82+
83+
/* Setting one mark will not set another mark */
84+
XA_BUG_ON(xa, xa_get_mark(xa, index + 1, XA_MARK_0));
85+
XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_1));
86+
87+
/* Storing NULL clears marks, and they can't be set again */
88+
xa_erase_index(xa, index);
89+
XA_BUG_ON(xa, !xa_empty(xa));
90+
XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));
91+
xa_set_mark(xa, index, XA_MARK_0);
92+
XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));
93+
}
94+
95+
static noinline void check_xa_mark(struct xarray *xa)
96+
{
97+
unsigned long index;
98+
99+
for (index = 0; index < 16384; index += 4)
100+
check_xa_mark_1(xa, index);
101+
}
102+
70103
static RADIX_TREE(array, GFP_KERNEL);
71104

72105
static int xarray_checks(void)
73106
{
74107
check_xa_load(&array);
108+
check_xa_mark(&array);
75109

76110
printk("XArray: %u of %u tests passed\n", tests_passed, tests_run);
77111
return (tests_run == tests_passed) ? 0 : -EINVAL;

0 commit comments

Comments
 (0)