diff options
Diffstat (limited to 'lib/xarray.c')
| -rw-r--r-- | lib/xarray.c | 163 |
1 files changed, 92 insertions, 71 deletions
diff --git a/lib/xarray.c b/lib/xarray.c index 81c3171ddde9..6be3acbb861f 100644 --- a/lib/xarray.c +++ b/lib/xarray.c | |||
| @@ -57,6 +57,11 @@ static inline bool xa_track_free(const struct xarray *xa) | |||
| 57 | return xa->xa_flags & XA_FLAGS_TRACK_FREE; | 57 | return xa->xa_flags & XA_FLAGS_TRACK_FREE; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | static inline bool xa_zero_busy(const struct xarray *xa) | ||
| 61 | { | ||
| 62 | return xa->xa_flags & XA_FLAGS_ZERO_BUSY; | ||
| 63 | } | ||
| 64 | |||
| 60 | static inline void xa_mark_set(struct xarray *xa, xa_mark_t mark) | 65 | static inline void xa_mark_set(struct xarray *xa, xa_mark_t mark) |
| 61 | { | 66 | { |
| 62 | if (!(xa->xa_flags & XA_FLAGS_MARK(mark))) | 67 | if (!(xa->xa_flags & XA_FLAGS_MARK(mark))) |
| @@ -432,6 +437,8 @@ static void xas_shrink(struct xa_state *xas) | |||
| 432 | break; | 437 | break; |
| 433 | if (!xa_is_node(entry) && node->shift) | 438 | if (!xa_is_node(entry) && node->shift) |
| 434 | break; | 439 | break; |
| 440 | if (xa_is_zero(entry) && xa_zero_busy(xa)) | ||
| 441 | entry = NULL; | ||
| 435 | xas->xa_node = XAS_BOUNDS; | 442 | xas->xa_node = XAS_BOUNDS; |
| 436 | 443 | ||
| 437 | RCU_INIT_POINTER(xa->xa_head, entry); | 444 | RCU_INIT_POINTER(xa->xa_head, entry); |
| @@ -628,6 +635,8 @@ static void *xas_create(struct xa_state *xas, bool allow_root) | |||
| 628 | if (xas_top(node)) { | 635 | if (xas_top(node)) { |
| 629 | entry = xa_head_locked(xa); | 636 | entry = xa_head_locked(xa); |
| 630 | xas->xa_node = NULL; | 637 | xas->xa_node = NULL; |
| 638 | if (!entry && xa_zero_busy(xa)) | ||
| 639 | entry = XA_ZERO_ENTRY; | ||
| 631 | shift = xas_expand(xas, entry); | 640 | shift = xas_expand(xas, entry); |
| 632 | if (shift < 0) | 641 | if (shift < 0) |
| 633 | return NULL; | 642 | return NULL; |
| @@ -758,10 +767,12 @@ void *xas_store(struct xa_state *xas, void *entry) | |||
| 758 | void *first, *next; | 767 | void *first, *next; |
| 759 | bool value = xa_is_value(entry); | 768 | bool value = xa_is_value(entry); |
| 760 | 769 | ||
| 761 | if (entry) | 770 | if (entry) { |
| 762 | first = xas_create(xas, !xa_is_node(entry)); | 771 | bool allow_root = !xa_is_node(entry) && !xa_is_zero(entry); |
| 763 | else | 772 | first = xas_create(xas, allow_root); |
| 773 | } else { | ||
| 764 | first = xas_load(xas); | 774 | first = xas_load(xas); |
| 775 | } | ||
| 765 | 776 | ||
| 766 | if (xas_invalid(xas)) | 777 | if (xas_invalid(xas)) |
| 767 | return first; | 778 | return first; |
| @@ -791,7 +802,7 @@ void *xas_store(struct xa_state *xas, void *entry) | |||
| 791 | * entry is set to NULL. | 802 | * entry is set to NULL. |
| 792 | */ | 803 | */ |
| 793 | rcu_assign_pointer(*slot, entry); | 804 | rcu_assign_pointer(*slot, entry); |
| 794 | if (xa_is_node(next)) | 805 | if (xa_is_node(next) && (!node || node->shift)) |
| 795 | xas_free_nodes(xas, xa_to_node(next)); | 806 | xas_free_nodes(xas, xa_to_node(next)); |
| 796 | if (!node) | 807 | if (!node) |
| 797 | break; | 808 | break; |
| @@ -1294,13 +1305,12 @@ static void *xas_result(struct xa_state *xas, void *curr) | |||
| 1294 | * @xa: XArray. | 1305 | * @xa: XArray. |
| 1295 | * @index: Index into array. | 1306 | * @index: Index into array. |
| 1296 | * | 1307 | * |
| 1297 | * If the entry at this index is a multi-index entry then all indices will | 1308 | * After this function returns, loading from @index will return %NULL. |
| 1298 | * be erased, and the entry will no longer be a multi-index entry. | 1309 | * If the index is part of a multi-index entry, all indices will be erased |
| 1299 | * This function expects the xa_lock to be held on entry. | 1310 | * and none of the entries will be part of a multi-index entry. |
| 1300 | * | 1311 | * |
| 1301 | * Context: Any context. Expects xa_lock to be held on entry. May | 1312 | * Context: Any context. Expects xa_lock to be held on entry. |
| 1302 | * release and reacquire xa_lock if @gfp flags permit. | 1313 | * Return: The entry which used to be at this index. |
| 1303 | * Return: The old entry at this index. | ||
| 1304 | */ | 1314 | */ |
| 1305 | void *__xa_erase(struct xarray *xa, unsigned long index) | 1315 | void *__xa_erase(struct xarray *xa, unsigned long index) |
| 1306 | { | 1316 | { |
| @@ -1314,9 +1324,9 @@ EXPORT_SYMBOL(__xa_erase); | |||
| 1314 | * @xa: XArray. | 1324 | * @xa: XArray. |
| 1315 | * @index: Index of entry. | 1325 | * @index: Index of entry. |
| 1316 | * | 1326 | * |
| 1317 | * This function is the equivalent of calling xa_store() with %NULL as | 1327 | * After this function returns, loading from @index will return %NULL. |
| 1318 | * the third argument. The XArray does not need to allocate memory, so | 1328 | * If the index is part of a multi-index entry, all indices will be erased |
| 1319 | * the user does not need to provide GFP flags. | 1329 | * and none of the entries will be part of a multi-index entry. |
| 1320 | * | 1330 | * |
| 1321 | * Context: Any context. Takes and releases the xa_lock. | 1331 | * Context: Any context. Takes and releases the xa_lock. |
| 1322 | * Return: The entry which used to be at this index. | 1332 | * Return: The entry which used to be at this index. |
| @@ -1421,16 +1431,12 @@ void *__xa_cmpxchg(struct xarray *xa, unsigned long index, | |||
| 1421 | 1431 | ||
| 1422 | if (WARN_ON_ONCE(xa_is_advanced(entry))) | 1432 | if (WARN_ON_ONCE(xa_is_advanced(entry))) |
| 1423 | return XA_ERROR(-EINVAL); | 1433 | return XA_ERROR(-EINVAL); |
| 1424 | if (xa_track_free(xa) && !entry) | ||
| 1425 | entry = XA_ZERO_ENTRY; | ||
| 1426 | 1434 | ||
| 1427 | do { | 1435 | do { |
| 1428 | curr = xas_load(&xas); | 1436 | curr = xas_load(&xas); |
| 1429 | if (curr == XA_ZERO_ENTRY) | ||
| 1430 | curr = NULL; | ||
| 1431 | if (curr == old) { | 1437 | if (curr == old) { |
| 1432 | xas_store(&xas, entry); | 1438 | xas_store(&xas, entry); |
| 1433 | if (xa_track_free(xa)) | 1439 | if (xa_track_free(xa) && entry && !curr) |
| 1434 | xas_clear_mark(&xas, XA_FREE_MARK); | 1440 | xas_clear_mark(&xas, XA_FREE_MARK); |
| 1435 | } | 1441 | } |
| 1436 | } while (__xas_nomem(&xas, gfp)); | 1442 | } while (__xas_nomem(&xas, gfp)); |
| @@ -1452,7 +1458,7 @@ EXPORT_SYMBOL(__xa_cmpxchg); | |||
| 1452 | * | 1458 | * |
| 1453 | * Context: Any context. Expects xa_lock to be held on entry. May | 1459 | * Context: Any context. Expects xa_lock to be held on entry. May |
| 1454 | * release and reacquire xa_lock if @gfp flags permit. | 1460 | * release and reacquire xa_lock if @gfp flags permit. |
| 1455 | * Return: 0 if the store succeeded. -EEXIST if another entry was present. | 1461 | * Return: 0 if the store succeeded. -EBUSY if another entry was present. |
| 1456 | * -ENOMEM if memory could not be allocated. | 1462 | * -ENOMEM if memory could not be allocated. |
| 1457 | */ | 1463 | */ |
| 1458 | int __xa_insert(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp) | 1464 | int __xa_insert(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp) |
| @@ -1472,7 +1478,7 @@ int __xa_insert(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp) | |||
| 1472 | if (xa_track_free(xa)) | 1478 | if (xa_track_free(xa)) |
| 1473 | xas_clear_mark(&xas, XA_FREE_MARK); | 1479 | xas_clear_mark(&xas, XA_FREE_MARK); |
| 1474 | } else { | 1480 | } else { |
| 1475 | xas_set_err(&xas, -EEXIST); | 1481 | xas_set_err(&xas, -EBUSY); |
| 1476 | } | 1482 | } |
| 1477 | } while (__xas_nomem(&xas, gfp)); | 1483 | } while (__xas_nomem(&xas, gfp)); |
| 1478 | 1484 | ||
| @@ -1480,42 +1486,6 @@ int __xa_insert(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp) | |||
| 1480 | } | 1486 | } |
| 1481 | EXPORT_SYMBOL(__xa_insert); | 1487 | EXPORT_SYMBOL(__xa_insert); |
| 1482 | 1488 | ||
| 1483 | /** | ||
| 1484 | * __xa_reserve() - Reserve this index in the XArray. | ||
| 1485 | * @xa: XArray. | ||
| 1486 | * @index: Index into array. | ||
| 1487 | * @gfp: Memory allocation flags. | ||
| 1488 | * | ||
| 1489 | * Ensures there is somewhere to store an entry at @index in the array. | ||
| 1490 | * If there is already something stored at @index, this function does | ||
| 1491 | * nothing. If there was nothing there, the entry is marked as reserved. | ||
| 1492 | * Loading from a reserved entry returns a %NULL pointer. | ||
| 1493 | * | ||
| 1494 | * If you do not use the entry that you have reserved, call xa_release() | ||
| 1495 | * or xa_erase() to free any unnecessary memory. | ||
| 1496 | * | ||
| 1497 | * Context: Any context. Expects the xa_lock to be held on entry. May | ||
| 1498 | * release the lock, sleep and reacquire the lock if the @gfp flags permit. | ||
| 1499 | * Return: 0 if the reservation succeeded or -ENOMEM if it failed. | ||
| 1500 | */ | ||
| 1501 | int __xa_reserve(struct xarray *xa, unsigned long index, gfp_t gfp) | ||
| 1502 | { | ||
| 1503 | XA_STATE(xas, xa, index); | ||
| 1504 | void *curr; | ||
| 1505 | |||
| 1506 | do { | ||
| 1507 | curr = xas_load(&xas); | ||
| 1508 | if (!curr) { | ||
| 1509 | xas_store(&xas, XA_ZERO_ENTRY); | ||
| 1510 | if (xa_track_free(xa)) | ||
| 1511 | xas_clear_mark(&xas, XA_FREE_MARK); | ||
| 1512 | } | ||
| 1513 | } while (__xas_nomem(&xas, gfp)); | ||
| 1514 | |||
| 1515 | return xas_error(&xas); | ||
| 1516 | } | ||
| 1517 | EXPORT_SYMBOL(__xa_reserve); | ||
| 1518 | |||
| 1519 | #ifdef CONFIG_XARRAY_MULTI | 1489 | #ifdef CONFIG_XARRAY_MULTI |
| 1520 | static void xas_set_range(struct xa_state *xas, unsigned long first, | 1490 | static void xas_set_range(struct xa_state *xas, unsigned long first, |
| 1521 | unsigned long last) | 1491 | unsigned long last) |
| @@ -1607,23 +1577,23 @@ EXPORT_SYMBOL(xa_store_range); | |||
| 1607 | * __xa_alloc() - Find somewhere to store this entry in the XArray. | 1577 | * __xa_alloc() - Find somewhere to store this entry in the XArray. |
| 1608 | * @xa: XArray. | 1578 | * @xa: XArray. |
| 1609 | * @id: Pointer to ID. | 1579 | * @id: Pointer to ID. |
| 1610 | * @max: Maximum ID to allocate (inclusive). | 1580 | * @limit: Range for allocated ID. |
| 1611 | * @entry: New entry. | 1581 | * @entry: New entry. |
| 1612 | * @gfp: Memory allocation flags. | 1582 | * @gfp: Memory allocation flags. |
| 1613 | * | 1583 | * |
| 1614 | * Allocates an unused ID in the range specified by @id and @max. | 1584 | * Finds an empty entry in @xa between @limit.min and @limit.max, |
| 1615 | * Updates the @id pointer with the index, then stores the entry at that | 1585 | * stores the index into the @id pointer, then stores the entry at |
| 1616 | * index. A concurrent lookup will not see an uninitialised @id. | 1586 | * that index. A concurrent lookup will not see an uninitialised @id. |
| 1617 | * | 1587 | * |
| 1618 | * Context: Any context. Expects xa_lock to be held on entry. May | 1588 | * Context: Any context. Expects xa_lock to be held on entry. May |
| 1619 | * release and reacquire xa_lock if @gfp flags permit. | 1589 | * release and reacquire xa_lock if @gfp flags permit. |
| 1620 | * Return: 0 on success, -ENOMEM if memory allocation fails or -ENOSPC if | 1590 | * Return: 0 on success, -ENOMEM if memory could not be allocated or |
| 1621 | * there is no more space in the XArray. | 1591 | * -EBUSY if there are no free entries in @limit. |
| 1622 | */ | 1592 | */ |
| 1623 | int __xa_alloc(struct xarray *xa, u32 *id, u32 max, void *entry, gfp_t gfp) | 1593 | int __xa_alloc(struct xarray *xa, u32 *id, void *entry, |
| 1594 | struct xa_limit limit, gfp_t gfp) | ||
| 1624 | { | 1595 | { |
| 1625 | XA_STATE(xas, xa, 0); | 1596 | XA_STATE(xas, xa, 0); |
| 1626 | int err; | ||
| 1627 | 1597 | ||
| 1628 | if (WARN_ON_ONCE(xa_is_advanced(entry))) | 1598 | if (WARN_ON_ONCE(xa_is_advanced(entry))) |
| 1629 | return -EINVAL; | 1599 | return -EINVAL; |
| @@ -1634,22 +1604,71 @@ int __xa_alloc(struct xarray *xa, u32 *id, u32 max, void *entry, gfp_t gfp) | |||
| 1634 | entry = XA_ZERO_ENTRY; | 1604 | entry = XA_ZERO_ENTRY; |
| 1635 | 1605 | ||
| 1636 | do { | 1606 | do { |
| 1637 | xas.xa_index = *id; | 1607 | xas.xa_index = limit.min; |
| 1638 | xas_find_marked(&xas, max, XA_FREE_MARK); | 1608 | xas_find_marked(&xas, limit.max, XA_FREE_MARK); |
| 1639 | if (xas.xa_node == XAS_RESTART) | 1609 | if (xas.xa_node == XAS_RESTART) |
| 1640 | xas_set_err(&xas, -ENOSPC); | 1610 | xas_set_err(&xas, -EBUSY); |
| 1611 | else | ||
| 1612 | *id = xas.xa_index; | ||
| 1641 | xas_store(&xas, entry); | 1613 | xas_store(&xas, entry); |
| 1642 | xas_clear_mark(&xas, XA_FREE_MARK); | 1614 | xas_clear_mark(&xas, XA_FREE_MARK); |
| 1643 | } while (__xas_nomem(&xas, gfp)); | 1615 | } while (__xas_nomem(&xas, gfp)); |
| 1644 | 1616 | ||
| 1645 | err = xas_error(&xas); | 1617 | return xas_error(&xas); |
| 1646 | if (!err) | ||
| 1647 | *id = xas.xa_index; | ||
| 1648 | return err; | ||
| 1649 | } | 1618 | } |
| 1650 | EXPORT_SYMBOL(__xa_alloc); | 1619 | EXPORT_SYMBOL(__xa_alloc); |
| 1651 | 1620 | ||
| 1652 | /** | 1621 | /** |
| 1622 | * __xa_alloc_cyclic() - Find somewhere to store this entry in the XArray. | ||
| 1623 | * @xa: XArray. | ||
| 1624 | * @id: Pointer to ID. | ||
| 1625 | * @entry: New entry. | ||
| 1626 | * @limit: Range of allocated ID. | ||
| 1627 | * @next: Pointer to next ID to allocate. | ||
| 1628 | * @gfp: Memory allocation flags. | ||
| 1629 | * | ||
| 1630 | * Finds an empty entry in @xa between @limit.min and @limit.max, | ||
| 1631 | * stores the index into the @id pointer, then stores the entry at | ||
| 1632 | * that index. A concurrent lookup will not see an uninitialised @id. | ||
| 1633 | * The search for an empty entry will start at @next and will wrap | ||
| 1634 | * around if necessary. | ||
| 1635 | * | ||
| 1636 | * Context: Any context. Expects xa_lock to be held on entry. May | ||
| 1637 | * release and reacquire xa_lock if @gfp flags permit. | ||
| 1638 | * Return: 0 if the allocation succeeded without wrapping. 1 if the | ||
| 1639 | * allocation succeeded after wrapping, -ENOMEM if memory could not be | ||
| 1640 | * allocated or -EBUSY if there are no free entries in @limit. | ||
| 1641 | */ | ||
| 1642 | int __xa_alloc_cyclic(struct xarray *xa, u32 *id, void *entry, | ||
| 1643 | struct xa_limit limit, u32 *next, gfp_t gfp) | ||
| 1644 | { | ||
| 1645 | u32 min = limit.min; | ||
| 1646 | int ret; | ||
| 1647 | |||
| 1648 | limit.min = max(min, *next); | ||
| 1649 | ret = __xa_alloc(xa, id, entry, limit, gfp); | ||
| 1650 | if ((xa->xa_flags & XA_FLAGS_ALLOC_WRAPPED) && ret == 0) { | ||
| 1651 | xa->xa_flags &= ~XA_FLAGS_ALLOC_WRAPPED; | ||
| 1652 | ret = 1; | ||
| 1653 | } | ||
| 1654 | |||
| 1655 | if (ret < 0 && limit.min > min) { | ||
| 1656 | limit.min = min; | ||
| 1657 | ret = __xa_alloc(xa, id, entry, limit, gfp); | ||
| 1658 | if (ret == 0) | ||
| 1659 | ret = 1; | ||
| 1660 | } | ||
| 1661 | |||
| 1662 | if (ret >= 0) { | ||
| 1663 | *next = *id + 1; | ||
| 1664 | if (*next == 0) | ||
| 1665 | xa->xa_flags |= XA_FLAGS_ALLOC_WRAPPED; | ||
| 1666 | } | ||
| 1667 | return ret; | ||
| 1668 | } | ||
| 1669 | EXPORT_SYMBOL(__xa_alloc_cyclic); | ||
| 1670 | |||
| 1671 | /** | ||
| 1653 | * __xa_set_mark() - Set this mark on this entry while locked. | 1672 | * __xa_set_mark() - Set this mark on this entry while locked. |
| 1654 | * @xa: XArray. | 1673 | * @xa: XArray. |
| 1655 | * @index: Index of entry. | 1674 | * @index: Index of entry. |
| @@ -1943,6 +1962,8 @@ void xa_destroy(struct xarray *xa) | |||
| 1943 | entry = xa_head_locked(xa); | 1962 | entry = xa_head_locked(xa); |
| 1944 | RCU_INIT_POINTER(xa->xa_head, NULL); | 1963 | RCU_INIT_POINTER(xa->xa_head, NULL); |
| 1945 | xas_init_marks(&xas); | 1964 | xas_init_marks(&xas); |
| 1965 | if (xa_zero_busy(xa)) | ||
| 1966 | xa_mark_clear(xa, XA_FREE_MARK); | ||
| 1946 | /* lockdep checks we're still holding the lock in xas_free_nodes() */ | 1967 | /* lockdep checks we're still holding the lock in xas_free_nodes() */ |
| 1947 | if (xa_is_node(entry)) | 1968 | if (xa_is_node(entry)) |
| 1948 | xas_free_nodes(&xas, xa_to_node(entry)); | 1969 | xas_free_nodes(&xas, xa_to_node(entry)); |
