diff options
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.patch | 82 |
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; |