diff options
Diffstat (limited to 'kernel/rcu/tree.c')
| -rw-r--r-- | kernel/rcu/tree.c | 73 | 
1 files changed, 56 insertions, 17 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 81105141b6a8..1694a6b57ad8 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -364,7 +364,7 @@ bool rcu_eqs_special_set(int cpu)   *   * The caller must have disabled interrupts and must not be idle.   */ -static void __maybe_unused rcu_momentary_dyntick_idle(void) +void rcu_momentary_dyntick_idle(void)  {  	int special; @@ -375,6 +375,7 @@ static void __maybe_unused rcu_momentary_dyntick_idle(void)  	WARN_ON_ONCE(!(special & RCU_DYNTICK_CTRL_CTR));  	rcu_preempt_deferred_qs(current);  } +EXPORT_SYMBOL_GPL(rcu_momentary_dyntick_idle);  /**   * rcu_is_cpu_rrupt_from_idle - see if interrupted from idle @@ -496,7 +497,7 @@ module_param_cb(jiffies_till_next_fqs, &next_fqs_jiffies_ops, &jiffies_till_next  module_param(rcu_kick_kthreads, bool, 0644);  static void force_qs_rnp(int (*f)(struct rcu_data *rdp)); -static int rcu_pending(void); +static int rcu_pending(int user);  /*   * Return the number of RCU GPs completed thus far for debug & stats. @@ -824,6 +825,11 @@ static __always_inline void rcu_nmi_enter_common(bool irq)  			rcu_cleanup_after_idle();  		incby = 1; +	} else if (tick_nohz_full_cpu(rdp->cpu) && +		   rdp->dynticks_nmi_nesting == DYNTICK_IRQ_NONIDLE && +		   READ_ONCE(rdp->rcu_urgent_qs) && !rdp->rcu_forced_tick) { +		rdp->rcu_forced_tick = true; +		tick_dep_set_cpu(rdp->cpu, TICK_DEP_BIT_RCU);  	}  	trace_rcu_dyntick(incby == 1 ? TPS("Endirq") : TPS("++="),  			  rdp->dynticks_nmi_nesting, @@ -885,6 +891,21 @@ void rcu_irq_enter_irqson(void)  	local_irq_restore(flags);  } +/* + * If any sort of urgency was applied to the current CPU (for example, + * the scheduler-clock interrupt was enabled on a nohz_full CPU) in order + * to get to a quiescent state, disable it. + */ +static void rcu_disable_urgency_upon_qs(struct rcu_data *rdp) +{ +	WRITE_ONCE(rdp->rcu_urgent_qs, false); +	WRITE_ONCE(rdp->rcu_need_heavy_qs, false); +	if (tick_nohz_full_cpu(rdp->cpu) && rdp->rcu_forced_tick) { +		tick_dep_clear_cpu(rdp->cpu, TICK_DEP_BIT_RCU); +		rdp->rcu_forced_tick = false; +	} +} +  /**   * rcu_is_watching - see if RCU thinks that the current CPU is not idle   * @@ -1073,6 +1094,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)  	if (tick_nohz_full_cpu(rdp->cpu) &&  		   time_after(jiffies,  			      READ_ONCE(rdp->last_fqs_resched) + jtsq * 3)) { +		WRITE_ONCE(*ruqp, true);  		resched_cpu(rdp->cpu);  		WRITE_ONCE(rdp->last_fqs_resched, jiffies);  	} @@ -1968,7 +1990,6 @@ rcu_report_qs_rdp(int cpu, struct rcu_data *rdp)  		return;  	}  	mask = rdp->grpmask; -	rdp->core_needs_qs = false;  	if ((rnp->qsmask & mask) == 0) {  		raw_spin_unlock_irqrestore_rcu_node(rnp, flags);  	} else { @@ -1979,6 +2000,7 @@ rcu_report_qs_rdp(int cpu, struct rcu_data *rdp)  		if (!offloaded)  			needwake = rcu_accelerate_cbs(rnp, rdp); +		rcu_disable_urgency_upon_qs(rdp);  		rcu_report_qs_rnp(mask, rnp, rnp->gp_seq, flags);  		/* ^^^ Released rnp->lock */  		if (needwake) @@ -2101,6 +2123,9 @@ int rcutree_dead_cpu(unsigned int cpu)  	rcu_boost_kthread_setaffinity(rnp, -1);  	/* Do any needed no-CB deferred wakeups from this CPU. */  	do_nocb_deferred_wakeup(per_cpu_ptr(&rcu_data, cpu)); + +	// Stop-machine done, so allow nohz_full to disable tick. +	tick_dep_clear(TICK_DEP_BIT_RCU);  	return 0;  } @@ -2151,6 +2176,7 @@ static void rcu_do_batch(struct rcu_data *rdp)  	rcu_nocb_unlock_irqrestore(rdp, flags);  	/* Invoke callbacks. */ +	tick_dep_set_task(current, TICK_DEP_BIT_RCU);  	rhp = rcu_cblist_dequeue(&rcl);  	for (; rhp; rhp = rcu_cblist_dequeue(&rcl)) {  		debug_rcu_head_unqueue(rhp); @@ -2217,6 +2243,7 @@ static void rcu_do_batch(struct rcu_data *rdp)  	/* Re-invoke RCU core processing if there are callbacks remaining. */  	if (!offloaded && rcu_segcblist_ready_cbs(&rdp->cblist))  		invoke_rcu_core(); +	tick_dep_clear_task(current, TICK_DEP_BIT_RCU);  }  /* @@ -2241,7 +2268,7 @@ void rcu_sched_clock_irq(int user)  		__this_cpu_write(rcu_data.rcu_urgent_qs, false);  	}  	rcu_flavor_sched_clock_irq(user); -	if (rcu_pending()) +	if (rcu_pending(user))  		invoke_rcu_core();  	trace_rcu_utilization(TPS("End scheduler-tick")); @@ -2259,6 +2286,7 @@ static void force_qs_rnp(int (*f)(struct rcu_data *rdp))  	int cpu;  	unsigned long flags;  	unsigned long mask; +	struct rcu_data *rdp;  	struct rcu_node *rnp;  	rcu_for_each_leaf_node(rnp) { @@ -2283,8 +2311,11 @@ static void force_qs_rnp(int (*f)(struct rcu_data *rdp))  		for_each_leaf_node_possible_cpu(rnp, cpu) {  			unsigned long bit = leaf_node_cpu_bit(rnp, cpu);  			if ((rnp->qsmask & bit) != 0) { -				if (f(per_cpu_ptr(&rcu_data, cpu))) +				rdp = per_cpu_ptr(&rcu_data, cpu); +				if (f(rdp)) {  					mask |= bit; +					rcu_disable_urgency_upon_qs(rdp); +				}  			}  		}  		if (mask != 0) { @@ -2312,7 +2343,7 @@ void rcu_force_quiescent_state(void)  	rnp = __this_cpu_read(rcu_data.mynode);  	for (; rnp != NULL; rnp = rnp->parent) {  		ret = (READ_ONCE(rcu_state.gp_flags) & RCU_GP_FLAG_FQS) || -		      !raw_spin_trylock(&rnp->fqslock); +		       !raw_spin_trylock(&rnp->fqslock);  		if (rnp_old != NULL)  			raw_spin_unlock(&rnp_old->fqslock);  		if (ret) @@ -2786,8 +2817,9 @@ EXPORT_SYMBOL_GPL(cond_synchronize_rcu);   * CPU-local state are performed first.  However, we must check for CPU   * stalls first, else we might not get a chance.   */ -static int rcu_pending(void) +static int rcu_pending(int user)  { +	bool gp_in_progress;  	struct rcu_data *rdp = this_cpu_ptr(&rcu_data);  	struct rcu_node *rnp = rdp->mynode; @@ -2798,12 +2830,13 @@ static int rcu_pending(void)  	if (rcu_nocb_need_deferred_wakeup(rdp))  		return 1; -	/* Is this CPU a NO_HZ_FULL CPU that should ignore RCU? */ -	if (rcu_nohz_full_cpu()) +	/* Is this a nohz_full CPU in userspace or idle?  (Ignore RCU if so.) */ +	if ((user || rcu_is_cpu_rrupt_from_idle()) && rcu_nohz_full_cpu())  		return 0;  	/* Is the RCU core waiting for a quiescent state from this CPU? */ -	if (rdp->core_needs_qs && !rdp->cpu_no_qs.b.norm) +	gp_in_progress = rcu_gp_in_progress(); +	if (rdp->core_needs_qs && !rdp->cpu_no_qs.b.norm && gp_in_progress)  		return 1;  	/* Does this CPU have callbacks ready to invoke? */ @@ -2811,8 +2844,7 @@ static int rcu_pending(void)  		return 1;  	/* Has RCU gone idle with this CPU needing another grace period? */ -	if (!rcu_gp_in_progress() && -	    rcu_segcblist_is_enabled(&rdp->cblist) && +	if (!gp_in_progress && rcu_segcblist_is_enabled(&rdp->cblist) &&  	    (!IS_ENABLED(CONFIG_RCU_NOCB_CPU) ||  	     !rcu_segcblist_is_offloaded(&rdp->cblist)) &&  	    !rcu_segcblist_restempty(&rdp->cblist, RCU_NEXT_READY_TAIL)) @@ -2845,7 +2877,7 @@ static void rcu_barrier_callback(struct rcu_head *rhp)  {  	if (atomic_dec_and_test(&rcu_state.barrier_cpu_count)) {  		rcu_barrier_trace(TPS("LastCB"), -1, -				   rcu_state.barrier_sequence); +				  rcu_state.barrier_sequence);  		complete(&rcu_state.barrier_completion);  	} else {  		rcu_barrier_trace(TPS("CB"), -1, rcu_state.barrier_sequence); @@ -2869,7 +2901,7 @@ static void rcu_barrier_func(void *unused)  	} else {  		debug_rcu_head_unqueue(&rdp->barrier_head);  		rcu_barrier_trace(TPS("IRQNQ"), -1, -				   rcu_state.barrier_sequence); +				  rcu_state.barrier_sequence);  	}  	rcu_nocb_unlock(rdp);  } @@ -2896,7 +2928,7 @@ void rcu_barrier(void)  	/* Did someone else do our work for us? */  	if (rcu_seq_done(&rcu_state.barrier_sequence, s)) {  		rcu_barrier_trace(TPS("EarlyExit"), -1, -				   rcu_state.barrier_sequence); +				  rcu_state.barrier_sequence);  		smp_mb(); /* caller's subsequent code after above check. */  		mutex_unlock(&rcu_state.barrier_mutex);  		return; @@ -2928,11 +2960,11 @@ void rcu_barrier(void)  			continue;  		if (rcu_segcblist_n_cbs(&rdp->cblist)) {  			rcu_barrier_trace(TPS("OnlineQ"), cpu, -					   rcu_state.barrier_sequence); +					  rcu_state.barrier_sequence);  			smp_call_function_single(cpu, rcu_barrier_func, NULL, 1);  		} else {  			rcu_barrier_trace(TPS("OnlineNQ"), cpu, -					   rcu_state.barrier_sequence); +					  rcu_state.barrier_sequence);  		}  	}  	put_online_cpus(); @@ -3083,6 +3115,9 @@ int rcutree_online_cpu(unsigned int cpu)  		return 0; /* Too early in boot for scheduler work. */  	sync_sched_exp_online_cleanup(cpu);  	rcutree_affinity_setting(cpu, -1); + +	// Stop-machine done, so allow nohz_full to disable tick. +	tick_dep_clear(TICK_DEP_BIT_RCU);  	return 0;  } @@ -3103,6 +3138,9 @@ int rcutree_offline_cpu(unsigned int cpu)  	raw_spin_unlock_irqrestore_rcu_node(rnp, flags);  	rcutree_affinity_setting(cpu, cpu); + +	// nohz_full CPUs need the tick for stop-machine to work quickly +	tick_dep_set(TICK_DEP_BIT_RCU);  	return 0;  } @@ -3148,6 +3186,7 @@ void rcu_cpu_starting(unsigned int cpu)  	rdp->rcu_onl_gp_seq = READ_ONCE(rcu_state.gp_seq);  	rdp->rcu_onl_gp_flags = READ_ONCE(rcu_state.gp_flags);  	if (rnp->qsmask & mask) { /* RCU waiting on incoming CPU? */ +		rcu_disable_urgency_upon_qs(rdp);  		/* Report QS -after- changing ->qsmaskinitnext! */  		rcu_report_qs_rnp(mask, rnp, rnp->gp_seq, flags);  	} else {  | 
