aboutsummaryrefslogtreecommitdiffstats
path: root/lib/xarray.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/xarray.c')
-rw-r--r--lib/xarray.c88
1 files changed, 84 insertions, 4 deletions
diff --git a/lib/xarray.c b/lib/xarray.c
index 546461914282..9a0d49d4b5f0 100644
--- a/lib/xarray.c
+++ b/lib/xarray.c
@@ -52,6 +52,11 @@ static inline void xas_unlock_type(struct xa_state *xas, unsigned int lock_type)
52 xas_unlock(xas); 52 xas_unlock(xas);
53} 53}
54 54
55static inline bool xa_track_free(const struct xarray *xa)
56{
57 return xa->xa_flags & XA_FLAGS_TRACK_FREE;
58}
59
55static inline void xa_mark_set(struct xarray *xa, xa_mark_t mark) 60static inline void xa_mark_set(struct xarray *xa, xa_mark_t mark)
56{ 61{
57 if (!(xa->xa_flags & XA_FLAGS_MARK(mark))) 62 if (!(xa->xa_flags & XA_FLAGS_MARK(mark)))
@@ -94,6 +99,11 @@ static inline bool node_any_mark(struct xa_node *node, xa_mark_t mark)
94 return !bitmap_empty(node_marks(node, mark), XA_CHUNK_SIZE); 99 return !bitmap_empty(node_marks(node, mark), XA_CHUNK_SIZE);
95} 100}
96 101
102static inline void node_mark_all(struct xa_node *node, xa_mark_t mark)
103{
104 bitmap_fill(node_marks(node, mark), XA_CHUNK_SIZE);
105}
106
97#define mark_inc(mark) do { \ 107#define mark_inc(mark) do { \
98 mark = (__force xa_mark_t)((__force unsigned)(mark) + 1); \ 108 mark = (__force xa_mark_t)((__force unsigned)(mark) + 1); \
99} while (0) 109} while (0)
@@ -416,6 +426,8 @@ static void xas_shrink(struct xa_state *xas)
416 xas->xa_node = XAS_BOUNDS; 426 xas->xa_node = XAS_BOUNDS;
417 427
418 RCU_INIT_POINTER(xa->xa_head, entry); 428 RCU_INIT_POINTER(xa->xa_head, entry);
429 if (xa_track_free(xa) && !node_get_mark(node, 0, XA_FREE_MARK))
430 xa_mark_clear(xa, XA_FREE_MARK);
419 431
420 node->count = 0; 432 node->count = 0;
421 node->nr_values = 0; 433 node->nr_values = 0;
@@ -549,8 +561,15 @@ static int xas_expand(struct xa_state *xas, void *head)
549 561
550 /* Propagate the aggregated mark info to the new child */ 562 /* Propagate the aggregated mark info to the new child */
551 for (;;) { 563 for (;;) {
552 if (xa_marked(xa, mark)) 564 if (xa_track_free(xa) && mark == XA_FREE_MARK) {
565 node_mark_all(node, XA_FREE_MARK);
566 if (!xa_marked(xa, XA_FREE_MARK)) {
567 node_clear_mark(node, 0, XA_FREE_MARK);
568 xa_mark_set(xa, XA_FREE_MARK);
569 }
570 } else if (xa_marked(xa, mark)) {
553 node_set_mark(node, 0, mark); 571 node_set_mark(node, 0, mark);
572 }
554 if (mark == XA_MARK_MAX) 573 if (mark == XA_MARK_MAX)
555 break; 574 break;
556 mark_inc(mark); 575 mark_inc(mark);
@@ -624,6 +643,8 @@ static void *xas_create(struct xa_state *xas)
624 node = xas_alloc(xas, shift); 643 node = xas_alloc(xas, shift);
625 if (!node) 644 if (!node)
626 break; 645 break;
646 if (xa_track_free(xa))
647 node_mark_all(node, XA_FREE_MARK);
627 rcu_assign_pointer(*slot, xa_mk_node(node)); 648 rcu_assign_pointer(*slot, xa_mk_node(node));
628 } else if (xa_is_node(entry)) { 649 } else if (xa_is_node(entry)) {
629 node = xa_to_node(entry); 650 node = xa_to_node(entry);
@@ -882,7 +903,10 @@ void xas_init_marks(const struct xa_state *xas)
882 xa_mark_t mark = 0; 903 xa_mark_t mark = 0;
883 904
884 for (;;) { 905 for (;;) {
885 xas_clear_mark(xas, mark); 906 if (xa_track_free(xas->xa) && mark == XA_FREE_MARK)
907 xas_set_mark(xas, mark);
908 else
909 xas_clear_mark(xas, mark);
886 if (mark == XA_MARK_MAX) 910 if (mark == XA_MARK_MAX)
887 break; 911 break;
888 mark_inc(mark); 912 mark_inc(mark);
@@ -1333,6 +1357,8 @@ void *xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp)
1333 do { 1357 do {
1334 xas_lock(&xas); 1358 xas_lock(&xas);
1335 curr = xas_store(&xas, entry); 1359 curr = xas_store(&xas, entry);
1360 if (xa_track_free(xa) && entry)
1361 xas_clear_mark(&xas, XA_FREE_MARK);
1336 xas_unlock(&xas); 1362 xas_unlock(&xas);
1337 } while (xas_nomem(&xas, gfp)); 1363 } while (xas_nomem(&xas, gfp));
1338 1364
@@ -1365,6 +1391,8 @@ void *__xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp)
1365 1391
1366 do { 1392 do {
1367 curr = xas_store(&xas, entry); 1393 curr = xas_store(&xas, entry);
1394 if (xa_track_free(xa) && entry)
1395 xas_clear_mark(&xas, XA_FREE_MARK);
1368 } while (__xas_nomem(&xas, gfp)); 1396 } while (__xas_nomem(&xas, gfp));
1369 1397
1370 return xas_result(&xas, curr); 1398 return xas_result(&xas, curr);
@@ -1400,8 +1428,11 @@ void *xa_cmpxchg(struct xarray *xa, unsigned long index,
1400 curr = xas_load(&xas); 1428 curr = xas_load(&xas);
1401 if (curr == XA_ZERO_ENTRY) 1429 if (curr == XA_ZERO_ENTRY)
1402 curr = NULL; 1430 curr = NULL;
1403 if (curr == old) 1431 if (curr == old) {
1404 xas_store(&xas, entry); 1432 xas_store(&xas, entry);
1433 if (xa_track_free(xa) && entry)
1434 xas_clear_mark(&xas, XA_FREE_MARK);
1435 }
1405 xas_unlock(&xas); 1436 xas_unlock(&xas);
1406 } while (xas_nomem(&xas, gfp)); 1437 } while (xas_nomem(&xas, gfp));
1407 1438
@@ -1438,8 +1469,11 @@ void *__xa_cmpxchg(struct xarray *xa, unsigned long index,
1438 curr = xas_load(&xas); 1469 curr = xas_load(&xas);
1439 if (curr == XA_ZERO_ENTRY) 1470 if (curr == XA_ZERO_ENTRY)
1440 curr = NULL; 1471 curr = NULL;
1441 if (curr == old) 1472 if (curr == old) {
1442 xas_store(&xas, entry); 1473 xas_store(&xas, entry);
1474 if (xa_track_free(xa) && entry)
1475 xas_clear_mark(&xas, XA_FREE_MARK);
1476 }
1443 } while (__xas_nomem(&xas, gfp)); 1477 } while (__xas_nomem(&xas, gfp));
1444 1478
1445 return xas_result(&xas, curr); 1479 return xas_result(&xas, curr);
@@ -1484,6 +1518,52 @@ int xa_reserve(struct xarray *xa, unsigned long index, gfp_t gfp)
1484EXPORT_SYMBOL(xa_reserve); 1518EXPORT_SYMBOL(xa_reserve);
1485 1519
1486/** 1520/**
1521 * __xa_alloc() - Find somewhere to store this entry in the XArray.
1522 * @xa: XArray.
1523 * @id: Pointer to ID.
1524 * @max: Maximum ID to allocate (inclusive).
1525 * @entry: New entry.
1526 * @gfp: Memory allocation flags.
1527 *
1528 * Allocates an unused ID in the range specified by @id and @max.
1529 * Updates the @id pointer with the index, then stores the entry at that
1530 * index. A concurrent lookup will not see an uninitialised @id.
1531 *
1532 * Context: Any context. Expects xa_lock to be held on entry. May
1533 * release and reacquire xa_lock if @gfp flags permit.
1534 * Return: 0 on success, -ENOMEM if memory allocation fails or -ENOSPC if
1535 * there is no more space in the XArray.
1536 */
1537int __xa_alloc(struct xarray *xa, u32 *id, u32 max, void *entry, gfp_t gfp)
1538{
1539 XA_STATE(xas, xa, 0);
1540 int err;
1541
1542 if (WARN_ON_ONCE(xa_is_internal(entry)))
1543 return -EINVAL;
1544 if (WARN_ON_ONCE(!xa_track_free(xa)))
1545 return -EINVAL;
1546
1547 if (!entry)
1548 entry = XA_ZERO_ENTRY;
1549
1550 do {
1551 xas.xa_index = *id;
1552 xas_find_marked(&xas, max, XA_FREE_MARK);
1553 if (xas.xa_node == XAS_RESTART)
1554 xas_set_err(&xas, -ENOSPC);
1555 xas_store(&xas, entry);
1556 xas_clear_mark(&xas, XA_FREE_MARK);
1557 } while (__xas_nomem(&xas, gfp));
1558
1559 err = xas_error(&xas);
1560 if (!err)
1561 *id = xas.xa_index;
1562 return err;
1563}
1564EXPORT_SYMBOL(__xa_alloc);
1565
1566/**
1487 * __xa_set_mark() - Set this mark on this entry while locked. 1567 * __xa_set_mark() - Set this mark on this entry while locked.
1488 * @xa: XArray. 1568 * @xa: XArray.
1489 * @index: Index of entry. 1569 * @index: Index of entry.