Skip to content

Commit

Permalink
lockdep/selftests: Unbalanced migrate_disable() & rcu_read_lock().
Browse files Browse the repository at this point in the history
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 the system explodes later after the selftest.  In the
double-unlock case on PREEMPT_RT, the migrate_disable() and RCU code
will trigger a warning 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>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20211129174654.668506-8-bigeasy@linutronix.de
  • Loading branch information
Sebastian Andrzej Siewior authored and Peter Zijlstra committed Dec 4, 2021
1 parent fc78dd0 commit 512bf71
Showing 1 changed file with 25 additions and 1 deletion.
26 changes: 25 additions & 1 deletion lib/locking-selftest.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down Expand Up @@ -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());

Expand Down Expand Up @@ -1432,6 +1444,18 @@ static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask)
* 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;
Expand Down

0 comments on commit 512bf71

Please sign in to comment.