Skip to content

Commit 2a0774c

Browse files
Matthew Wilcox (Oracle)akpm00
authored andcommitted
XArray: set the marks correctly when splitting an entry
If we created a new node to replace an entry which had search marks set, we were setting the search mark on every entry in that node. That works fine when we're splitting to order 0, but when splitting to a larger order, we must not set the search marks on the sibling entries. Link: https://lkml.kernel.org/r/20240501153120.4094530-1-willy@infradead.org Fixes: c010d47 ("mm: thp: split huge page to any lower order pages") Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Reported-by: Luis Chamberlain <mcgrof@kernel.org> Link: https://lore.kernel.org/r/ZjFGCOYk3FK_zVy3@bombadil.infradead.org Tested-by: Luis Chamberlain <mcgrof@kernel.org> Cc: Zi Yan <ziy@nvidia.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 48f044a commit 2a0774c

File tree

2 files changed

+32
-5
lines changed

2 files changed

+32
-5
lines changed

lib/test_xarray.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1788,9 +1788,11 @@ static void check_split_1(struct xarray *xa, unsigned long index,
17881788
unsigned int order, unsigned int new_order)
17891789
{
17901790
XA_STATE_ORDER(xas, xa, index, new_order);
1791-
unsigned int i;
1791+
unsigned int i, found;
1792+
void *entry;
17921793

17931794
xa_store_order(xa, index, order, xa, GFP_KERNEL);
1795+
xa_set_mark(xa, index, XA_MARK_1);
17941796

17951797
xas_split_alloc(&xas, xa, order, GFP_KERNEL);
17961798
xas_lock(&xas);
@@ -1807,6 +1809,16 @@ static void check_split_1(struct xarray *xa, unsigned long index,
18071809
xa_set_mark(xa, index, XA_MARK_0);
18081810
XA_BUG_ON(xa, !xa_get_mark(xa, index, XA_MARK_0));
18091811

1812+
xas_set_order(&xas, index, 0);
1813+
found = 0;
1814+
rcu_read_lock();
1815+
xas_for_each_marked(&xas, entry, ULONG_MAX, XA_MARK_1) {
1816+
found++;
1817+
XA_BUG_ON(xa, xa_is_internal(entry));
1818+
}
1819+
rcu_read_unlock();
1820+
XA_BUG_ON(xa, found != 1 << (order - new_order));
1821+
18101822
xa_destroy(xa);
18111823
}
18121824

lib/xarray.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -969,16 +969,30 @@ static unsigned int node_get_marks(struct xa_node *node, unsigned int offset)
969969
return marks;
970970
}
971971

972+
static inline void node_mark_slots(struct xa_node *node, unsigned int sibs,
973+
xa_mark_t mark)
974+
{
975+
int i;
976+
977+
if (sibs == 0)
978+
node_mark_all(node, mark);
979+
else {
980+
for (i = 0; i < XA_CHUNK_SIZE; i += sibs + 1)
981+
node_set_mark(node, i, mark);
982+
}
983+
}
984+
972985
static void node_set_marks(struct xa_node *node, unsigned int offset,
973-
struct xa_node *child, unsigned int marks)
986+
struct xa_node *child, unsigned int sibs,
987+
unsigned int marks)
974988
{
975989
xa_mark_t mark = XA_MARK_0;
976990

977991
for (;;) {
978992
if (marks & (1 << (__force unsigned int)mark)) {
979993
node_set_mark(node, offset, mark);
980994
if (child)
981-
node_mark_all(child, mark);
995+
node_mark_slots(child, sibs, mark);
982996
}
983997
if (mark == XA_MARK_MAX)
984998
break;
@@ -1077,7 +1091,8 @@ void xas_split(struct xa_state *xas, void *entry, unsigned int order)
10771091
child->nr_values = xa_is_value(entry) ?
10781092
XA_CHUNK_SIZE : 0;
10791093
RCU_INIT_POINTER(child->parent, node);
1080-
node_set_marks(node, offset, child, marks);
1094+
node_set_marks(node, offset, child, xas->xa_sibs,
1095+
marks);
10811096
rcu_assign_pointer(node->slots[offset],
10821097
xa_mk_node(child));
10831098
if (xa_is_value(curr))
@@ -1086,7 +1101,7 @@ void xas_split(struct xa_state *xas, void *entry, unsigned int order)
10861101
} else {
10871102
unsigned int canon = offset - xas->xa_sibs;
10881103

1089-
node_set_marks(node, canon, NULL, marks);
1104+
node_set_marks(node, canon, NULL, 0, marks);
10901105
rcu_assign_pointer(node->slots[canon], entry);
10911106
while (offset > canon)
10921107
rcu_assign_pointer(node->slots[offset--],

0 commit comments

Comments
 (0)