|
@@ -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"));
|
|
trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("dti"));
|
|
return 1;
|
|
return 1;
|
|
} else {
|
|
} else {
|
|
|
|
+ if (ULONG_CMP_LT(ACCESS_ONCE(rdp->gpnum) + ULONG_MAX / 4,
|
|
|
|
+ rdp->mynode->gpnum))
|
|
|
|
+ ACCESS_ONCE(rdp->gpwrap) = true;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1577,7 +1580,8 @@ static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp,
|
|
bool ret;
|
|
bool ret;
|
|
|
|
|
|
/* Handle the ends of any preceding grace periods first. */
|
|
/* 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. */
|
|
/* No grace period end, so just accelerate recent callbacks. */
|
|
ret = rcu_accelerate_cbs(rsp, rnp, rdp);
|
|
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"));
|
|
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,
|
|
* If the current grace period is waiting for this CPU,
|
|
* set up to detect a quiescent state, otherwise don't
|
|
* 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->passed_quiesce = 0;
|
|
rdp->qs_pending = !!(rnp->qsmask & rdp->grpmask);
|
|
rdp->qs_pending = !!(rnp->qsmask & rdp->grpmask);
|
|
zero_cpu_stall_ticks(rdp);
|
|
zero_cpu_stall_ticks(rdp);
|
|
|
|
+ ACCESS_ONCE(rdp->gpwrap) = false;
|
|
}
|
|
}
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -1616,7 +1621,8 @@ static void note_gp_changes(struct rcu_state *rsp, struct rcu_data *rdp)
|
|
local_irq_save(flags);
|
|
local_irq_save(flags);
|
|
rnp = rdp->mynode;
|
|
rnp = rdp->mynode;
|
|
if ((rdp->gpnum == ACCESS_ONCE(rnp->gpnum) &&
|
|
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. */
|
|
!raw_spin_trylock(&rnp->lock)) { /* irqs already off, so later. */
|
|
local_irq_restore(flags);
|
|
local_irq_restore(flags);
|
|
return;
|
|
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);
|
|
raw_spin_lock_irqsave(&rnp->lock, flags);
|
|
smp_mb__after_unlock_lock();
|
|
smp_mb__after_unlock_lock();
|
|
if (rdp->passed_quiesce == 0 || rdp->gpnum != rnp->gpnum ||
|
|
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
|
|
* 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? */
|
|
/* 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++;
|
|
rdp->n_rp_gp_started++;
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|