Skip to content

Commit 4703d91

Browse files
committed
Merge tag 'xarray-5.5' of git://git.infradead.org/users/willy/linux-dax
Pull XArray fixes from Matthew Wilcox: "Primarily bugfixes, mostly around handling index wrap-around correctly. A couple of doc fixes and adding missing APIs. I had an oops live on stage at linux.conf.au this year, and it turned out to be a bug in xas_find() which I can't prove isn't triggerable in the current codebase. Then in looking for the bug, I spotted two more bugs. The bots have had a few days to chew on this with no problems reported, and it passes the test-suite (which now has more tests to make sure these problems don't come back)" * tag 'xarray-5.5' of git://git.infradead.org/users/willy/linux-dax: XArray: Add xa_for_each_range XArray: Fix xas_find returning too many entries XArray: Fix xa_find_after with multi-index entries XArray: Fix infinite loop with entry at ULONG_MAX XArray: Add wrappers for nested spinlocks XArray: Improve documentation of search marks XArray: Fix xas_pause at ULONG_MAX
2 parents 34597c8 + 00ed452 commit 4703d91

4 files changed

Lines changed: 175 additions & 59 deletions

File tree

Documentation/core-api/xarray.rst

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ good performance with large indices. If your index can be larger than
2525
``ULONG_MAX`` then the XArray is not the data type for you. The most
2626
important user of the XArray is the page cache.
2727

28-
Each non-``NULL`` entry in the array has three bits associated with
29-
it called marks. Each mark may be set or cleared independently of
30-
the others. You can iterate over entries which are marked.
31-
3228
Normal pointers may be stored in the XArray directly. They must be 4-byte
3329
aligned, which is true for any pointer returned from kmalloc() and
3430
alloc_page(). It isn't true for arbitrary user-space pointers,
@@ -41,12 +37,11 @@ When you retrieve an entry from the XArray, you can check whether it is
4137
a value entry by calling xa_is_value(), and convert it back to
4238
an integer by calling xa_to_value().
4339

44-
Some users want to store tagged pointers instead of using the marks
45-
described above. They can call xa_tag_pointer() to create an
46-
entry with a tag, xa_untag_pointer() to turn a tagged entry
47-
back into an untagged pointer and xa_pointer_tag() to retrieve
48-
the tag of an entry. Tagged pointers use the same bits that are used
49-
to distinguish value entries from normal pointers, so each user must
40+
Some users want to tag the pointers they store in the XArray. You can
41+
call xa_tag_pointer() to create an entry with a tag, xa_untag_pointer()
42+
to turn a tagged entry back into an untagged pointer and xa_pointer_tag()
43+
to retrieve the tag of an entry. Tagged pointers use the same bits that
44+
are used to distinguish value entries from normal pointers, so you must
5045
decide whether they want to store value entries or tagged pointers in
5146
any particular XArray.
5247

@@ -56,10 +51,9 @@ conflict with value entries or internal entries.
5651
An unusual feature of the XArray is the ability to create entries which
5752
occupy a range of indices. Once stored to, looking up any index in
5853
the range will return the same entry as looking up any other index in
59-
the range. Setting a mark on one index will set it on all of them.
60-
Storing to any index will store to all of them. Multi-index entries can
61-
be explicitly split into smaller entries, or storing ``NULL`` into any
62-
entry will cause the XArray to forget about the range.
54+
the range. Storing to any index will store to all of them. Multi-index
55+
entries can be explicitly split into smaller entries, or storing ``NULL``
56+
into any entry will cause the XArray to forget about the range.
6357

6458
Normal API
6559
==========
@@ -87,17 +81,11 @@ If you want to only store a new entry to an index if the current entry
8781
at that index is ``NULL``, you can use xa_insert() which
8882
returns ``-EBUSY`` if the entry is not empty.
8983

