diff options
Diffstat (limited to 'lib/xarray.c')
-rw-r--r-- | lib/xarray.c | 97 |
1 files changed, 95 insertions, 2 deletions
diff --git a/lib/xarray.c b/lib/xarray.c index 9a0d49d4b5f0..8b176f009c08 100644 --- a/lib/xarray.c +++ b/lib/xarray.c | |||
@@ -376,6 +376,14 @@ static void *xas_alloc(struct xa_state *xas, unsigned int shift) | |||
376 | return node; | 376 | return node; |
377 | } | 377 | } |
378 | 378 | ||
379 | #ifdef CONFIG_XARRAY_MULTI | ||
380 | /* Returns the number of indices covered by a given xa_state */ | ||
381 | static unsigned long xas_size(const struct xa_state *xas) | ||
382 | { | ||
383 | return (xas->xa_sibs + 1UL) << xas->xa_shift; | ||
384 | } | ||
385 | #endif | ||
386 | |||
379 | /* | 387 | /* |
380 | * Use this to calculate the maximum index that will need to be created | 388 | * Use this to calculate the maximum index that will need to be created |
381 | * in order to add the entry described by @xas. Because we cannot store a | 389 | * in order to add the entry described by @xas. Because we cannot store a |
@@ -388,8 +396,7 @@ static unsigned long xas_max(struct xa_state *xas) | |||
388 | 396 | ||
389 | #ifdef CONFIG_XARRAY_MULTI | 397 | #ifdef CONFIG_XARRAY_MULTI |
390 | if (xas->xa_shift || xas->xa_sibs) { | 398 | if (xas->xa_shift || xas->xa_sibs) { |
391 | unsigned long mask; | 399 | unsigned long mask = xas_size(xas) - 1; |
392 | mask = (((xas->xa_sibs + 1UL) << xas->xa_shift) - 1); | ||
393 | max |= mask; | 400 | max |= mask; |
394 | if (mask == max) | 401 | if (mask == max) |
395 | max++; | 402 | max++; |
@@ -1517,6 +1524,92 @@ int xa_reserve(struct xarray *xa, unsigned long index, gfp_t gfp) | |||
1517 | } | 1524 | } |
1518 | EXPORT_SYMBOL(xa_reserve); | 1525 | EXPORT_SYMBOL(xa_reserve); |
1519 | 1526 | ||
1527 | #ifdef CONFIG_XARRAY_MULTI | ||
1528 | static void xas_set_range(struct xa_state *xas, unsigned long first, | ||
1529 | unsigned long last) | ||
1530 | { | ||
1531 | unsigned int shift = 0; | ||
1532 | unsigned long sibs = last - first; | ||
1533 | unsigned int offset = XA_CHUNK_MASK; | ||
1534 | |||
1535 | xas_set(xas, first); | ||
1536 | |||
1537 | while ((first & XA_CHUNK_MASK) == 0) { | ||
1538 | if (sibs < XA_CHUNK_MASK) | ||
1539 | break; | ||
1540 | if ((sibs == XA_CHUNK_MASK) && (offset < XA_CHUNK_MASK)) | ||
1541 | break; | ||
1542 | shift += XA_CHUNK_SHIFT; | ||
1543 | if (offset == XA_CHUNK_MASK) | ||
1544 | offset = sibs & XA_CHUNK_MASK; | ||
1545 | sibs >>= XA_CHUNK_SHIFT; | ||
1546 | first >>= XA_CHUNK_SHIFT; | ||
1547 | } | ||
1548 | |||
1549 | offset = first & XA_CHUNK_MASK; | ||
1550 | if (offset + sibs > XA_CHUNK_MASK) | ||
1551 | sibs = XA_CHUNK_MASK - offset; | ||
1552 | if ((((first + sibs + 1) << shift) - 1) > last) | ||
1553 | sibs -= 1; | ||
1554 | |||
1555 | xas->xa_shift = shift; | ||
1556 | xas->xa_sibs = sibs; | ||
1557 | } | ||
1558 | |||
1559 | /** | ||
1560 | * xa_store_range() - Store this entry at a range of indices in the XArray. | ||
1561 | * @xa: XArray. | ||
1562 | * @first: First index to affect. | ||
1563 | * @last: Last index to affect. | ||
1564 | * @entry: New entry. | ||
1565 | * @gfp: Memory allocation flags. | ||
1566 | * | ||
1567 | * After this function returns, loads from any index between @first and @last, | ||
1568 | * inclusive will return @entry. | ||
1569 | * Storing into an existing multislot entry updates the entry of every index. | ||
1570 | * The marks associated with @index are unaffected unless @entry is %NULL. | ||
1571 | * | ||
1572 | * Context: Process context. Takes and releases the xa_lock. May sleep | ||
1573 | * if the @gfp flags permit. | ||
1574 | * Return: %NULL on success, xa_err(-EINVAL) if @entry cannot be stored in | ||
1575 | * an XArray, or xa_err(-ENOMEM) if memory allocation failed. | ||
1576 | */ | ||
1577 | void *xa_store_range(struct xarray *xa, unsigned long first, | ||
1578 | unsigned long last, void *entry, gfp_t gfp) | ||
1579 | { | ||
1580 | XA_STATE(xas, xa, 0); | ||
1581 | |||
1582 | if (WARN_ON_ONCE(xa_is_internal(entry))) | ||
1583 | return XA_ERROR(-EINVAL); | ||
1584 | if (last < first) | ||
1585 | return XA_ERROR(-EINVAL); | ||
1586 | |||
1587 | do { | ||
1588 | xas_lock(&xas); | ||
1589 | if (entry) { | ||
1590 | unsigned int order = (last == ~0UL) ? 64 : | ||
1591 | ilog2(last + 1); | ||
1592 | xas_set_order(&xas, last, order); | ||
1593 | xas_create(&xas); | ||
1594 | if (xas_error(&xas)) | ||
1595 | goto unlock; | ||
1596 | } | ||
1597 | do { | ||
1598 | xas_set_range(&xas, first, last); | ||
1599 | xas_store(&xas, entry); | ||
1600 | if (xas_error(&xas)) | ||
1601 | goto unlock; | ||
1602 | first += xas_size(&xas); | ||
1603 | } while (first <= last); | ||
1604 | unlock: | ||
1605 | xas_unlock(&xas); | ||
1606 | } while (xas_nomem(&xas, gfp)); | ||
1607 | |||
1608 | return xas_result(&xas, NULL); | ||
1609 | } | ||
1610 | EXPORT_SYMBOL(xa_store_range); | ||
1611 | #endif /* CONFIG_XARRAY_MULTI */ | ||
1612 | |||
1520 | /** | 1613 | /** |
1521 | * __xa_alloc() - Find somewhere to store this entry in the XArray. | 1614 | * __xa_alloc() - Find somewhere to store this entry in the XArray. |
1522 | * @xa: XArray. | 1615 | * @xa: XArray. |