diff options
Diffstat (limited to 'lib/xarray.c')
| -rw-r--r-- | lib/xarray.c | 92 |
1 files changed, 54 insertions, 38 deletions
diff --git a/lib/xarray.c b/lib/xarray.c index 5f3f9311de89..81c3171ddde9 100644 --- a/lib/xarray.c +++ b/lib/xarray.c | |||
| @@ -232,6 +232,8 @@ void *xas_load(struct xa_state *xas) | |||
| 232 | if (xas->xa_shift > node->shift) | 232 | if (xas->xa_shift > node->shift) |
| 233 | break; | 233 | break; |
| 234 | entry = xas_descend(xas, node); | 234 | entry = xas_descend(xas, node); |
| 235 | if (node->shift == 0) | ||
| 236 | break; | ||
| 235 | } | 237 | } |
| 236 | return entry; | 238 | return entry; |
| 237 | } | 239 | } |
| @@ -506,7 +508,7 @@ static void xas_free_nodes(struct xa_state *xas, struct xa_node *top) | |||
| 506 | for (;;) { | 508 | for (;;) { |
| 507 | void *entry = xa_entry_locked(xas->xa, node, offset); | 509 | void *entry = xa_entry_locked(xas->xa, node, offset); |
| 508 | 510 | ||
| 509 | if (xa_is_node(entry)) { | 511 | if (node->shift && xa_is_node(entry)) { |
| 510 | node = xa_to_node(entry); | 512 | node = xa_to_node(entry); |
| 511 | offset = 0; | 513 | offset = 0; |
| 512 | continue; | 514 | continue; |
| @@ -604,6 +606,7 @@ static int xas_expand(struct xa_state *xas, void *head) | |||
| 604 | /* | 606 | /* |
| 605 | * xas_create() - Create a slot to store an entry in. | 607 | * xas_create() - Create a slot to store an entry in. |
| 606 | * @xas: XArray operation state. | 608 | * @xas: XArray operation state. |
| 609 | * @allow_root: %true if we can store the entry in the root directly | ||
| 607 | * | 610 | * |
| 608 | * Most users will not need to call this function directly, as it is called | 611 | * Most users will not need to call this function directly, as it is called |
| 609 | * by xas_store(). It is useful for doing conditional store operations | 612 | * by xas_store(). It is useful for doing conditional store operations |
| @@ -613,7 +616,7 @@ static int xas_expand(struct xa_state *xas, void *head) | |||
| 613 | * If the slot was newly created, returns %NULL. If it failed to create the | 616 | * If the slot was newly created, returns %NULL. If it failed to create the |
| 614 | * slot, returns %NULL and indicates the error in @xas. | 617 | * slot, returns %NULL and indicates the error in @xas. |
| 615 | */ | 618 | */ |
| 616 | static void *xas_create(struct xa_state *xas) | 619 | static void *xas_create(struct xa_state *xas, bool allow_root) |
| 617 | { | 620 | { |
| 618 | struct xarray *xa = xas->xa; | 621 | struct xarray *xa = xas->xa; |
| 619 | void *entry; | 622 | void *entry; |
| @@ -628,6 +631,8 @@ static void *xas_create(struct xa_state *xas) | |||
| 628 | shift = xas_expand(xas, entry); | 631 | shift = xas_expand(xas, entry); |
| 629 | if (shift < 0) | 632 | if (shift < 0) |
| 630 | return NULL; | 633 | return NULL; |
| 634 | if (!shift && !allow_root) | ||
| 635 | shift = XA_CHUNK_SHIFT; | ||
| 631 | entry = xa_head_locked(xa); | 636 | entry = xa_head_locked(xa); |
| 632 | slot = &xa->xa_head; | 637 | slot = &xa->xa_head; |
| 633 | } else if (xas_error(xas)) { | 638 | } else if (xas_error(xas)) { |
| @@ -687,7 +692,7 @@ void xas_create_range(struct xa_state *xas) | |||
| 687 | xas->xa_sibs = 0; | 692 | xas->xa_sibs = 0; |
| 688 | 693 | ||
| 689 | for (;;) { | 694 | for (;;) { |
| 690 | xas_create(xas); | 695 | xas_create(xas, true); |
| 691 | if (xas_error(xas)) | 696 | if (xas_error(xas)) |
| 692 | goto restore; | 697 | goto restore; |
| 693 | if (xas->xa_index <= (index | XA_CHUNK_MASK)) | 698 | if (xas->xa_index <= (index | XA_CHUNK_MASK)) |
| @@ -754,7 +759,7 @@ void *xas_store(struct xa_state *xas, void *entry) | |||
| 754 | bool value = xa_is_value(entry); | 759 | bool value = xa_is_value(entry); |
| 755 | 760 | ||
| 756 | if (entry) | 761 | if (entry) |
| 757 | first = xas_create(xas); | 762 | first = xas_create(xas, !xa_is_node(entry)); |
| 758 | else | 763 | else |
| 759 | first = xas_load(xas); | 764 | first = xas_load(xas); |
| 760 | 765 | ||
| @@ -1251,35 +1256,6 @@ void *xas_find_conflict(struct xa_state *xas) | |||
| 1251 | EXPORT_SYMBOL_GPL(xas_find_conflict); | 1256 | EXPORT_SYMBOL_GPL(xas_find_conflict); |
| 1252 | 1257 | ||
| 1253 | /** | 1258 | /** |
| 1254 | * xa_init_flags() - Initialise an empty XArray with flags. | ||
| 1255 | * @xa: XArray. | ||
| 1256 | * @flags: XA_FLAG values. | ||
| 1257 | * | ||
| 1258 | * If you need to initialise an XArray with special flags (eg you need | ||
| 1259 | * to take the lock from interrupt context), use this function instead | ||
| 1260 | * of xa_init(). | ||
| 1261 | * | ||
| 1262 | * Context: Any context. | ||
| 1263 | */ | ||
| 1264 | void xa_init_flags(struct xarray *xa, gfp_t flags) | ||
| 1265 | { | ||
| 1266 | unsigned int lock_type; | ||
| 1267 | static struct lock_class_key xa_lock_irq; | ||
| 1268 | static struct lock_class_key xa_lock_bh; | ||
| 1269 | |||
| 1270 | spin_lock_init(&xa->xa_lock); | ||
| 1271 | xa->xa_flags = flags; | ||
| 1272 | xa->xa_head = NULL; | ||
| 1273 | |||
| 1274 | lock_type = xa_lock_type(xa); | ||
| 1275 | if (lock_type == XA_LOCK_IRQ) | ||
| 1276 | lockdep_set_class(&xa->xa_lock, &xa_lock_irq); | ||
| 1277 | else if (lock_type == XA_LOCK_BH) | ||
| 1278 | lockdep_set_class(&xa->xa_lock, &xa_lock_bh); | ||
| 1279 | } | ||
| 1280 | EXPORT_SYMBOL(xa_init_flags); | ||
| 1281 | |||
| 1282 | /** | ||
| 1283 | * xa_load() - Load an entry from an XArray. | 1259 | * xa_load() - Load an entry from an XArray. |
| 1284 | * @xa: XArray. | 1260 | * @xa: XArray. |
| 1285 | * @index: index into array. | 1261 | * @index: index into array. |
| @@ -1308,7 +1284,6 @@ static void *xas_result(struct xa_state *xas, void *curr) | |||
| 1308 | { | 1284 | { |
| 1309 | if (xa_is_zero(curr)) | 1285 | if (xa_is_zero(curr)) |
| 1310 | return NULL; | 1286 | return NULL; |
| 1311 | XA_NODE_BUG_ON(xas->xa_node, xa_is_internal(curr)); | ||
| 1312 | if (xas_error(xas)) | 1287 | if (xas_error(xas)) |
| 1313 | curr = xas->xa_node; | 1288 | curr = xas->xa_node; |
| 1314 | return curr; | 1289 | return curr; |
| @@ -1378,7 +1353,7 @@ void *__xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp) | |||
| 1378 | XA_STATE(xas, xa, index); | 1353 | XA_STATE(xas, xa, index); |
| 1379 | void *curr; | 1354 | void *curr; |
| 1380 | 1355 | ||
| 1381 | if (WARN_ON_ONCE(xa_is_internal(entry))) | 1356 | if (WARN_ON_ONCE(xa_is_advanced(entry))) |
| 1382 | return XA_ERROR(-EINVAL); | 1357 | return XA_ERROR(-EINVAL); |
| 1383 | if (xa_track_free(xa) && !entry) | 1358 | if (xa_track_free(xa) && !entry) |
| 1384 | entry = XA_ZERO_ENTRY; | 1359 | entry = XA_ZERO_ENTRY; |
| @@ -1444,7 +1419,7 @@ void *__xa_cmpxchg(struct xarray *xa, unsigned long index, | |||
| 1444 | XA_STATE(xas, xa, index); | 1419 | XA_STATE(xas, xa, index); |
| 1445 | void *curr; | 1420 | void *curr; |
| 1446 | 1421 | ||
| 1447 | if (WARN_ON_ONCE(xa_is_internal(entry))) | 1422 | if (WARN_ON_ONCE(xa_is_advanced(entry))) |
| 1448 | return XA_ERROR(-EINVAL); | 1423 | return XA_ERROR(-EINVAL); |
| 1449 | if (xa_track_free(xa) && !entry) | 1424 | if (xa_track_free(xa) && !entry) |
| 1450 | entry = XA_ZERO_ENTRY; | 1425 | entry = XA_ZERO_ENTRY; |
| @@ -1465,6 +1440,47 @@ void *__xa_cmpxchg(struct xarray *xa, unsigned long index, | |||
| 1465 | EXPORT_SYMBOL(__xa_cmpxchg); | 1440 | EXPORT_SYMBOL(__xa_cmpxchg); |
| 1466 | 1441 | ||
| 1467 | /** | 1442 | /** |
| 1443 | * __xa_insert() - Store this entry in the XArray if no entry is present. | ||
| 1444 | * @xa: XArray. | ||
| 1445 | * @index: Index into array. | ||
| 1446 | * @entry: New entry. | ||
| 1447 | * @gfp: Memory allocation flags. | ||
| 1448 | * | ||
| 1449 | * Inserting a NULL entry will store a reserved entry (like xa_reserve()) | ||
| 1450 | * if no entry is present. Inserting will fail if a reserved entry is | ||
| 1451 | * present, even though loading from this index will return NULL. | ||
| 1452 | * | ||
| 1453 | * Context: Any context. Expects xa_lock to be held on entry. May | ||
| 1454 | * release and reacquire xa_lock if @gfp flags permit. | ||
| 1455 | * Return: 0 if the store succeeded. -EEXIST if another entry was present. | ||
| 1456 | * -ENOMEM if memory could not be allocated. | ||
| 1457 | */ | ||
| 1458 | int __xa_insert(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp) | ||
| 1459 | { | ||
| 1460 | XA_STATE(xas, xa, index); | ||
| 1461 | void *curr; | ||
| 1462 | |||
| 1463 | if (WARN_ON_ONCE(xa_is_advanced(entry))) | ||
| 1464 | return -EINVAL; | ||
| 1465 | if (!entry) | ||
| 1466 | entry = XA_ZERO_ENTRY; | ||
| 1467 | |||
| 1468 | do { | ||
| 1469 | curr = xas_load(&xas); | ||
| 1470 | if (!curr) { | ||
| 1471 | xas_store(&xas, entry); | ||
| 1472 | if (xa_track_free(xa)) | ||
| 1473 | xas_clear_mark(&xas, XA_FREE_MARK); | ||
| 1474 | } else { | ||
| 1475 | xas_set_err(&xas, -EEXIST); | ||
| 1476 | } | ||
| 1477 | } while (__xas_nomem(&xas, gfp)); | ||
| 1478 | |||
| 1479 | return xas_error(&xas); | ||
| 1480 | } | ||
| 1481 | EXPORT_SYMBOL(__xa_insert); | ||
| 1482 | |||
| 1483 | /** | ||
| 1468 | * __xa_reserve() - Reserve this index in the XArray. | 1484 | * __xa_reserve() - Reserve this index in the XArray. |
| 1469 | * @xa: XArray. | 1485 | * @xa: XArray. |
| 1470 | * @index: Index into array. | 1486 | * @index: Index into array. |
| @@ -1567,7 +1583,7 @@ void *xa_store_range(struct xarray *xa, unsigned long first, | |||
| 1567 | if (last + 1) | 1583 | if (last + 1) |
| 1568 | order = __ffs(last + 1); | 1584 | order = __ffs(last + 1); |
| 1569 | xas_set_order(&xas, last, order); | 1585 | xas_set_order(&xas, last, order); |
| 1570 | xas_create(&xas); | 1586 | xas_create(&xas, true); |
| 1571 | if (xas_error(&xas)) | 1587 | if (xas_error(&xas)) |
| 1572 | goto unlock; | 1588 | goto unlock; |
| 1573 | } | 1589 | } |
| @@ -1609,7 +1625,7 @@ int __xa_alloc(struct xarray *xa, u32 *id, u32 max, void *entry, gfp_t gfp) | |||
| 1609 | XA_STATE(xas, xa, 0); | 1625 | XA_STATE(xas, xa, 0); |
| 1610 | int err; | 1626 | int err; |
| 1611 | 1627 | ||
| 1612 | if (WARN_ON_ONCE(xa_is_internal(entry))) | 1628 | if (WARN_ON_ONCE(xa_is_advanced(entry))) |
| 1613 | return -EINVAL; | 1629 | return -EINVAL; |
| 1614 | if (WARN_ON_ONCE(!xa_track_free(xa))) | 1630 | if (WARN_ON_ONCE(!xa_track_free(xa))) |
| 1615 | return -EINVAL; | 1631 | return -EINVAL; |