90-
You can enquire whether a mark is set on an entry by using
91-
xa_get_mark(). If the entry is not ``NULL``, you can set a mark
92-
on it by using xa_set_mark() and remove the mark from an entry by
93-
calling xa_clear_mark(). You can ask whether any entry in the
94-
XArray has a particular mark set by calling xa_marked().
95-
9684
You can copy entries out of the XArray into a plain array by calling
97-
xa_extract(). Or you can iterate over the present entries in
98-
the XArray by calling xa_for_each(). You may prefer to use
99-
xa_find() or xa_find_after() to move to the next present
100-
entry in the XArray.
85+
xa_extract(). Or you can iterate over the present entries in the XArray
86+
by calling xa_for_each(), xa_for_each_start() or xa_for_each_range().
87+
You may prefer to use xa_find() or xa_find_after() to move to the next
88+
present entry in the XArray.
10189

10290
Calling xa_store_range() stores the same entry in a range
10391
of indices. If you do this, some of the other operations will behave
@@ -124,6 +112,31 @@ xa_destroy(). If the XArray entries are pointers, you may wish
124112
to free the entries first. You can do this by iterating over all present
125113
entries in the XArray using the xa_for_each() iterator.
126114

115+
Search Marks
116+
------------
117+
118+
Each entry in the array has three bits associated with it called marks.
119+
Each mark may be set or cleared independently of the others. You can
120+
iterate over marked entries by using the xa_for_each_marked() iterator.
121+
122+
You can enquire whether a mark is set on an entry by using
123+
xa_get_mark(). If the entry is not ``NULL``, you can set a mark on it
124+
by using xa_set_mark() and remove the mark from an entry by calling
125+
xa_clear_mark(). You can ask whether any entry in the XArray has a
126+
particular mark set by calling xa_marked(). Erasing an entry from the
127+
XArray causes all marks associated with that entry to be cleared.
128+
129+
Setting or clearing a mark on any index of a multi-index entry will
130+
affect all indices covered by that entry. Querying the mark on any
131+
index will return the same result.
132+
133+
There is no way to iterate over entries which are not marked; the data
134+
structure does not allow this to be implemented efficiently. There are
135+
not currently iterators to search for logical combinations of bits (eg
136+
iterate over all entries which have both ``XA_MARK_1`` and ``XA_MARK_2``
137+
set, or iterate over all entries which have ``XA_MARK_0`` or ``XA_MARK_2``
138+
set). It would be possible to add these if a user arises.
139+
127140
Allocating XArrays
128141
------------------
129142

@@ -180,6 +193,8 @@ No lock needed:
180193
Takes RCU read lock:
181194
* xa_load()
182195
* xa_for_each()
196+
* xa_for_each_start()
197+
* xa_for_each_range()
183198
* xa_find()
184199
* xa_find_after()
185200
* xa_extract()
@@ -419,10 +434,9 @@ you last processed. If you have interrupts disabled while iterating,
419434
then it is good manners to pause the iteration and reenable interrupts
420435
every ``XA_CHECK_SCHED`` entries.
421436

422-
The xas_get_mark(), xas_set_mark() and
423-
xas_clear_mark() functions require the xa_state cursor to have
424-
been moved to the appropriate location in the xarray; they will do
425-
nothing if you have called xas_pause() or xas_set()
437+
The xas_get_mark(), xas_set_mark() and xas_clear_mark() functions require
438+
the xa_state cursor to have been moved to the appropriate location in the
439+
XArray; they will do nothing if you have called xas_pause() or xas_set()
426440
immediately before.
427441

428442
You can call xas_set_update() to have a callback function

include/linux/xarray.h

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,36 @@ static inline bool xa_marked(const struct xarray *xa, xa_mark_t mark)
416416
return xa->xa_flags & XA_FLAGS_MARK(mark);
417417
}
418418

