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; |