aboutsummaryrefslogtreecommitdiffstats
path: root/lib/xarray.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/xarray.c')
-rw-r--r--lib/xarray.c97
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 */
381static 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}
1518EXPORT_SYMBOL(xa_reserve); 1525EXPORT_SYMBOL(xa_reserve);
1519 1526
1527#ifdef CONFIG_XARRAY_MULTI
1528static 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 */
1577void *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);
1604unlock:
1605 xas_unlock(&xas);
1606 } while (xas_nomem(&xas, gfp));
1607
1608 return xas_result(&xas, NULL);
1609}
1610EXPORT_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.