rcu: Improve diagnostics for blocked critical sections in irq
If an RCU read-side critical section occurs within an interrupt handler or a softirq handler, it cannot have been preempted. Therefore, there is a check in rcu_read_unlock_special() checking for this error. However, when this check triggers, it lacks diagnostic information. This commit therefore moves rcu_read_unlock()'s lockdep annotation to follow the call to __rcu_read_unlock() and changes rcu_read_unlock_special()'s WARN_ON_ONCE() to an lockdep_rcu_suspicious() in order to locate where the offending RCU read-side critical section began. In addition, the value of the ->rcu_read_unlock_special field is printed. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
This commit is contained in:
		
							parent
							
								
									6629240575
								
							
						
					
					
						commit
						d24209bb68
					
				| @ -531,8 +531,13 @@ do {									\ | ||||
| # define might_lock_read(lock) do { } while (0) | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_PROVE_RCU | ||||
| #ifdef CONFIG_LOCKDEP | ||||
| void lockdep_rcu_suspicious(const char *file, const int line, const char *s); | ||||
| #else | ||||
| static inline void | ||||
| lockdep_rcu_suspicious(const char *file, const int line, const char *s) | ||||
| { | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif /* __LINUX_LOCKDEP_H */ | ||||
|  | ||||
| @ -942,9 +942,9 @@ static inline void rcu_read_unlock(void) | ||||
| { | ||||
| 	rcu_lockdep_assert(rcu_is_watching(), | ||||
| 			   "rcu_read_unlock() used illegally while idle"); | ||||
| 	rcu_lock_release(&rcu_lock_map); | ||||
| 	__release(RCU); | ||||
| 	__rcu_read_unlock(); | ||||
| 	rcu_lock_release(&rcu_lock_map); /* Keep acq info for rls diags. */ | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
| @ -334,7 +334,13 @@ void rcu_read_unlock_special(struct task_struct *t) | ||||
| 	} | ||||
| 
 | ||||
| 	/* Hardware IRQ handlers cannot block, complain if they get here. */ | ||||
| 	if (WARN_ON_ONCE(in_irq() || in_serving_softirq())) { | ||||
| 	if (in_irq() || in_serving_softirq()) { | ||||
| 		lockdep_rcu_suspicious(__FILE__, __LINE__, | ||||
| 				       "rcu_read_unlock() from irq or softirq with blocking in critical section!!!\n"); | ||||
| 		pr_alert("->rcu_read_unlock_special: %#x (b: %d, nq: %d)\n", | ||||
| 			 t->rcu_read_unlock_special.s, | ||||
| 			 t->rcu_read_unlock_special.b.blocked, | ||||
| 			 t->rcu_read_unlock_special.b.need_qs); | ||||
| 		local_irq_restore(flags); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user