rcu: Silence lockdep false positive for expedited grace periods
In a CONFIG_PREEMPT=y kernel, synchronize_rcu_expedited() acquires the ->exp_funnel_mutex in rcu_preempt_state, then invokes synchronize_sched_expedited, which acquires the ->exp_funnel_mutex in rcu_sched_state. There can be no deadlock because rcu_preempt_state ->exp_funnel_mutex acquisition always precedes that of rcu_sched_state. But lockdep does not know that, so it gives false-positive splats. This commit therefore associates a separate lock_class_key structure with the rcu_sched_state structure's ->exp_funnel_mutex, allowing lockdep to see the lock ordering, avoiding the false positives. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
This commit is contained in:
		
							parent
							
								
									cdacbe1f91
								
							
						
					
					
						commit
						af859beaab
					
				| @ -71,6 +71,7 @@ MODULE_ALIAS("rcutree"); | ||||
| static struct lock_class_key rcu_node_class[RCU_NUM_LVLS]; | ||||
| static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS]; | ||||
| static struct lock_class_key rcu_exp_class[RCU_NUM_LVLS]; | ||||
| static struct lock_class_key rcu_exp_sched_class[RCU_NUM_LVLS]; | ||||
| 
 | ||||
| /*
 | ||||
|  * In order to export the rcu_state name to the tracing tools, it | ||||
| @ -4049,6 +4050,7 @@ static void __init rcu_init_one(struct rcu_state *rsp, | ||||
| 	static const char * const buf[] = RCU_NODE_NAME_INIT; | ||||
| 	static const char * const fqs[] = RCU_FQS_NAME_INIT; | ||||
| 	static const char * const exp[] = RCU_EXP_NAME_INIT; | ||||
| 	static const char * const exp_sched[] = RCU_EXP_SCHED_NAME_INIT; | ||||
| 	static u8 fl_mask = 0x1; | ||||
| 
 | ||||
| 	int levelcnt[RCU_NUM_LVLS];		/* # nodes in each level. */ | ||||
| @ -4108,8 +4110,14 @@ static void __init rcu_init_one(struct rcu_state *rsp, | ||||
| 			INIT_LIST_HEAD(&rnp->blkd_tasks); | ||||
| 			rcu_init_one_nocb(rnp); | ||||
| 			mutex_init(&rnp->exp_funnel_mutex); | ||||
| 			lockdep_set_class_and_name(&rnp->exp_funnel_mutex, | ||||
| 						   &rcu_exp_class[i], exp[i]); | ||||
| 			if (rsp == &rcu_sched_state) | ||||
| 				lockdep_set_class_and_name( | ||||
| 					&rnp->exp_funnel_mutex, | ||||
| 					&rcu_exp_sched_class[i], exp_sched[i]); | ||||
| 			else | ||||
| 				lockdep_set_class_and_name( | ||||
| 					&rnp->exp_funnel_mutex, | ||||
| 					&rcu_exp_class[i], exp[i]); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -70,6 +70,8 @@ | ||||
| #  define RCU_NODE_NAME_INIT  { "rcu_node_0" } | ||||
| #  define RCU_FQS_NAME_INIT   { "rcu_node_fqs_0" } | ||||
| #  define RCU_EXP_NAME_INIT   { "rcu_node_exp_0" } | ||||
| #  define RCU_EXP_SCHED_NAME_INIT \ | ||||
| 			      { "rcu_node_exp_sched_0" } | ||||
| #elif NR_CPUS <= RCU_FANOUT_2 | ||||
| #  define RCU_NUM_LVLS	      2 | ||||
| #  define NUM_RCU_LVL_0	      1 | ||||
| @ -79,6 +81,8 @@ | ||||
| #  define RCU_NODE_NAME_INIT  { "rcu_node_0", "rcu_node_1" } | ||||
| #  define RCU_FQS_NAME_INIT   { "rcu_node_fqs_0", "rcu_node_fqs_1" } | ||||
| #  define RCU_EXP_NAME_INIT   { "rcu_node_exp_0", "rcu_node_exp_1" } | ||||
| #  define RCU_EXP_SCHED_NAME_INIT \ | ||||
| 			      { "rcu_node_exp_sched_0", "rcu_node_exp_sched_1" } | ||||
| #elif NR_CPUS <= RCU_FANOUT_3 | ||||
| #  define RCU_NUM_LVLS	      3 | ||||
| #  define NUM_RCU_LVL_0	      1 | ||||
| @ -89,6 +93,8 @@ | ||||
| #  define RCU_NODE_NAME_INIT  { "rcu_node_0", "rcu_node_1", "rcu_node_2" } | ||||
| #  define RCU_FQS_NAME_INIT   { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2" } | ||||
| #  define RCU_EXP_NAME_INIT   { "rcu_node_exp_0", "rcu_node_exp_1", "rcu_node_exp_2" } | ||||
| #  define RCU_EXP_SCHED_NAME_INIT \ | ||||
| 			      { "rcu_node_exp_sched_0", "rcu_node_exp_sched_1", "rcu_node_exp_sched_2" } | ||||
| #elif NR_CPUS <= RCU_FANOUT_4 | ||||
| #  define RCU_NUM_LVLS	      4 | ||||
| #  define NUM_RCU_LVL_0	      1 | ||||
| @ -100,6 +106,8 @@ | ||||
| #  define RCU_NODE_NAME_INIT  { "rcu_node_0", "rcu_node_1", "rcu_node_2", "rcu_node_3" } | ||||
| #  define RCU_FQS_NAME_INIT   { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2", "rcu_node_fqs_3" } | ||||
| #  define RCU_EXP_NAME_INIT   { "rcu_node_exp_0", "rcu_node_exp_1", "rcu_node_exp_2", "rcu_node_exp_3" } | ||||
| #  define RCU_EXP_SCHED_NAME_INIT \ | ||||
| 			      { "rcu_node_exp_sched_0", "rcu_node_exp_sched_1", "rcu_node_exp_sched_2", "rcu_node_exp_sched_3" } | ||||
| #else | ||||
| # error "CONFIG_RCU_FANOUT insufficient for NR_CPUS" | ||||
| #endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */ | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user