summaryrefslogtreecommitdiff
path: root/patches/0007-lockdep-selftests-Unbalanced-migrate_disable-rcu_rea.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/0007-lockdep-selftests-Unbalanced-migrate_disable-rcu_rea.patch')
-rw-r--r--patches/0007-lockdep-selftests-Unbalanced-migrate_disable-rcu_rea.patch82
1 files changed, 82 insertions, 0 deletions
diff --git a/patches/0007-lockdep-selftests-Unbalanced-migrate_disable-rcu_rea.patch b/patches/0007-lockdep-selftests-Unbalanced-migrate_disable-rcu_rea.patch
new file mode 100644
index 000000000000..6837b520496b
--- /dev/null
+++ b/patches/0007-lockdep-selftests-Unbalanced-migrate_disable-rcu_rea.patch
@@ -0,0 +1,82 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Thu, 12 Aug 2021 14:25:38 +0200
+Subject: [PATCH 07/10] lockdep/selftests: Unbalanced migrate_disable() &
+ rcu_read_lock()
+
+The tests with unbalanced lock() + unlock() operation leave a modified
+preemption counter behind which is then reset to its original value
+after the test.
+
+The spin_lock() function on PREEMPT_RT does not include a
+preempt_disable() statement but migrate_disable() and read_rcu_lock().
+As a consequence both counter never get back to their original value and
+system explodes later after the selftest.
+In the double-unlock case on PREEMPT_RT, the migrate_disable() and RCU
+code will trigger which should be avoided. These counter should not be
+decremented below their initial value.
+
+Save both counters and bring them back to their original value after the
+test.
+In the double-unlock case, increment both counter in advance to they
+become balanced after the double unlock.
+
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ lib/locking-selftest.c | 26 +++++++++++++++++++++++++-
+ 1 file changed, 25 insertions(+), 1 deletion(-)
+
+--- a/lib/locking-selftest.c
++++ b/lib/locking-selftest.c
+@@ -712,12 +712,18 @@ GENERATE_TESTCASE(ABCDBCDA_rtmutex);
+
+ #undef E
+
++#ifdef CONFIG_PREEMPT_RT
++# define RT_PREPARE_DBL_UNLOCK() { migrate_disable(); rcu_read_lock(); }
++#else
++# define RT_PREPARE_DBL_UNLOCK()
++#endif
+ /*
+ * Double unlock:
+ */
+ #define E() \
+ \
+ LOCK(A); \
++ RT_PREPARE_DBL_UNLOCK(); \
+ UNLOCK(A); \
+ UNLOCK(A); /* fail */
+
+@@ -1398,7 +1404,13 @@ static int unexpected_testcase_failures;
+
+ static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask)
+ {
+- unsigned long saved_preempt_count = preempt_count();
++ int saved_preempt_count = preempt_count();
++#ifdef CONFIG_PREEMPT_RT
++#ifdef CONFIG_SMP
++ int saved_mgd_count = current->migration_disabled;
++#endif
++ int saved_rcu_count = current->rcu_read_lock_nesting;
++#endif
+
+ WARN_ON(irqs_disabled());
+
+@@ -1432,6 +1444,18 @@ static void dotest(void (*testcase_fn)(v
+ * count, so restore it:
+ */
+ preempt_count_set(saved_preempt_count);
++
++#ifdef CONFIG_PREEMPT_RT
++#ifdef CONFIG_SMP
++ while (current->migration_disabled > saved_mgd_count)
++ migrate_enable();
++#endif
++
++ while (current->rcu_read_lock_nesting > saved_rcu_count)
++ rcu_read_unlock();
++ WARN_ON_ONCE(current->rcu_read_lock_nesting < saved_rcu_count);
++#endif
++
+ #ifdef CONFIG_TRACE_IRQFLAGS
+ if (softirq_count())
+ current->softirqs_enabled = 0;