419+
/**
420+
* xa_for_each_range() - Iterate over a portion of an XArray.
421+
* @xa: XArray.
422+
* @index: Index of @entry.
423+
* @entry: Entry retrieved from array.
424+
* @start: First index to retrieve from array.
425+
* @last: Last index to retrieve from array.
426+
*
427+
* During the iteration, @entry will have the value of the entry stored
428+
* in @xa at @index. You may modify @index during the iteration if you
429+
* want to skip or reprocess indices. It is safe to modify the array
430+
* during the iteration. At the end of the iteration, @entry will be set
431+
* to NULL and @index will have a value less than or equal to max.
432+
*
433+
* xa_for_each_range() is O(n.log(n)) while xas_for_each() is O(n). You have
434+
* to handle your own locking with xas_for_each(), and if you have to unlock
435+
* after each iteration, it will also end up being O(n.log(n)).
436+
* xa_for_each_range() will spin if it hits a retry entry; if you intend to
437+
* see retry entries, you should use the xas_for_each() iterator instead.
438+
* The xas_for_each() iterator will expand into more inline code than
439+
* xa_for_each_range().
440+
*
441+
* Context: Any context. Takes and releases the RCU lock.
442+
*/
443+
#define xa_for_each_range(xa, index, entry, start, last) \
444+
for (index = start, \
445+
entry = xa_find(xa, &index, last, XA_PRESENT); \
446+
entry; \
447+
entry = xa_find_after(xa, &index, last, XA_PRESENT))
448+
419449
/**
420450
* xa_for_each_start() - Iterate over a portion of an XArray.
421451
* @xa: XArray.
@@ -439,11 +469,8 @@ static inline bool xa_marked(const struct xarray *xa, xa_mark_t mark)
439469
*
440470
* Context: Any context. Takes and releases the RCU lock.
441471
*/
442-
#define xa_for_each_start(xa, index, entry, start) \
443-
for (index = start, \
444-
entry = xa_find(xa, &index, ULONG_MAX, XA_PRESENT); \
445-
entry; \
446-
entry = xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT))
472+
#define xa_for_each_start(xa, index, entry, start) \
473+
xa_for_each_range(xa, index, entry, start, ULONG_MAX)
447474

448475
/**
449476
* xa_for_each() - Iterate over present entries in an XArray.
@@ -508,6 +535,14 @@ static inline bool xa_marked(const struct xarray *xa, xa_mark_t mark)
508535
spin_lock_irqsave(&(xa)->xa_lock, flags)
509536
#define xa_unlock_irqrestore(xa, flags) \
510537
spin_unlock_irqrestore(&(xa)->xa_lock, flags)
538+
#define xa_lock_nested(xa, subclass) \
539+
spin_lock_nested(&(xa)->xa_lock, subclass)
540+
#define xa_lock_bh_nested(xa, subclass) \
541+
spin_lock_bh_nested(&(xa)->xa_lock, subclass)
542+
#define xa_lock_irq_nested(xa, subclass) \
543+
spin_lock_irq_nested(&(xa)->xa_lock, subclass)
544+
#define xa_lock_irqsave_nested(xa, flags, subclass) \
545+
spin_lock_irqsave_nested(&(xa)->xa_lock, flags, subclass)
511546

512547
/*
513548
* Versions of the normal API which require the caller to hold the

lib/test_xarray.c

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/*
33
* test_xarray.c: Test the XArray API
44
* Copyright (c) 2017-2018 Microsoft Corporation
5+
* Copyright (c) 2019-2020 Oracle
56
* Author: Matthew Wilcox <willy@infradead.org>
67
*/
78

@@ -902,28 +903,34 @@ static noinline void check_store_iter(struct xarray *xa)
902903
XA_BUG_ON(xa, !xa_empty(xa));
903904
}
904905

