diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/rcu/tree.c | 17 | ||||
| -rw-r--r-- | kernel/rcu/tree.h | 1 | ||||
| -rw-r--r-- | kernel/rcu/tree_plugin.h | 3 | 
3 files changed, 15 insertions, 6 deletions
| diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index a2ceb66bcd67..5987fdc85fc4 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -930,6 +930,9 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp,  		trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("dti"));  		return 1;  	} else { +		if (ULONG_CMP_LT(ACCESS_ONCE(rdp->gpnum) + ULONG_MAX / 4, +				 rdp->mynode->gpnum)) +			ACCESS_ONCE(rdp->gpwrap) = true;  		return 0;  	}  } @@ -1577,7 +1580,8 @@ static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp,  	bool ret;  	/* Handle the ends of any preceding grace periods first. */ -	if (rdp->completed == rnp->completed) { +	if (rdp->completed == rnp->completed && +	    !unlikely(ACCESS_ONCE(rdp->gpwrap))) {  		/* No grace period end, so just accelerate recent callbacks. */  		ret = rcu_accelerate_cbs(rsp, rnp, rdp); @@ -1592,7 +1596,7 @@ static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp,  		trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("cpuend"));  	} -	if (rdp->gpnum != rnp->gpnum) { +	if (rdp->gpnum != rnp->gpnum || unlikely(ACCESS_ONCE(rdp->gpwrap))) {  		/*  		 * If the current grace period is waiting for this CPU,  		 * set up to detect a quiescent state, otherwise don't @@ -1603,6 +1607,7 @@ static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp,  		rdp->passed_quiesce = 0;  		rdp->qs_pending = !!(rnp->qsmask & rdp->grpmask);  		zero_cpu_stall_ticks(rdp); +		ACCESS_ONCE(rdp->gpwrap) = false;  	}  	return ret;  } @@ -1616,7 +1621,8 @@ static void note_gp_changes(struct rcu_state *rsp, struct rcu_data *rdp)  	local_irq_save(flags);  	rnp = rdp->mynode;  	if ((rdp->gpnum == ACCESS_ONCE(rnp->gpnum) && -	     rdp->completed == ACCESS_ONCE(rnp->completed)) || /* w/out lock. */ +	     rdp->completed == ACCESS_ONCE(rnp->completed) && +	     !unlikely(ACCESS_ONCE(rdp->gpwrap))) || /* w/out lock. */  	    !raw_spin_trylock(&rnp->lock)) { /* irqs already off, so later. */  		local_irq_restore(flags);  		return; @@ -2066,7 +2072,7 @@ rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp)  	raw_spin_lock_irqsave(&rnp->lock, flags);  	smp_mb__after_unlock_lock();  	if (rdp->passed_quiesce == 0 || rdp->gpnum != rnp->gpnum || -	    rnp->completed == rnp->gpnum) { +	    rnp->completed == rnp->gpnum || rdp->gpwrap) {  		/*  		 * The grace period in which this quiescent state was @@ -3190,7 +3196,8 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)  	}  	/* Has a new RCU grace period started? */ -	if (ACCESS_ONCE(rnp->gpnum) != rdp->gpnum) { /* outside lock */ +	if (ACCESS_ONCE(rnp->gpnum) != rdp->gpnum || +	    unlikely(ACCESS_ONCE(rdp->gpwrap))) { /* outside lock */  		rdp->n_rp_gp_started++;  		return 1;  	} diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 5ec81cf938fd..7472ff388d55 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -260,6 +260,7 @@ struct rcu_data {  	bool		passed_quiesce;	/* User-mode/idle loop etc. */  	bool		qs_pending;	/* Core waits for quiesc state. */  	bool		beenonline;	/* CPU online at least once. */ +	bool		gpwrap;		/* Possible gpnum/completed wrap. */  	struct rcu_node *mynode;	/* This CPU's leaf of hierarchy */  	unsigned long grpmask;		/* Mask to apply to leaf qsmask. */  #ifdef CONFIG_RCU_CPU_STALL_INFO diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 769384d77437..81ff8b9a5a39 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -1605,7 +1605,8 @@ static bool __maybe_unused rcu_try_advance_all_cbs(void)  		 * completed since we last checked and there are  		 * callbacks not yet ready to invoke.  		 */ -		if (rdp->completed != rnp->completed && +		if ((rdp->completed != rnp->completed || +		     unlikely(ACCESS_ONCE(rdp->gpwrap))) &&  		    rdp->nxttail[RCU_DONE_TAIL] != rdp->nxttail[RCU_NEXT_TAIL])  			note_gp_changes(rsp, rdp); | 
