Skip to content

Commit e4f7805

Browse files
Frederic Weisbeckerpaulmckrcu
authored andcommitted
rcu/nocb: Remove buggy bypass lock contention mitigation
The bypass lock contention mitigation assumes there can be at most 2 contenders on the bypass lock, following this scheme: 1) One kthread takes the bypass lock 2) Another one spins on it and increment the contended counter 3) A third one (a bypass enqueuer) sees the contended counter on and busy loops waiting on it to decrement. However this assumption is wrong. There can be only one CPU to find the lock contended because call_rcu() (the bypass enqueuer) is the only bypass lock acquire site that may not already hold the NOCB lock beforehand, all the other sites must first contend on the NOCB lock. Therefore step 2) is impossible. The other problem is that the mitigation assumes that contenders all belong to the same rdp CPU, which is also impossible for a raw spinlock. In theory the warning could trigger if the enqueuer holds the bypass lock and another CPU flushes the bypass queue concurrently but this is prevented from all flush users: 1) NOCB kthreads only flush if they successfully _tried_ to lock the bypass lock. So no contention management here. 2) Flush on callbacks migration happen remotely when the CPU is offline. No concurrency against bypass enqueue. 3) Flush on deoffloading happen either locally with IRQs disabled or remotely when the CPU is not yet online. No concurrency against bypass enqueue. 4) Flush on barrier entrain happen either locally with IRQs disabled or remotely when the CPU is offline. No concurrency against bypass enqueue. For those reasons, the bypass lock contention mitigation isn't needed and is even wrong. Remove it but keep the warning reporting a contended bypass lock on a remote CPU, to keep unexpected contention awareness. Signed-off-by: Frederic Weisbecker <[email protected]> Signed-off-by: Paul E. McKenney <[email protected]>
1 parent 483d5bf commit e4f7805

File tree

2 files changed

+6
-27
lines changed

2 files changed

+6
-27
lines changed

kernel/rcu/tree.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,6 @@ struct rcu_data {
223223
struct swait_queue_head nocb_state_wq; /* For offloading state changes */
224224
struct task_struct *nocb_gp_kthread;
225225
raw_spinlock_t nocb_lock; /* Guard following pair of fields. */
226-
atomic_t nocb_lock_contended; /* Contention experienced. */
227226
int nocb_defer_wakeup; /* Defer wakeup of nocb_kthread. */
228227
struct timer_list nocb_timer; /* Enforce finite deferral. */
229228
unsigned long nocb_gp_adv_time; /* Last call_rcu() CB adv (jiffies). */

kernel/rcu/tree_nocb.h

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -91,38 +91,20 @@ module_param(nocb_nobypass_lim_per_jiffy, int, 0);
9191

9292
/*
9393
* Acquire the specified rcu_data structure's ->nocb_bypass_lock. If the
94-
* lock isn't immediately available, increment ->nocb_lock_contended to
95-
* flag the contention.
94+
* lock isn't immediately available, perform minimal sanity check.
9695
*/
9796
static void rcu_nocb_bypass_lock(struct rcu_data *rdp)
9897
__acquires(&rdp->nocb_bypass_lock)
9998
{
10099
lockdep_assert_irqs_disabled();
101100
if (raw_spin_trylock(&rdp->nocb_bypass_lock))
102101
return;
103-
atomic_inc(&rdp->nocb_lock_contended);
102+
/*
103+
* Contention expected only when local enqueue collide with
104+
* remote flush from kthreads.
105+
*/
104106
WARN_ON_ONCE(smp_processor_id() != rdp->cpu);
105-
smp_mb__after_atomic(); /* atomic_inc() before lock. */
106107
raw_spin_lock(&rdp->nocb_bypass_lock);
107-
smp_mb__before_atomic(); /* atomic_dec() after lock. */
108-
atomic_dec(&rdp->nocb_lock_contended);
109-
}
110-
111-
/*
112-
* Spinwait until the specified rcu_data structure's ->nocb_lock is
113-
* not contended. Please note that this is extremely special-purpose,
114-
* relying on the fact that at most two kthreads and one CPU contend for
115-
* this lock, and also that the two kthreads are guaranteed to have frequent
116-
* grace-period-duration time intervals between successive acquisitions
117-
* of the lock. This allows us to use an extremely simple throttling
118-
* mechanism, and further to apply it only to the CPU doing floods of
119-
* call_rcu() invocations. Don't try this at home!
120-
*/
121-
static void rcu_nocb_wait_contended(struct rcu_data *rdp)
122-
{
123-
WARN_ON_ONCE(smp_processor_id() != rdp->cpu);
124-
while (WARN_ON_ONCE(atomic_read(&rdp->nocb_lock_contended)))
125-
cpu_relax();
126108
}
127109

128110
/*
@@ -510,7 +492,6 @@ static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
510492
}
511493

512494
// We need to use the bypass.
513-
rcu_nocb_wait_contended(rdp);
514495
rcu_nocb_bypass_lock(rdp);
515496
ncbs = rcu_cblist_n_cbs(&rdp->nocb_bypass);
516497
rcu_segcblist_inc_len(&rdp->cblist); /* Must precede enqueue. */
@@ -1631,12 +1612,11 @@ static void show_rcu_nocb_state(struct rcu_data *rdp)
16311612

16321613
sprintf(bufw, "%ld", rsclp->gp_seq[RCU_WAIT_TAIL]);
16331614
sprintf(bufr, "%ld", rsclp->gp_seq[RCU_NEXT_READY_TAIL]);
1634-
pr_info(" CB %d^%d->%d %c%c%c%c%c%c F%ld L%ld C%d %c%c%s%c%s%c%c q%ld %c CPU %d%s\n",
1615+
pr_info(" CB %d^%d->%d %c%c%c%c%c F%ld L%ld C%d %c%c%s%c%s%c%c q%ld %c CPU %d%s\n",
16351616
rdp->cpu, rdp->nocb_gp_rdp->cpu,
16361617
nocb_next_rdp ? nocb_next_rdp->cpu : -1,
16371618
"kK"[!!rdp->nocb_cb_kthread],
16381619
"bB"[raw_spin_is_locked(&rdp->nocb_bypass_lock)],
1639-
"cC"[!!atomic_read(&rdp->nocb_lock_contended)],
16401620
"lL"[raw_spin_is_locked(&rdp->nocb_lock)],
16411621
"sS"[!!rdp->nocb_cb_sleep],
16421622
".W"[swait_active(&rdp->nocb_cb_wq)],

0 commit comments

Comments
 (0)