905-
static noinline void check_multi_find(struct xarray *xa)
906+
static noinline void check_multi_find_1(struct xarray *xa, unsigned order)
906907
{
907908
#ifdef CONFIG_XARRAY_MULTI
909+
unsigned long multi = 3 << order;
910+
unsigned long next = 4 << order;
908911
unsigned long index;
909912

910-
xa_store_order(xa, 12, 2, xa_mk_value(12), GFP_KERNEL);
911-
XA_BUG_ON(xa, xa_store_index(xa, 16, GFP_KERNEL) != NULL);
913+
xa_store_order(xa, multi, order, xa_mk_value(multi), GFP_KERNEL);
914+
XA_BUG_ON(xa, xa_store_index(xa, next, GFP_KERNEL) != NULL);
915+
XA_BUG_ON(xa, xa_store_index(xa, next + 1, GFP_KERNEL) != NULL);
912916

913917
index = 0;
914918
XA_BUG_ON(xa, xa_find(xa, &index, ULONG_MAX, XA_PRESENT) !=
915-
xa_mk_value(12));
916-
XA_BUG_ON(xa, index != 12);
917-
index = 13;
919+
xa_mk_value(multi));
920+
XA_BUG_ON(xa, index != multi);
921+
index = multi + 1;
918922
XA_BUG_ON(xa, xa_find(xa, &index, ULONG_MAX, XA_PRESENT) !=
919-
xa_mk_value(12));
920-
XA_BUG_ON(xa, (index < 12) || (index >= 16));
923+
xa_mk_value(multi));
924+
XA_BUG_ON(xa, (index < multi) || (index >= next));
921925
XA_BUG_ON(xa, xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT) !=
922-
xa_mk_value(16));
923-
XA_BUG_ON(xa, index != 16);
924-
925-
xa_erase_index(xa, 12);
926-
xa_erase_index(xa, 16);
926+
xa_mk_value(next));
927+
XA_BUG_ON(xa, index != next);
928+
XA_BUG_ON(xa, xa_find_after(xa, &index, next, XA_PRESENT) != NULL);
929+
XA_BUG_ON(xa, index != next);
930+
931+
xa_erase_index(xa, multi);
932+
xa_erase_index(xa, next);
933+
xa_erase_index(xa, next + 1);
927934
XA_BUG_ON(xa, !xa_empty(xa));
928935
#endif
929936
}
@@ -1046,12 +1053,33 @@ static noinline void check_find_3(struct xarray *xa)
10461053
xa_destroy(xa);
10471054
}
10481055

1056+
static noinline void check_find_4(struct xarray *xa)
1057+
{
1058+
unsigned long index = 0;
1059+
void *entry;
1060+
1061+
xa_store_index(xa, ULONG_MAX, GFP_KERNEL);
1062+
1063+
entry = xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT);
1064+
XA_BUG_ON(xa, entry != xa_mk_index(ULONG_MAX));
1065+
1066+
entry = xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT);
1067+
XA_BUG_ON(xa, entry);
1068+
1069+
xa_erase_index(xa, ULONG_MAX);
1070+
}
1071+
10491072
static noinline void check_find(struct xarray *xa)
10501073
{
1074+
unsigned i;
1075+
10511076
check_find_1(xa);
10521077
check_find_2(xa);
10531078
check_find_3(xa);
1054-
check_multi_find(xa);
1079+
check_find_4(xa);
1080+
1081+
for (i = 2; i < 10; i++)
1082+
check_multi_find_1(xa, i);
10551083
check_multi_find_2(xa);
10561084
}
10571085

@@ -1132,6 +1160,27 @@ static noinline void check_move_tiny(struct xarray *xa)
11321160
XA_BUG_ON(xa, !xa_empty(xa));
11331161
}
11341162

1163+
static noinline void check_move_max(struct xarray *xa)
1164+
{
1165+
XA_STATE(xas, xa, 0);
1166+
1167+
xa_store_index(xa, ULONG_MAX, GFP_KERNEL);
1168+
rcu_read_lock();
1169+
XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != xa_mk_index(ULONG_MAX));
1170+
XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != NULL);
1171+
rcu_read_unlock();
1172+
1173+
xas_set(&xas, 0);
1174+
rcu_read_lock();
1175+
XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != xa_mk_index(ULONG_MAX));
1176+
xas_pause(&xas);
1177+
XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != NULL);
1178+
rcu_read_unlock();
1179+
1180+
xa_erase_index(xa, ULONG_MAX);
1181+
XA_BUG_ON(xa, !xa_empty(xa));
1182+
}
1183+
11351184
static noinline void check_move_small(struct xarray *xa, unsigned long idx)
11361185
{
11371186
XA_STATE(xas, xa, 0);
@@ -1240,6 +1289,7 @@ static noinline void check_move(struct xarray *xa)
12401289
xa_destroy(xa);
12411290

12421291
check_move_tiny(xa);
1292+
check_move_max(xa);
12431293

12441294
for (i = 0; i < 16; i++)
12451295
check_move_small(xa, 1UL << i);

0 commit comments

Comments
 (0)