Commit a773abf7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rcu-urgent.2022.01.26a' of...

Merge tag 'rcu-urgent.2022.01.26a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu

Pull RCU fix from Paul McKenney:
 "This fixes a brown-paper-bag bug in RCU tasks that causes things like
  BPF and ftrace to fail miserably on systems with non-power-of-two
  numbers of CPUs.

  It fixes a math error added in 7a30871b ("rcu-tasks: Introduce
  ->percpu_enqueue_shift for dynamic queue selection') during the v5.17
  merge window. This commit works correctly only on systems with a
  power-of-two number of CPUs, which just so happens to be the kind that
  rcutorture always uses by default.

  This pull request fixes the math so that things also work on systems
  that don't happen to have a power-of-two number of CPUs"

* tag 'rcu-urgent.2022.01.26a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu:
  rcu-tasks: Fix computation of CPU-to-list shift counts
parents 56a14c69 da123016
...@@ -123,7 +123,7 @@ static struct rcu_tasks rt_name = \ ...@@ -123,7 +123,7 @@ static struct rcu_tasks rt_name = \
.call_func = call, \ .call_func = call, \
.rtpcpu = &rt_name ## __percpu, \ .rtpcpu = &rt_name ## __percpu, \
.name = n, \ .name = n, \
.percpu_enqueue_shift = ilog2(CONFIG_NR_CPUS), \ .percpu_enqueue_shift = ilog2(CONFIG_NR_CPUS) + 1, \
.percpu_enqueue_lim = 1, \ .percpu_enqueue_lim = 1, \
.percpu_dequeue_lim = 1, \ .percpu_dequeue_lim = 1, \
.barrier_q_mutex = __MUTEX_INITIALIZER(rt_name.barrier_q_mutex), \ .barrier_q_mutex = __MUTEX_INITIALIZER(rt_name.barrier_q_mutex), \
...@@ -216,6 +216,7 @@ static void cblist_init_generic(struct rcu_tasks *rtp) ...@@ -216,6 +216,7 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
int cpu; int cpu;
unsigned long flags; unsigned long flags;
int lim; int lim;
int shift;
raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags); raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
if (rcu_task_enqueue_lim < 0) { if (rcu_task_enqueue_lim < 0) {
...@@ -229,7 +230,10 @@ static void cblist_init_generic(struct rcu_tasks *rtp) ...@@ -229,7 +230,10 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
if (lim > nr_cpu_ids) if (lim > nr_cpu_ids)
lim = nr_cpu_ids; lim = nr_cpu_ids;
WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids / lim)); shift = ilog2(nr_cpu_ids / lim);
if (((nr_cpu_ids - 1) >> shift) >= lim)
shift++;
WRITE_ONCE(rtp->percpu_enqueue_shift, shift);
WRITE_ONCE(rtp->percpu_dequeue_lim, lim); WRITE_ONCE(rtp->percpu_dequeue_lim, lim);
smp_store_release(&rtp->percpu_enqueue_lim, lim); smp_store_release(&rtp->percpu_enqueue_lim, lim);
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
...@@ -298,7 +302,7 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func, ...@@ -298,7 +302,7 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
if (unlikely(needadjust)) { if (unlikely(needadjust)) {
raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags); raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
if (rtp->percpu_enqueue_lim != nr_cpu_ids) { if (rtp->percpu_enqueue_lim != nr_cpu_ids) {
WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids)); WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids) + 1);
WRITE_ONCE(rtp->percpu_dequeue_lim, nr_cpu_ids); WRITE_ONCE(rtp->percpu_dequeue_lim, nr_cpu_ids);
smp_store_release(&rtp->percpu_enqueue_lim, nr_cpu_ids); smp_store_release(&rtp->percpu_enqueue_lim, nr_cpu_ids);
pr_info("Switching %s to per-CPU callback queuing.\n", rtp->name); pr_info("Switching %s to per-CPU callback queuing.\n", rtp->name);
...@@ -413,7 +417,7 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp) ...@@ -413,7 +417,7 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
if (rcu_task_cb_adjust && ncbs <= rcu_task_collapse_lim) { if (rcu_task_cb_adjust && ncbs <= rcu_task_collapse_lim) {
raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags); raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
if (rtp->percpu_enqueue_lim > 1) { if (rtp->percpu_enqueue_lim > 1) {
WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids)); WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids) + 1);
smp_store_release(&rtp->percpu_enqueue_lim, 1); smp_store_release(&rtp->percpu_enqueue_lim, 1);
rtp->percpu_dequeue_gpseq = get_state_synchronize_rcu(); rtp->percpu_dequeue_gpseq = get_state_synchronize_rcu();
pr_info("Starting switch %s to CPU-0 callback queuing.\n", rtp->name); pr_info("Starting switch %s to CPU-0 callback queuing.\n", rtp->name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment