aboutsummaryrefslogtreecommitdiffstats
path: root/lib/xarray.c
diff options
context:
space:
mode:
authorMatthew Wilcox <willy@infradead.org>2017-11-10 09:34:31 -0500
committerMatthew Wilcox <willy@infradead.org>2018-10-21 10:45:57 -0400
commit9b89a0355144685a787b0dc5bcf7bdd6f2d02968 (patch)
tree5e9d4f434e638313df1f9d96c145097b9897d122 /lib/xarray.c
parentad3d6c7263e368abdc151e1cc13dc78aa39cc7a7 (diff)
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>
Diffstat (limited to 'lib/xarray.c')
-rw-r--r--lib/xarray.c232
1 files changed, 230 insertions, 2 deletions
diff --git a/lib/xarray.c b/lib/xarray.c
index 19cfcbc69a68..aa86c47e532f 100644
--- a/lib/xarray.c
+++ b/lib/xarray.c
@@ -5,6 +5,7 @@
5 * Author: Matthew Wilcox <willy@infradead.org> 5 * Author: Matthew Wilcox <willy@infradead.org>
6 */ 6 */
7 7
8#include <linux/bitmap.h>
8#include <linux/export.h> 9#include <linux/export.h>
9#include <linux/xarray.h> 10#include <linux/xarray.h>
10 11
@@ -24,6 +25,48 @@
24 * @entry refers to something stored in a slot in the xarray 25 * @entry refers to something stored in a slot in the xarray
25 */ 26 */
26 27
28static inline void xa_mark_set(struct xarray *xa, xa_mark_t mark)
29{
30 if (!(xa->xa_flags & XA_FLAGS_MARK(mark)))
31 xa->xa_flags |= XA_FLAGS_MARK(mark);
32}
33
34static inline void xa_mark_clear(struct xarray *xa, xa_mark_t mark)
35{
36 if (xa->xa_flags & XA_FLAGS_MARK(mark))
37 xa->xa_flags &= ~(XA_FLAGS_MARK(mark));
38}
39
40static inline unsigned long *node_marks(struct xa_node *node, xa_mark_t mark)
41{
42 return node->marks[(__force unsigned)mark];
43}
44
45static inline bool node_get_mark(struct xa_node *node,
46 unsigned int offset, xa_mark_t mark)
47{
48 return test_bit(offset, node_marks(node, mark));
49}
50
51/* returns true if the bit was set */
52static inline bool node_set_mark(struct xa_node *node, unsigned int offset,
53 xa_mark_t mark)
54{
55 return __test_and_set_bit(offset, node_marks(node, mark));
56}
57
58/* returns true if the bit was set */
59static inline bool node_clear_mark(struct xa_node *node, unsigned int offset,
60 xa_mark_t mark)
61{
62 return __test_and_clear_bit(offset, node_marks(node, mark));
63}
64
65static inline bool node_any_mark(struct xa_node *node, xa_mark_t mark)
66{
67 return !bitmap_empty(node_marks(node, mark), XA_CHUNK_SIZE);
68}
69
27/* extracts the offset within this node from the index */ 70/* extracts the offset within this node from the index */
28static unsigned int get_offset(unsigned long index, struct xa_node *node) 71static unsigned int get_offset(unsigned long index, struct xa_node *node)
29{ 72{
@@ -119,6 +162,85 @@ void *xas_load(struct xa_state *xas)
119EXPORT_SYMBOL_GPL(xas_load); 162EXPORT_SYMBOL_GPL(xas_load);
120 163
121/** 164/**
165 * xas_get_mark() - Returns the state of this mark.
166 * @xas: XArray operation state.
167 * @mark: Mark number.
168 *
169 * Return: true if the mark is set, false if the mark is clear or @xas
170 * is in an error state.
171 */
172bool xas_get_mark(const struct xa_state *xas, xa_mark_t mark)
173{
174 if (xas_invalid(xas))
175 return false;
176 if (!xas->xa_node)
177 return xa_marked(xas->xa, mark);
178 return node_get_mark(xas->xa_node, xas->xa_offset, mark);
179}
180EXPORT_SYMBOL_GPL(xas_get_mark);
181
182/**
183 * xas_set_mark() - Sets the mark on this entry and its parents.
184 * @xas: XArray operation state.
185 * @mark: Mark number.
186 *
187 * Sets the specified mark on this entry, and walks up the tree setting it
188 * on all the ancestor entries. Does nothing if @xas has not been walked to
189 * an entry, or is in an error state.
190 */
191void xas_set_mark(const struct xa_state *xas, xa_mark_t mark)
192{
193 struct xa_node *node = xas->xa_node;
194 unsigned int offset = xas->xa_offset;
195
196 if (xas_invalid(xas))
197 return;
198
199 while (node) {
200 if (node_set_mark(node, offset, mark))
201 return;
202 offset = node->offset;
203 node = xa_parent_locked(xas->xa, node);
204 }
205
206 if (!xa_marked(xas->xa, mark))
207 xa_mark_set(xas->xa, mark);
208}
209EXPORT_SYMBOL_GPL(xas_set_mark);
210
211/**
212 * xas_clear_mark() - Clears the mark on this entry and its parents.
213 * @xas: XArray operation state.
214 * @mark: Mark number.
215 *
216 * Clears the specified mark on this entry, and walks back to the head
217 * attempting to clear it on all the ancestor entries. Does nothing if
218 * @xas has not been walked to an entry, or is in an error state.
219 */
220void xas_clear_mark(const struct xa_state *xas, xa_mark_t mark)
221{
222 struct xa_node *node = xas->xa_node;
223 unsigned int offset = xas->xa_offset;
224
225 if (xas_invalid(xas))
226 return;
227
228 while (node) {
229 if (!node_clear_mark(node, offset, mark))
230 return;
231 if (node_any_mark(node, mark))
232 return;
233
234 offset = node->offset;
235 node = xa_parent_locked(xas->xa, node);
236 }
237
238 if (xa_marked(xas->xa, mark))
239 xa_mark_clear(xas->xa, mark);
240}
241EXPORT_SYMBOL_GPL(xas_clear_mark);
242
243/**
122 * xa_init_flags() - Initialise an empty XArray with flags. 244 * xa_init_flags() - Initialise an empty XArray with flags.
123 * @xa: XArray. 245 * @xa: XArray.
124 * @flags: XA_FLAG values. 246 * @flags: XA_FLAG values.
@@ -160,6 +282,112 @@ void *xa_load(struct xarray *xa, unsigned long index)
160} 282}
161EXPORT_SYMBOL(xa_load); 283EXPORT_SYMBOL(xa_load);
162 284
285/**
286 * __xa_set_mark() - Set this mark on this entry while locked.
287 * @xa: XArray.
288 * @index: Index of entry.
289 * @mark: Mark number.
290 *
291 * Attempting to set a mark on a NULL entry does not succeed.
292 *
293 * Context: Any context. Expects xa_lock to be held on entry.
294 */
295void __xa_set_mark(struct xarray *xa, unsigned long index, xa_mark_t mark)
296{
297 XA_STATE(xas, xa, index);
298 void *entry = xas_load(&xas);
299
300 if (entry)
301 xas_set_mark(&xas, mark);
302}
303EXPORT_SYMBOL_GPL(__xa_set_mark);
304
305/**
306 * __xa_clear_mark() - Clear this mark on this entry while locked.
307 * @xa: XArray.
308 * @index: Index of entry.
309 * @mark: Mark number.
310 *
311 * Context: Any context. Expects xa_lock to be held on entry.
312 */
313void __xa_clear_mark(struct xarray *xa, unsigned long index, xa_mark_t mark)
314{
315 XA_STATE(xas, xa, index);
316 void *entry = xas_load(&xas);
317
318 if (entry)
319 xas_clear_mark(&xas, mark);
320}
321EXPORT_SYMBOL_GPL(__xa_clear_mark);
322
323/**
324 * xa_get_mark() - Inquire whether this mark is set on this entry.
325 * @xa: XArray.
326 * @index: Index of entry.
327 * @mark: Mark number.
328 *
329 * This function uses the RCU read lock, so the result may be out of date
330 * by the time it returns. If you need the result to be stable, use a lock.
331 *
332 * Context: Any context. Takes and releases the RCU lock.
333 * Return: True if the entry at @index has this mark set, false if it doesn't.
334 */
335bool xa_get_mark(struct xarray *xa, unsigned long index, xa_mark_t mark)
336{
337 XA_STATE(xas, xa, index);
338 void *entry;
339
340 rcu_read_lock();
341 entry = xas_start(&xas);
342 while (xas_get_mark(&xas, mark)) {
343 if (!xa_is_node(entry))
344 goto found;
345 entry = xas_descend(&xas, xa_to_node(entry));
346 }
347 rcu_read_unlock();
348 return false;
349 found:
350 rcu_read_unlock();
351 return true;
352}
353EXPORT_SYMBOL(xa_get_mark);
354
355/**
356 * xa_set_mark() - Set this mark on this entry.
357 * @xa: XArray.
358 * @index: Index of entry.
359 * @mark: Mark number.
360 *
361 * Attempting to set a mark on a NULL entry does not succeed.
362 *
363 * Context: Process context. Takes and releases the xa_lock.
364 */
365void xa_set_mark(struct xarray *xa, unsigned long index, xa_mark_t mark)
366{
367 xa_lock(xa);
368 __xa_set_mark(xa, index, mark);
369 xa_unlock(xa);
370}
371EXPORT_SYMBOL(xa_set_mark);
372
373/**
374 * xa_clear_mark() - Clear this mark on this entry.
375 * @xa: XArray.
376 * @index: Index of entry.
377 * @mark: Mark number.
378 *
379 * Clearing a mark always succeeds.
380 *
381 * Context: Process context. Takes and releases the xa_lock.
382 */
383void xa_clear_mark(struct xarray *xa, unsigned long index, xa_mark_t mark)
384{
385 xa_lock(xa);
386 __xa_clear_mark(xa, index, mark);
387 xa_unlock(xa);
388}
389EXPORT_SYMBOL(xa_clear_mark);
390
163#ifdef XA_DEBUG 391#ifdef XA_DEBUG
164void xa_dump_node(const struct xa_node *node) 392void xa_dump_node(const struct xa_node *node)
165{ 393{
@@ -230,8 +458,8 @@ void xa_dump(const struct xarray *xa)
230 unsigned int shift = 0; 458 unsigned int shift = 0;
231 459
232 pr_info("xarray: %px head %px flags %x marks %d %d %d\n", xa, entry, 460 pr_info("xarray: %px head %px flags %x marks %d %d %d\n", xa, entry,
233 xa->xa_flags, radix_tree_tagged(xa, 0), 461 xa->xa_flags, xa_marked(xa, XA_MARK_0),
234 radix_tree_tagged(xa, 1), radix_tree_tagged(xa, 2)); 462 xa_marked(xa, XA_MARK_1), xa_marked(xa, XA_MARK_2));
235 if (xa_is_node(entry)) 463 if (xa_is_node(entry))
236 shift = xa_to_node(entry)->shift + XA_CHUNK_SHIFT; 464 shift = xa_to_node(entry)->shift + XA_CHUNK_SHIFT;
237 xa_dump_entry(entry, 0, shift); 465 xa_dump_entry(entry, 0, shift);