maple_tree: add test for expanding range in RCU mode
authorPeng Zhang <zhangpeng.00@bytedance.com>
Wed, 28 Jun 2023 07:36:55 +0000 (15:36 +0800)
committerAndrew Morton <akpm@linux-foundation.org>
Fri, 18 Aug 2023 17:12:05 +0000 (10:12 -0700)
Add test for expanding range in RCU mode. If we use the fast path of the
slot store to expand range in RCU mode, this test will fail.

Link: https://lkml.kernel.org/r/20230628073657.75314-3-zhangpeng.00@bytedance.com
Signed-off-by: Peng Zhang <zhangpeng.00@bytedance.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
tools/testing/radix-tree/maple.c

index 75ea2081a317e5f49922b89fdab1f64e277bd8c5..9901ae821911a2cb83cf755a32e2ffd6a3bc8b68 100644 (file)
@@ -45,6 +45,13 @@ struct rcu_test_struct2 {
        unsigned long last[RCU_RANGE_COUNT];
 };
 
+struct rcu_test_struct3 {
+       struct maple_tree *mt;
+       unsigned long index;
+       unsigned long last;
+       bool stop;
+};
+
 struct rcu_reader_struct {
        unsigned int id;
        int mod;
@@ -34954,6 +34961,70 @@ void run_check_rcu(struct maple_tree *mt, struct rcu_test_struct *vals)
        MT_BUG_ON(mt, !vals->seen_entry2);
 }
 
+static void *rcu_slot_store_reader(void *ptr)
+{
+       struct rcu_test_struct3 *test = ptr;
+       MA_STATE(mas, test->mt, test->index, test->index);
+
+       rcu_register_thread();
+
+       rcu_read_lock();
+       while (!test->stop) {
+               mas_walk(&mas);
+               /* The length of growth to both sides must be equal. */
+               RCU_MT_BUG_ON(test, (test->index - mas.index) !=
+                                   (mas.last - test->last));
+       }
+       rcu_read_unlock();
+
+       rcu_unregister_thread();
+       return NULL;
+}
+
+static noinline void run_check_rcu_slot_store(struct maple_tree *mt)
+{
+       pthread_t readers[20];
+       int range_cnt = 200, i, limit = 10000;
+       unsigned long len = ULONG_MAX / range_cnt, start, end;
+       struct rcu_test_struct3 test = {.stop = false, .mt = mt};
+
+       start = range_cnt / 2 * len;
+       end = start + len - 1;
+       test.index = start;
+       test.last = end;
+
+       for (i = 0; i < range_cnt; i++) {
+               mtree_store_range(mt, i * len, i * len + len - 1,
+                                 xa_mk_value(i * 100), GFP_KERNEL);
+       }
+
+       mt_set_in_rcu(mt);
+       MT_BUG_ON(mt, !mt_in_rcu(mt));
+
+       for (i = 0; i < ARRAY_SIZE(readers); i++) {
+               if (pthread_create(&readers[i], NULL, rcu_slot_store_reader,
+                                  &test)) {
+                       perror("creating reader thread");
+                       exit(1);
+               }
+       }
+
+       usleep(5);
+
+       while (limit--) {
+               /* Step by step, expand the most middle range to both sides. */
+               mtree_store_range(mt, --start, ++end, xa_mk_value(100),
+                                 GFP_KERNEL);
+       }
+
+       test.stop = true;
+
+       while (i--)
+               pthread_join(readers[i], NULL);
+
+       mt_validate(mt);
+}
+
 static noinline
 void run_check_rcu_slowread(struct maple_tree *mt, struct rcu_test_struct *vals)
 {
@@ -35206,6 +35277,10 @@ static noinline void __init check_rcu_threaded(struct maple_tree *mt)
        run_check_rcu(mt, &vals);
        mtree_destroy(mt);
 
+       /* Check expanding range in RCU mode */
+       mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+       run_check_rcu_slot_store(mt);
+       mtree_destroy(mt);
 
        /* Forward writer for rcu stress */
        mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);