Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Xarray: move forward index correctly in xas_pause()

After xas_load(), xas->index could point to mid of found multi-index entry
and xas->index's bits under node->shift maybe non-zero. The afterward
xas_pause() will move forward xas->index with xa->node->shift with bits
under node->shift un-masked and thus skip some index unexpectedly.

Consider following case:
Assume XA_CHUNK_SHIFT is 4.
xa_store_range(xa, 16, 31, ...)
xa_store(xa, 32, ...)
XA_STATE(xas, xa, 17);
xas_for_each(&xas,...)
xas_load(&xas)
/* xas->index = 17, xas->xa_offset = 1, xas->xa_node->xa_shift = 4 */
xas_pause()
/* xas->index = 33, xas->xa_offset = 2, xas->xa_node->xa_shift = 4 */
As we can see, index of 32 is skipped unexpectedly.

Fix this by mask bit under node->xa_shift when move forward index in
xas_pause().

For now, this will not cause serious problems. Only minor problem like
cachestat return less number of page status could happen.

Link: https://lkml.kernel.org/r/20241213122523.12764-3-shikemeng@huaweicloud.com
Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
Cc: Mattew Wilcox <willy@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Kemeng Shi and committed by
Andrew Morton
c9ba5249 7e060df0

+36
+35
lib/test_xarray.c
··· 1511 1511 XA_BUG_ON(xa, count != order_limit); 1512 1512 1513 1513 xa_destroy(xa); 1514 + 1515 + index = 0; 1516 + for (order = XA_CHUNK_SHIFT; order > 0; order--) { 1517 + XA_BUG_ON(xa, xa_store_order(xa, index, order, 1518 + xa_mk_index(index), GFP_KERNEL)); 1519 + index += 1UL << order; 1520 + } 1521 + 1522 + index = 0; 1523 + count = 0; 1524 + xas_set(&xas, 0); 1525 + rcu_read_lock(); 1526 + xas_for_each(&xas, entry, ULONG_MAX) { 1527 + XA_BUG_ON(xa, entry != xa_mk_index(index)); 1528 + index += 1UL << (XA_CHUNK_SHIFT - count); 1529 + count++; 1530 + } 1531 + rcu_read_unlock(); 1532 + XA_BUG_ON(xa, count != XA_CHUNK_SHIFT); 1533 + 1534 + index = 0; 1535 + count = 0; 1536 + xas_set(&xas, XA_CHUNK_SIZE / 2 + 1); 1537 + rcu_read_lock(); 1538 + xas_for_each(&xas, entry, ULONG_MAX) { 1539 + XA_BUG_ON(xa, entry != xa_mk_index(index)); 1540 + index += 1UL << (XA_CHUNK_SHIFT - count); 1541 + count++; 1542 + xas_pause(&xas); 1543 + } 1544 + rcu_read_unlock(); 1545 + XA_BUG_ON(xa, count != XA_CHUNK_SHIFT); 1546 + 1547 + xa_destroy(xa); 1548 + 1514 1549 } 1515 1550 1516 1551 static noinline void check_move_tiny(struct kunit *test)
+1
lib/xarray.c
··· 1152 1152 if (!xa_is_sibling(xa_entry(xas->xa, node, offset))) 1153 1153 break; 1154 1154 } 1155 + xas->xa_index &= ~0UL << node->shift; 1155 1156 xas->xa_index += (offset - xas->xa_offset) << node->shift; 1156 1157 if (xas->xa_index == 0) 1157 1158 xas->xa_node = XAS_BOUNDS;