radix tree test suite: iteration test misuses RCU
authorMatthew Wilcox <mawilcox@microsoft.com>
Wed, 14 Dec 2016 23:08:11 +0000 (15:08 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 15 Dec 2016 00:04:09 +0000 (16:04 -0800)
Each thread needs to register itself with RCU, otherwise the reading
thread's read lock has no effect and the freeing thread will free the
memory in the tree without waiting for the read lock to be dropped.

Link: http://lkml.kernel.org/r/1480369871-5271-42-git-send-email-mawilcox@linuxonhyperv.com
Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com>
Tested-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
Cc: Matthew Wilcox <mawilcox@microsoft.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
tools/testing/radix-tree/iteration_check.c

index 11d570c3fc83c7b8523f91522d987a2c9ffe3f95..df71cb841385d5cf4ea1e1dcdd6410ad721666cd 100644 (file)
@@ -29,6 +29,8 @@ static void *add_entries_fn(void *arg)
 {
        int pgoff;
 
+       rcu_register_thread();
+
        while (!test_complete) {
                for (pgoff = 0; pgoff < 100; pgoff++) {
                        pthread_mutex_lock(&tree_lock);
@@ -38,6 +40,8 @@ static void *add_entries_fn(void *arg)
                }
        }
 
+       rcu_unregister_thread();
+
        return NULL;
 }
 
@@ -53,6 +57,8 @@ static void *tagged_iteration_fn(void *arg)
        struct radix_tree_iter iter;
        void **slot;
 
+       rcu_register_thread();
+
        while (!test_complete) {
                rcu_read_lock();
                radix_tree_for_each_tagged(slot, &tree, &iter, 0, TAG) {
@@ -72,12 +78,18 @@ static void *tagged_iteration_fn(void *arg)
                                continue;
                        }
 
-                       if (rand_r(&seeds[0]) % 50 == 0)
+                       if (rand_r(&seeds[0]) % 50 == 0) {
                                slot = radix_tree_iter_next(&iter);
+                               rcu_read_unlock();
+                               rcu_barrier();
+                               rcu_read_lock();
+                       }
                }
                rcu_read_unlock();
        }
 
+       rcu_unregister_thread();
+
        return NULL;
 }
 
@@ -93,6 +105,8 @@ static void *untagged_iteration_fn(void *arg)
        struct radix_tree_iter iter;
        void **slot;
 
+       rcu_register_thread();
+
        while (!test_complete) {
                rcu_read_lock();
                radix_tree_for_each_slot(slot, &tree, &iter, 0) {
@@ -112,12 +126,18 @@ static void *untagged_iteration_fn(void *arg)
                                continue;
                        }
 
-                       if (rand_r(&seeds[1]) % 50 == 0)
+                       if (rand_r(&seeds[1]) % 50 == 0) {
                                slot = radix_tree_iter_next(&iter);
+                               rcu_read_unlock();
+                               rcu_barrier();
+                               rcu_read_lock();
+                       }
                }
                rcu_read_unlock();
        }
 
+       rcu_unregister_thread();
+
        return NULL;
 }
 
@@ -127,6 +147,8 @@ static void *untagged_iteration_fn(void *arg)
  */
 static void *remove_entries_fn(void *arg)
 {
+       rcu_register_thread();
+
        while (!test_complete) {
                int pgoff;
 
@@ -137,6 +159,8 @@ static void *remove_entries_fn(void *arg)
                pthread_mutex_unlock(&tree_lock);
        }
 
+       rcu_unregister_thread();
+
        return NULL;
 }