summaryrefslogtreecommitdiff
path: root/lib/test_context-analysis.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/test_context-analysis.c')
-rw-r--r--lib/test_context-analysis.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/lib/test_context-analysis.c b/lib/test_context-analysis.c
index be0c5d462a48..559df32fb5f8 100644
--- a/lib/test_context-analysis.c
+++ b/lib/test_context-analysis.c
@@ -7,6 +7,7 @@
#include <linux/bit_spinlock.h>
#include <linux/build_bug.h>
#include <linux/mutex.h>
+#include <linux/rcupdate.h>
#include <linux/seqlock.h>
#include <linux/spinlock.h>
@@ -284,3 +285,87 @@ static void __used test_bit_spin_lock(struct test_bit_spinlock_data *d)
bit_spin_unlock(3, &d->bits);
}
}
+
+/*
+ * Test that we can mark a variable guarded by RCU, and we can dereference and
+ * write to the pointer with RCU's primitives.
+ */
+struct test_rcu_data {
+ long __rcu_guarded *data;
+};
+
+static void __used test_rcu_guarded_reader(struct test_rcu_data *d)
+{
+ rcu_read_lock();
+ (void)rcu_dereference(d->data);
+ rcu_read_unlock();
+
+ rcu_read_lock_bh();
+ (void)rcu_dereference(d->data);
+ rcu_read_unlock_bh();
+
+ rcu_read_lock_sched();
+ (void)rcu_dereference(d->data);
+ rcu_read_unlock_sched();
+}
+
+static void __used test_rcu_guard(struct test_rcu_data *d)
+{
+ guard(rcu)();
+ (void)rcu_dereference(d->data);
+}
+
+static void __used test_rcu_guarded_updater(struct test_rcu_data *d)
+{
+ rcu_assign_pointer(d->data, NULL);
+ RCU_INIT_POINTER(d->data, NULL);
+ (void)unrcu_pointer(d->data);
+}
+
+static void wants_rcu_held(void) __must_hold_shared(RCU) { }
+static void wants_rcu_held_bh(void) __must_hold_shared(RCU_BH) { }
+static void wants_rcu_held_sched(void) __must_hold_shared(RCU_SCHED) { }
+
+static void __used test_rcu_lock_variants(void)
+{
+ rcu_read_lock();
+ wants_rcu_held();
+ rcu_read_unlock();
+
+ rcu_read_lock_bh();
+ wants_rcu_held_bh();
+ rcu_read_unlock_bh();
+
+ rcu_read_lock_sched();
+ wants_rcu_held_sched();
+ rcu_read_unlock_sched();
+}
+
+static void __used test_rcu_lock_reentrant(void)
+{
+ rcu_read_lock();
+ rcu_read_lock();
+ rcu_read_lock_bh();
+ rcu_read_lock_bh();
+ rcu_read_lock_sched();
+ rcu_read_lock_sched();
+
+ rcu_read_unlock_sched();
+ rcu_read_unlock_sched();
+ rcu_read_unlock_bh();
+ rcu_read_unlock_bh();
+ rcu_read_unlock();
+ rcu_read_unlock();
+}
+
+static void __used test_rcu_assert_variants(void)
+{
+ lockdep_assert_in_rcu_read_lock();
+ wants_rcu_held();
+
+ lockdep_assert_in_rcu_read_lock_bh();
+ wants_rcu_held_bh();
+
+ lockdep_assert_in_rcu_read_lock_sched();
+ wants_rcu_held_sched();
+}