Skip to content

Commit c9ba524

Browse files
Kemeng Shiakpm00
authored andcommitted
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/[email protected] Signed-off-by: Kemeng Shi <[email protected]> Cc: Mattew Wilcox <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 7e060df commit c9ba524

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

lib/test_xarray.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,41 @@ static noinline void check_pause(struct kunit *test)
15111511
XA_BUG_ON(xa, count != order_limit);
15121512

15131513
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+
15141549
}
15151550

15161551
static noinline void check_move_tiny(struct kunit *test)

lib/xarray.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,7 @@ void xas_pause(struct xa_state *xas)
11521152
if (!xa_is_sibling(xa_entry(xas->xa, node, offset)))
11531153
break;
11541154
}
1155+
xas->xa_index &= ~0UL << node->shift;
11551156
xas->xa_index += (offset - xas->xa_offset) << node->shift;
11561157
if (xas->xa_index == 0)
11571158
xas->xa_node = XAS_BOUNDS;

0 commit comments

Comments
 (0)