mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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
					
				
					 2 changed files with 18 additions and 2 deletions
				
			
		| 
						 | 
					@ -71,6 +71,7 @@ MODULE_ALIAS("rcutree");
 | 
				
			||||||
static struct lock_class_key rcu_node_class[RCU_NUM_LVLS];
 | 
					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_fqs_class[RCU_NUM_LVLS];
 | 
				
			||||||
static struct lock_class_key rcu_exp_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
 | 
					 * 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 buf[] = RCU_NODE_NAME_INIT;
 | 
				
			||||||
	static const char * const fqs[] = RCU_FQS_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[] = RCU_EXP_NAME_INIT;
 | 
				
			||||||
 | 
						static const char * const exp_sched[] = RCU_EXP_SCHED_NAME_INIT;
 | 
				
			||||||
	static u8 fl_mask = 0x1;
 | 
						static u8 fl_mask = 0x1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int levelcnt[RCU_NUM_LVLS];		/* # nodes in each level. */
 | 
						int levelcnt[RCU_NUM_LVLS];		/* # nodes in each level. */
 | 
				
			||||||
| 
						 | 
					@ -4108,7 +4110,13 @@ static void __init rcu_init_one(struct rcu_state *rsp,
 | 
				
			||||||
			INIT_LIST_HEAD(&rnp->blkd_tasks);
 | 
								INIT_LIST_HEAD(&rnp->blkd_tasks);
 | 
				
			||||||
			rcu_init_one_nocb(rnp);
 | 
								rcu_init_one_nocb(rnp);
 | 
				
			||||||
			mutex_init(&rnp->exp_funnel_mutex);
 | 
								mutex_init(&rnp->exp_funnel_mutex);
 | 
				
			||||||
			lockdep_set_class_and_name(&rnp->exp_funnel_mutex,
 | 
								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]);
 | 
										&rcu_exp_class[i], exp[i]);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,6 +70,8 @@
 | 
				
			||||||
#  define RCU_NODE_NAME_INIT  { "rcu_node_0" }
 | 
					#  define RCU_NODE_NAME_INIT  { "rcu_node_0" }
 | 
				
			||||||
#  define RCU_FQS_NAME_INIT   { "rcu_node_fqs_0" }
 | 
					#  define RCU_FQS_NAME_INIT   { "rcu_node_fqs_0" }
 | 
				
			||||||
#  define RCU_EXP_NAME_INIT   { "rcu_node_exp_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
 | 
					#elif NR_CPUS <= RCU_FANOUT_2
 | 
				
			||||||
#  define RCU_NUM_LVLS	      2
 | 
					#  define RCU_NUM_LVLS	      2
 | 
				
			||||||
#  define NUM_RCU_LVL_0	      1
 | 
					#  define NUM_RCU_LVL_0	      1
 | 
				
			||||||
| 
						 | 
					@ -79,6 +81,8 @@
 | 
				
			||||||
#  define RCU_NODE_NAME_INIT  { "rcu_node_0", "rcu_node_1" }
 | 
					#  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_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_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
 | 
					#elif NR_CPUS <= RCU_FANOUT_3
 | 
				
			||||||
#  define RCU_NUM_LVLS	      3
 | 
					#  define RCU_NUM_LVLS	      3
 | 
				
			||||||
#  define NUM_RCU_LVL_0	      1
 | 
					#  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_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_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_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
 | 
					#elif NR_CPUS <= RCU_FANOUT_4
 | 
				
			||||||
#  define RCU_NUM_LVLS	      4
 | 
					#  define RCU_NUM_LVLS	      4
 | 
				
			||||||
#  define NUM_RCU_LVL_0	      1
 | 
					#  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_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_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_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
 | 
					#else
 | 
				
			||||||
# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS"
 | 
					# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS"
 | 
				
			||||||
#endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */
 | 
					#endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue