diff options
Diffstat (limited to 'kernel/rcu/tree_exp.h')
| -rw-r--r-- | kernel/rcu/tree_exp.h | 24 | 
1 files changed, 21 insertions, 3 deletions
| diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h index 8a1d9c8bd9f7..4acd29d16fdb 100644 --- a/kernel/rcu/tree_exp.h +++ b/kernel/rcu/tree_exp.h @@ -265,7 +265,12 @@ static bool sync_exp_work_done(unsigned long s)  {  	if (rcu_exp_gp_seq_done(s)) {  		trace_rcu_exp_grace_period(rcu_state.name, s, TPS("done")); -		smp_mb(); /* Ensure test happens before caller kfree(). */ +		/* +		 * Order GP completion with preceding accesses. Order also GP +		 * completion with post GP update side accesses. Pairs with +		 * rcu_seq_end(). +		 */ +		smp_mb();  		return true;  	}  	return false; @@ -357,7 +362,21 @@ static void __sync_rcu_exp_select_node_cpus(struct rcu_exp_work *rewp)  		    !(rnp->qsmaskinitnext & mask)) {  			mask_ofl_test |= mask;  		} else { -			snap = rcu_dynticks_snap(cpu); +			/* +			 * Full ordering between remote CPU's post idle accesses +			 * and updater's accesses prior to current GP (and also +			 * the started GP sequence number) is enforced by +			 * rcu_seq_start() implicit barrier, relayed by kworkers +			 * locking and even further by smp_mb__after_unlock_lock() +			 * barriers chained all the way throughout the rnp locking +			 * tree since sync_exp_reset_tree() and up to the current +			 * leaf rnp locking. +			 * +			 * Ordering between remote CPU's pre idle accesses and +			 * post grace period updater's accesses is enforced by the +			 * below acquire semantic. +			 */ +			snap = ct_dynticks_cpu_acquire(cpu);  			if (rcu_dynticks_in_eqs(snap))  				mask_ofl_test |= mask;  			else @@ -953,7 +972,6 @@ void synchronize_rcu_expedited(void)  	rnp = rcu_get_root();  	wait_event(rnp->exp_wq[rcu_seq_ctr(s) & 0x3],  		   sync_exp_work_done(s)); -	smp_mb(); /* Work actions happen before return. */  	/* Let the next expedited grace period start. */  	mutex_unlock(&rcu_state.exp_mutex); |