]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
maple_tree: add regression test for spanning store bug
authorLorenzo Stoakes <lorenzo.stoakes@oracle.com>
Mon, 7 Oct 2024 15:28:33 +0000 (16:28 +0100)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 17 Oct 2024 15:35:10 +0000 (08:35 -0700)
Add a regression test to assert that, when performing a spanning store
which consumes the entirety of the rightmost right leaf node does not
result in maple tree corruption when doing so.

This achieves this by building a test tree of 3 levels and establishing a
store which ultimately results in a spanned store of this nature.

Link: https://lkml.kernel.org/r/30cdc101a700d16e03ba2f9aa5d83f2efa894168.1728314403.git.lorenzo.stoakes@oracle.com
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Reviewed-by: Liam R. Howlett <Liam.Howlett@Oracle.com>
Reviewed-by: Wei Yang <richard.weiyang@gmail.com>
Cc: Bert Karwatzki <spasswolf@web.de>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Cc: Sidhartha Kumar <sidhartha.kumar@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
tools/testing/radix-tree/maple.c

index 6ec18883e11e67f20dde382d5c1876d4f2bacc5e..551ae6898c1d2dd7d05c446e5956f7e168ba1c9c 100644 (file)
@@ -36432,9 +36432,93 @@ void farmer_tests(void)
        check_nomem(&tree);
 }
 
+static unsigned long get_last_index(struct ma_state *mas)
+{
+       struct maple_node *node = mas_mn(mas);
+       enum maple_type mt = mte_node_type(mas->node);
+       unsigned long *pivots = ma_pivots(node, mt);
+       unsigned long last_index = mas_data_end(mas);
+
+       BUG_ON(last_index == 0);
+
+       return pivots[last_index - 1] + 1;
+}
+
+/*
+ * Assert that we handle spanning stores that consume the entirety of the right
+ * leaf node correctly.
+ */
+static void test_spanning_store_regression(void)
+{
+       unsigned long from = 0, to = 0;
+       DEFINE_MTREE(tree);
+       MA_STATE(mas, &tree, 0, 0);
+
+       /*
+        * Build a 3-level tree. We require a parent node below the root node
+        * and 2 leaf nodes under it, so we can span the entirety of the right
+        * hand node.
+        */
+       build_full_tree(&tree, 0, 3);
+
+       /* Descend into position at depth 2. */
+       mas_reset(&mas);
+       mas_start(&mas);
+       mas_descend(&mas);
+       mas_descend(&mas);
+
+       /*
+        * We need to establish a tree like the below.
+        *
+        * Then we can try a store in [from, to] which results in a spanned
+        * store across nodes B and C, with the maple state at the time of the
+        * write being such that only the subtree at A and below is considered.
+        *
+        * Height
+        *  0                              Root Node
+        *                                  /      \
+        *                    pivot = to   /        \ pivot = ULONG_MAX
+        *                                /          \
+        *   1                       A [-----]       ...
+        *                              /   \
+        *                pivot = from /     \ pivot = to
+        *                            /       \
+        *   2 (LEAVES)          B [-----]  [-----] C
+        *                                       ^--- Last pivot to.
+        */
+       while (true) {
+               unsigned long tmp = get_last_index(&mas);
+
+               if (mas_next_sibling(&mas)) {
+                       from = tmp;
+                       to = mas.max;
+               } else {
+                       break;
+               }
+       }
+
+       BUG_ON(from == 0 && to == 0);
+
+       /* Perform the store. */
+       mas_set_range(&mas, from, to);
+       mas_store_gfp(&mas, xa_mk_value(0xdead), GFP_KERNEL);
+
+       /* If the regression occurs, the validation will fail. */
+       mt_validate(&tree);
+
+       /* Cleanup. */
+       __mt_destroy(&tree);
+}
+
+static void regression_tests(void)
+{
+       test_spanning_store_regression();
+}
+
 void maple_tree_tests(void)
 {
 #if !defined(BENCH)
+       regression_tests();
        farmer_tests();
 #endif
        maple_tree_seed();