Skip to contentSkip to conversation

cpu stopper threads and load balancing leads to deadlock

DISCUSSION Matt Fleming 6 participants 28 messages Apr 17, 2018 – May 22, 2018

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

Hi guys,

We've seen a bug in one of our SLE kernels where the cpu stopper thread ("migration/15") is entering idle balance. This then triggers active load balance.

At the same time, a task on another CPU triggers a page fault and NUMA balancing kicks in to try and migrate the task closer to the NUMA node for that page (we're inside stop_two_cpus()). This faulting task is spinning in try_to_wake_up() (inside smp_cond_load_acquire(&p->on_cpu, !VAL)), waiting for "migration/15" to context switch.

Unfortunately, because "migration/15" is doing active load balance it's spinning waiting for the NUMA-page-faulting CPU's stopper lock, which is already held (since it's inside stop_two_cpus()).

Deadlock ensues.

This seems like a situation that should be prohibited, but I cannot find any code to prevent it. Is it OK for stopper threads to load balance? Is there something that should prevent this situation from happening?

#1 lore raw
Quoted 16 lines · Matt Fleming

Hi guys,

We've seen a bug in one of our SLE kernels where the cpu stopper thread ("migration/15") is entering idle balance. This then triggers active load balance.

At the same time, a task on another CPU triggers a page fault and NUMA balancing kicks in to try and migrate the task closer to the NUMA node for that page (we're inside stop_two_cpus()). This faulting task is spinning in try_to_wake_up() (inside smp_cond_load_acquire(&p->on_cpu, !VAL)), waiting for "migration/15" to context switch.

Unfortunately, because "migration/15" is doing active load balance it's spinning waiting for the NUMA-page-faulting CPU's stopper lock, which is already held (since it's inside stop_two_cpus()).

Quoted 6 lines

Deadlock ensues.

This seems like a situation that should be prohibited, but I cannot find any code to prevent it. Is it OK for stopper threads to load balance? Is there something that should prevent this situation from happening?

I don't see anything to stop the deadlock either, would exclude stop class from playing idle balancer entirely, though I suppose you could check for caller being stop class in need_active_balance(). I don't think any RT class playing idle balancer is particularly wonderful.

-Mike

#2 lore raw
Quoted 19 lines · Mike Galbraith
Quoted 18 lines · Matt Fleming

Hi guys,

We've seen a bug in one of our SLE kernels where the cpu stopper thread ("migration/15") is entering idle balance. This then triggers active load balance.

At the same time, a task on another CPU triggers a page fault and NUMA balancing kicks in to try and migrate the task closer to the NUMA node for that page (we're inside stop_two_cpus()). This faulting task is spinning in try_to_wake_up() (inside smp_cond_load_acquire(&p->on_cpu, !VAL)), waiting for "migration/15" to context switch.

Unfortunately, because "migration/15" is doing active load balance it's spinning waiting for the NUMA-page-faulting CPU's stopper lock, which is already held (since it's inside stop_two_cpus()).

Deadlock ensues.

Quoted 7 lines
Quoted 4 lines

This seems like a situation that should be prohibited, but I cannot find any code to prevent it. Is it OK for stopper threads to load balance? Is there something that should prevent this situation from happening?

I don't see anything to stop the deadlock either, would exclude stop class from playing idle balancer entirely...

Bah, insufficient: __do_softirq() -> rebalance_domains() still bites.

maintainer
#3 lore raw
In reply to Matt Fleming
Quoted 12 lines · Matt Fleming

Hi guys,

We've seen a bug in one of our SLE kernels where the cpu stopper thread ("migration/15") is entering idle balance. This then triggers active load balance.

At the same time, a task on another CPU triggers a page fault and NUMA balancing kicks in to try and migrate the task closer to the NUMA node for that page (we're inside stop_two_cpus()). This faulting task is spinning in try_to_wake_up() (inside smp_cond_load_acquire(&p->on_cpu, !VAL)), waiting for "migration/15" to context switch.

Quoted 5 lines

Unfortunately, because "migration/15" is doing active load balance it's spinning waiting for the NUMA-page-faulting CPU's stopper lock, which is already held (since it's inside stop_two_cpus()).

Deadlock ensues.

So if I read that right, something like the following happens:

CPU0 CPU1

schedule(.prev=migrate/0) <fault>
pick_next_task ...

    idle_balance			    migrate_swap()
      active_balance			      stop_two_cpus()
						spin_lock(stopper0->lock)
						spin_lock(stopper1->lock)
						ttwu(migrate/0)
						  smp_cond_load_acquire() -- waits for schedule()
        stop_one_cpu(1)
	  spin_lock(stopper1->lock) -- waits for stopper lock

Fix _this_ deadlock by taking out the wakeups from under stopper->lock. I'm not entirely sure there isn't more dragons here, but this particular one seems fixable by doing that.

Is there any way you can reproduce/test this?

---
 kernel/stop_machine.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)
kernel/stop_machine.c +14 -5
index b7591261652d..64c0291b579c 100644
@@ -21,6 +21,7 @@
 #include <linux/smpboot.h>
 #include <linux/atomic.h>
 #include <linux/nmi.h>
+#include <linux/sched/wake_q.h>
 
 /*
  * Structure to determine completion condition and record errors.  May
@@ -65,27 +66,31 @@ static void cpu_stop_signal_done(struct cpu_stop_done *done)
 }
 
 static void __cpu_stop_queue_work(struct cpu_stopper *stopper,
-					struct cpu_stop_work *work)
+					struct cpu_stop_work *work,
+					struct wake_q_head *wakeq)
 {
 	list_add_tail(&work->list, &stopper->works);
-	wake_up_process(stopper->thread);
+	wake_q_add(wakeq, stopper->thread);
 }
 
 /* queue @work to @stopper.  if offline, @work is completed immediately */
 static bool cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work)
 {
 	struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
+	DEFINE_WAKE_Q(wakeq);
 	unsigned long flags;
 	bool enabled;
 
 	spin_lock_irqsave(&stopper->lock, flags);
 	enabled = stopper->enabled;
 	if (enabled)
-		__cpu_stop_queue_work(stopper, work);
+		__cpu_stop_queue_work(stopper, work, &wakeq);
 	else if (work->done)
 		cpu_stop_signal_done(work->done);
 	spin_unlock_irqrestore(&stopper->lock, flags);
 
+	wake_up_q(&wakeq);
+
 	return enabled;
 }
 
@@ -229,6 +234,7 @@ static int cpu_stop_queue_two_works(int cpu1, struct cpu_stop_work *work1,
 {
 	struct cpu_stopper *stopper1 = per_cpu_ptr(&cpu_stopper, cpu1);
 	struct cpu_stopper *stopper2 = per_cpu_ptr(&cpu_stopper, cpu2);
+	DEFINE_WAKE_Q(wakeq);
 	int err;
 retry:
 	spin_lock_irq(&stopper1->lock);
@@ -252,8 +258,8 @@ static int cpu_stop_queue_two_works(int cpu1, struct cpu_stop_work *work1,
 			goto unlock;
 
 	err = 0;
-	__cpu_stop_queue_work(stopper1, work1);
-	__cpu_stop_queue_work(stopper2, work2);
+	__cpu_stop_queue_work(stopper1, work1, &wakeq);
+	__cpu_stop_queue_work(stopper2, work2, &wakeq);
 unlock:
 	spin_unlock(&stopper2->lock);
 	spin_unlock_irq(&stopper1->lock);
@@ -263,6 +269,9 @@ static int cpu_stop_queue_two_works(int cpu1, struct cpu_stop_work *work1,
 			cpu_relax();
 		goto retry;
 	}
+
+	wake_up_q(&wakeq);
+
 	return err;
 }
 /**
#4 lore raw
Quoted 26 lines · Peter Zijlstra
Quoted 12 lines · Matt Fleming

Hi guys,

We've seen a bug in one of our SLE kernels where the cpu stopper thread ("migration/15") is entering idle balance. This then triggers active load balance.

At the same time, a task on another CPU triggers a page fault and NUMA balancing kicks in to try and migrate the task closer to the NUMA node for that page (we're inside stop_two_cpus()). This faulting task is spinning in try_to_wake_up() (inside smp_cond_load_acquire(&p->on_cpu, !VAL)), waiting for "migration/15" to context switch.

Quoted 5 lines

Unfortunately, because "migration/15" is doing active load balance it's spinning waiting for the NUMA-page-faulting CPU's stopper lock, which is already held (since it's inside stop_two_cpus()).

Deadlock ensues.

So if I read that right, something like the following happens:

CPU0 CPU1

schedule(.prev=migrate/0) <fault>
pick_next_task ...

Quoted 8 lines
    idle_balance			    migrate_swap()
      active_balance			      stop_two_cpus()
						spin_lock(stopper0->lock)
						spin_lock(stopper1->lock)
						ttwu(migrate/0)
						  smp_cond_load_acquire() -- waits for schedule()
        stop_one_cpu(1)
	  spin_lock(stopper1->lock) -- waits for stopper lock

Yep, that's exactly right.

Quoted 5 lines

Fix _this_ deadlock by taking out the wakeups from under stopper->lock. I'm not entirely sure there isn't more dragons here, but this particular one seems fixable by doing that.

Is there any way you can reproduce/test this?

I'm afraid I don't have any way to test this, but I can ask the customer that reported it if they can.

Either way, this fix looks good to me.

#5 lore raw
Quoted 42 lines · Matt Fleming
Quoted 26 lines · Peter Zijlstra
Quoted 12 lines · Matt Fleming

Hi guys,

We've seen a bug in one of our SLE kernels where the cpu stopper thread ("migration/15") is entering idle balance. This then triggers active load balance.

At the same time, a task on another CPU triggers a page fault and NUMA balancing kicks in to try and migrate the task closer to the NUMA node for that page (we're inside stop_two_cpus()). This faulting task is spinning in try_to_wake_up() (inside smp_cond_load_acquire(&p->on_cpu, !VAL)), waiting for "migration/15" to context switch.

Quoted 5 lines

Unfortunately, because "migration/15" is doing active load balance it's spinning waiting for the NUMA-page-faulting CPU's stopper lock, which is already held (since it's inside stop_two_cpus()).

Deadlock ensues.

So if I read that right, something like the following happens:

CPU0 CPU1

schedule(.prev=migrate/0) <fault>
pick_next_task ...

Quoted 8 lines
    idle_balance			    migrate_swap()
      active_balance			      stop_two_cpus()
						spin_lock(stopper0->lock)
						spin_lock(stopper1->lock)
						ttwu(migrate/0)
						  smp_cond_load_acquire() -- waits for schedule()
        stop_one_cpu(1)
	  spin_lock(stopper1->lock) -- waits for stopper lock

Yep, that's exactly right.

Quoted 4 lines

Fix _this_ deadlock by taking out the wakeups from under stopper->lock. I'm not entirely sure there isn't more dragons here, but this particular one seems fixable by doing that.

Quoted 6 lines
Quoted 1 line

Is there any way you can reproduce/test this?

I'm afraid I don't have any way to test this, but I can ask the customer that reported it if they can.

Either way, this fix looks good to me.

Seems there's another problem there with hotplug. Virgin tip...

[  122.147601] smpboot: CPU 4 is now offline
[  122.189701] smpboot: CPU 5 is now offline
[  122.225612] smpboot: CPU 6 is now offline
[  122.257760] smpboot: CPU 7 is now offline
[  124.172418] smpboot: CPU 2 is now offline
[  124.209121] smpboot: CPU 3 is now offline
[  124.215810] smpboot: Booting Node 0 Processor 2 APIC 0x4
[  124.216939] =============================
[  124.216939] WARNING: suspicious RCU usage
[  124.216941] 4.17.0.g66d489e-tip-default #82 Tainted: G            E    
[  124.216941] -----------------------------
[  124.216943] kernel/sched/core.c:1614 suspicious rcu_dereference_check() usage!
[  124.216944] 
               other info that might help us debug this:
[  124.216945] 
               RCU used illegally from offline CPU!
               rcu_scheduler_active = 2, debug_locks = 0
[  124.216946] 4 locks held by swapper/2/0:
[  124.216947]  #0: 000000001f9fa447 (stop_cpus_mutex){+.+.}, at: stop_machine_from_inactive_cpu+0x86/0x130
[  124.216953]  #1: 000000004cb07b3b (&stopper->lock){..-.}, at: cpu_stop_queue_work+0x2d/0x80
[  124.216958]  #2: 00000000d3a46b90 (&p->pi_lock){-.-.}, at: try_to_wake_up+0x2d/0x5f0
[  124.216964]  #3: 00000000f360767b (rcu_read_lock){....}, at: rcu_read_lock+0x0/0x80
[  124.216969] 
               stack backtrace:
[  124.216971] CPU: 2 PID: 0 Comm: swapper/2 Kdump: loaded Tainted: G            E     4.17.0.g66d489e-tip-default #82
[  124.216972] Hardware name: MEDION MS-7848/MS-7848, BIOS M7848W08.20C 09/23/2013
[  124.216973] Call Trace:
[  124.216977]  dump_stack+0x78/0xb3
[  124.216979]  ttwu_stat+0x121/0x130
[  124.216983]  try_to_wake_up+0x2c2/0x5f0
[  124.216988]  ? cpu_stop_park+0x30/0x30
[  124.216990]  cpu_stop_queue_work+0x7c/0x80
[  124.216993]  queue_stop_cpus_work+0x61/0xb0
[  124.216997]  stop_machine_from_inactive_cpu+0xd3/0x130
[  124.216999]  ? mtrr_restore+0x80/0x80
[  124.217005]  mtrr_ap_init+0x62/0x70
[  124.217008]  identify_secondary_cpu+0x18/0x80
[  124.217011]  smp_store_cpu_info+0x44/0x50
[  124.217014]  start_secondary+0x9a/0x1e0
[  124.217017]  secondary_startup_64+0xa5/0xb0
[  124.218433] ======================================================
[  124.218433] WARNING: possible circular locking dependency detected
[  124.218433] 4.17.0.g66d489e-tip-default #82 Tainted: G            E    
[  124.218434] ------------------------------------------------------
[  124.218434] swapper/2/0 is trying to acquire lock:
[  124.218434] 000000006b311cf8 ((console_sem).lock){-...}, at: down_trylock+0xf/0x30
[  124.218436] but task is already holding lock:
[  124.218436] 00000000d3a46b90 (&p->pi_lock){-.-.}, at: try_to_wake_up+0x2d/0x5f0
[  124.218438] which lock already depends on the new lock.
[  124.218438] the existing dependency chain (in reverse order) is:
[  124.218439] -> #1 (&p->pi_lock){-.-.}:
[  124.218440]        lock_acquire+0xbd/0x200
[  124.218440]        _raw_spin_lock_irqsave+0x4c/0x60
[  124.218441]        try_to_wake_up+0x2d/0x5f0
[  124.218441]        up+0x40/0x50
[  124.218441]        __up_console_sem+0x41/0x80
[  124.218441]        console_unlock+0x398/0x6b0
[  124.218442]        do_con_write.part.20+0x71b/0x9d0
[  124.218442]        con_write+0x55/0x60
[  124.218442]        do_output_char+0x181/0x200
[  124.218442]        n_tty_write+0x20a/0x460
[  124.218443]        tty_write+0x14a/0x2b0
[  124.218443]        do_iter_write+0x144/0x180
[  124.218443]        vfs_writev+0x71/0xd0
[  124.218444]        do_writev+0x51/0xd0
[  124.218444]        do_syscall_64+0x60/0x210
[  124.218444]        entry_SYSCALL_64_after_hwframe+0x49/0xbe
[  124.218445] -> #0 ((console_sem).lock){-...}:
[  124.218446]        __lock_acquire+0x436/0x770
[  124.218446]        lock_acquire+0xbd/0x200
[  124.218446]        _raw_spin_lock_irqsave+0x4c/0x60
[  124.218447]        down_trylock+0xf/0x30
[  124.218447]        __down_trylock_console_sem+0x37/0xa0
[  124.218447]        console_trylock+0x13/0x60
[  124.218447]        vprintk_emit+0x237/0x460
[  124.218448]        printk+0x48/0x4a
[  124.218448]        lockdep_rcu_suspicious+0x26/0x100
[  124.218448]        ttwu_stat+0x121/0x130
[  124.218449]        try_to_wake_up+0x2c2/0x5f0
[  124.218449]        cpu_stop_queue_work+0x7c/0x80
[  124.218449]        queue_stop_cpus_work+0x61/0xb0
[  124.218450]        stop_machine_from_inactive_cpu+0xd3/0x130
[  124.218450]        mtrr_ap_init+0x62/0x70
[  124.218450]        identify_secondary_cpu+0x18/0x80
[  124.218450]        smp_store_cpu_info+0x44/0x50
[  124.218451]        start_secondary+0x9a/0x1e0
[  124.218451]        secondary_startup_64+0xa5/0xb0
[  124.218451] other info that might help us debug this:
[  124.218452]  Possible unsafe locking scenario:
[  124.218452]        CPU0                    CPU1
[  124.218453]        ----                    ----
[  124.218453]   lock(&p->pi_lock);
[  124.218454]                                lock((console_sem).lock);
[  124.218454]                                lock(&p->pi_lock);
[  124.218455]   lock((console_sem).lock);
[  124.218456]  *** DEADLOCK ***
[  124.218456] 4 locks held by swapper/2/0:
[  124.218456]  #0: 000000001f9fa447 (stop_cpus_mutex){+.+.}, at: stop_machine_from_inactive_cpu+0x86/0x130
[  124.218458]  #1: 000000004cb07b3b (&stopper->lock){..-.}, at: cpu_stop_queue_work+0x2d/0x80
[  124.218459]  #2: 00000000d3a46b90 (&p->pi_lock){-.-.}, at: try_to_wake_up+0x2d/0x5f0
[  124.218460]  #3: 00000000f360767b (rcu_read_lock){....}, at: rcu_read_lock+0x0/0x80
[  124.218462] stack backtrace:
[  124.218462] CPU: 2 PID: 0 Comm: swapper/2 Kdump: loaded Tainted: G            E     4.17.0.g66d489e-tip-default #82
[  124.218462] Hardware name: MEDION MS-7848/MS-7848, BIOS M7848W08.20C 09/23/2013
[  124.218463] Call Trace:
[  124.218463]  dump_stack+0x78/0xb3
[  124.218463]  print_circular_bug.isra.38+0x1f3/0x200
[  124.218463]  check_prev_add.constprop.46+0x717/0x730
[  124.218464]  validate_chain.isra.42+0x652/0x980
[  124.218464]  __lock_acquire+0x436/0x770
[  124.218464]  lock_acquire+0xbd/0x200
[  124.218464]  ? down_trylock+0xf/0x30
[  124.218465]  ? vprintk_emit+0x237/0x460
[  124.218465]  _raw_spin_lock_irqsave+0x4c/0x60
[  124.218465]  ? down_trylock+0xf/0x30
[  124.218466]  down_trylock+0xf/0x30
[  124.218466]  __down_trylock_console_sem+0x37/0xa0
[  124.218466]  console_trylock+0x13/0x60
[  124.218466]  vprintk_emit+0x237/0x460
[  124.218467]  printk+0x48/0x4a
[  124.218467]  lockdep_rcu_suspicious+0x26/0x100
[  124.218467]  ttwu_stat+0x121/0x130
[  124.218467]  try_to_wake_up+0x2c2/0x5f0
[  124.218468]  ? cpu_stop_park+0x30/0x30
[  124.218468]  cpu_stop_queue_work+0x7c/0x80
[  124.218468]  queue_stop_cpus_work+0x61/0xb0
[  124.218468]  stop_machine_from_inactive_cpu+0xd3/0x130
[  124.218469]  ? mtrr_restore+0x80/0x80
[  124.218469]  mtrr_ap_init+0x62/0x70
[  124.218469]  identify_secondary_cpu+0x18/0x80
[  124.218469]  smp_store_cpu_info+0x44/0x50
[  124.218470]  start_secondary+0x9a/0x1e0
[  124.218470]  secondary_startup_64+0xa5/0xb0
[  124.478753] smpboot: Booting Node 0 Processor 3 APIC 0x6
maintainer
#6 lore raw
Quoted 26 lines · Mike Galbraith
[  124.216939] =============================
[  124.216939] WARNING: suspicious RCU usage
[  124.216941] 4.17.0.g66d489e-tip-default #82 Tainted: G            E    
[  124.216941] -----------------------------
[  124.216943] kernel/sched/core.c:1614 suspicious rcu_dereference_check() usage!
[  124.216944] 
               other info that might help us debug this:
[  124.216945] 
               RCU used illegally from offline CPU!
               rcu_scheduler_active = 2, debug_locks = 0
[  124.216946] 4 locks held by swapper/2/0:
[  124.216947]  #0: 000000001f9fa447 (stop_cpus_mutex){+.+.}, at: stop_machine_from_inactive_cpu+0x86/0x130
[  124.216953]  #1: 000000004cb07b3b (&stopper->lock){..-.}, at: cpu_stop_queue_work+0x2d/0x80
[  124.216958]  #2: 00000000d3a46b90 (&p->pi_lock){-.-.}, at: try_to_wake_up+0x2d/0x5f0
[  124.216964]  #3: 00000000f360767b (rcu_read_lock){....}, at: rcu_read_lock+0x0/0x80
[  124.216969] 
               stack backtrace:
[  124.216971] CPU: 2 PID: 0 Comm: swapper/2 Kdump: loaded Tainted: G            E     4.17.0.g66d489e-tip-default #82
[  124.216972] Hardware name: MEDION MS-7848/MS-7848, BIOS M7848W08.20C 09/23/2013
[  124.216973] Call Trace:
[  124.216977]  dump_stack+0x78/0xb3
[  124.216979]  ttwu_stat+0x121/0x130
[  124.216983]  try_to_wake_up+0x2c2/0x5f0
[  124.216988]  ? cpu_stop_park+0x30/0x30
[  124.216990]  cpu_stop_queue_work+0x7c/0x80
Quoted 8 lines
[  124.216993]  queue_stop_cpus_work+0x61/0xb0
[  124.216997]  stop_machine_from_inactive_cpu+0xd3/0x130
[  124.216999]  ? mtrr_restore+0x80/0x80
[  124.217005]  mtrr_ap_init+0x62/0x70
[  124.217008]  identify_secondary_cpu+0x18/0x80
[  124.217011]  smp_store_cpu_info+0x44/0x50
[  124.217014]  start_secondary+0x9a/0x1e0
[  124.217017]  secondary_startup_64+0xa5/0xb0

Hurm.. I don't see how this is 'new'. We moved the wakeup out from under stopper lock, but that should not affect the RCU state.

The warning is of course valid, stop_machine_from_inactive_cpu() explicitly run on an 'offline' CPU. The patch didn't change this.

#7 lore raw
Quoted 3 lines · Peter Zijlstra

Hurm.. I don't see how this is 'new'. We moved the wakeup out from under stopper lock, but that should not affect the RCU state.

No, not new, just an additional woes from same spot.

-Mike

maintainer
#8 lore raw
Quoted 6 lines · Mike Galbraith
Quoted 3 lines · Peter Zijlstra

Hurm.. I don't see how this is 'new'. We moved the wakeup out from under stopper lock, but that should not affect the RCU state.

No, not new, just an additional woes from same spot.

Ah, ok. Does somsething like this make it go away?

kernel/stop_machine.c +4 -2
index f89014a2c238..a32518c2ba4a 100644
@@ -650,8 +650,10 @@ int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
 	/* Schedule work on other CPUs and execute directly for local CPU */
 	set_state(&msdata, MULTI_STOP_PREPARE);
 	cpu_stop_init_done(&done, num_active_cpus());
-	queue_stop_cpus_work(cpu_active_mask, multi_cpu_stop, &msdata,
-			     &done);
+
+	RCU_NONIDLE(queue_stop_cpus_work(cpu_active_mask, multi_cpu_stop,
+				         &msdata, &done));
+
 	ret = multi_cpu_stop(&msdata);
 
 	/* Busy wait for completion. */
#9 lore raw
Quoted 9 lines · Peter Zijlstra
Quoted 6 lines · Mike Galbraith
Quoted 3 lines · Peter Zijlstra

Hurm.. I don't see how this is 'new'. We moved the wakeup out from under stopper lock, but that should not affect the RCU state.

No, not new, just an additional woes from same spot.

Ah, ok. Does somsething like this make it go away?

Dang. With $subject fix applied as well..

[  151.103732] smpboot: Booting Node 0 Processor 2 APIC 0x4
[  151.104908] =============================
[  151.104909] WARNING: suspicious RCU usage
[  151.104910] 4.17.0.g66d489e-tip-default #84 Tainted: G            E    
[  151.104911] -----------------------------
[  151.104912] kernel/sched/core.c:1625 suspicious rcu_dereference_check() usage!
[  151.104913] 
               other info that might help us debug this:
[  151.104914] 
               RCU used illegally from offline CPU!
               rcu_scheduler_active = 2, debug_locks = 0
[  151.104916] 3 locks held by swapper/2/0:
[  151.104916]  #0: 00000000560adb60 (stop_cpus_mutex){+.+.}, at: stop_machine_from_inactive_cpu+0x86/0x140
[  151.104923]  #1: 00000000e4fb0238 (&p->pi_lock){-.-.}, at: try_to_wake_up+0x2d/0x5f0
[  151.104929]  #2: 000000003341403b (rcu_read_lock){....}, at: rcu_read_lock+0x0/0x80
[  151.104934] 
               stack backtrace:
[  151.104937] CPU: 2 PID: 0 Comm: swapper/2 Kdump: loaded Tainted: G            E     4.17.0.g66d489e-tip-default #84
[  151.104938] Hardware name: MEDION MS-7848/MS-7848, BIOS M7848W08.20C 09/23/2013
[  151.104938] Call Trace:
[  151.104942]  dump_stack+0x78/0xb3
[  151.104945]  ttwu_stat+0x121/0x130
[  151.104949]  try_to_wake_up+0x2c2/0x5f0
[  151.104953]  ? cpu_stop_park+0x30/0x30
[  151.104956]  wake_up_q+0x4a/0x70
[  151.104959]  cpu_stop_queue_work+0x6b/0xa0
[  151.104963]  queue_stop_cpus_work+0x61/0xb0
[  151.104968]  stop_machine_from_inactive_cpu+0xd8/0x140
[  151.104970]  ? mtrr_restore+0x80/0x80
[  151.104976]  mtrr_ap_init+0x62/0x70
[  151.104979]  identify_secondary_cpu+0x18/0x80
[  151.104982]  smp_store_cpu_info+0x44/0x50
[  151.104985]  start_secondary+0x9a/0x1e0
[  151.104988]  secondary_startup_64+0xa5/0xb0
Quoted 17 lines
kernel/stop_machine.c +4 -2
index f89014a2c238..a32518c2ba4a 100644
@@ -650,8 +650,10 @@ int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
 	/* Schedule work on other CPUs and execute directly for local CPU */
 	set_state(&msdata, MULTI_STOP_PREPARE);
 	cpu_stop_init_done(&done, num_active_cpus());
-	queue_stop_cpus_work(cpu_active_mask, multi_cpu_stop, &msdata,
-			     &done);
+
+	RCU_NONIDLE(queue_stop_cpus_work(cpu_active_mask, multi_cpu_stop,
+				         &msdata, &done));
+
 	ret = multi_cpu_stop(&msdata);
 
 	/* Busy wait for completion. */
maintainer
#10 lore raw
Quoted 1 line · Mike Galbraith

Dang. With $subject fix applied as well..

That's a NO then... :-(

Quoted 30 lines
[  151.103732] smpboot: Booting Node 0 Processor 2 APIC 0x4
[  151.104908] =============================
[  151.104909] WARNING: suspicious RCU usage
[  151.104910] 4.17.0.g66d489e-tip-default #84 Tainted: G            E    
[  151.104911] -----------------------------
[  151.104912] kernel/sched/core.c:1625 suspicious rcu_dereference_check() usage!
[  151.104913] 
               other info that might help us debug this:
[  151.104914] 
               RCU used illegally from offline CPU!
               rcu_scheduler_active = 2, debug_locks = 0
[  151.104916] 3 locks held by swapper/2/0:
[  151.104916]  #0: 00000000560adb60 (stop_cpus_mutex){+.+.}, at: stop_machine_from_inactive_cpu+0x86/0x140
[  151.104923]  #1: 00000000e4fb0238 (&p->pi_lock){-.-.}, at: try_to_wake_up+0x2d/0x5f0
[  151.104929]  #2: 000000003341403b (rcu_read_lock){....}, at: rcu_read_lock+0x0/0x80
[  151.104934] 
               stack backtrace:
[  151.104937] CPU: 2 PID: 0 Comm: swapper/2 Kdump: loaded Tainted: G            E     4.17.0.g66d489e-tip-default #84
[  151.104938] Hardware name: MEDION MS-7848/MS-7848, BIOS M7848W08.20C 09/23/2013
[  151.104938] Call Trace:
[  151.104942]  dump_stack+0x78/0xb3
[  151.104945]  ttwu_stat+0x121/0x130
[  151.104949]  try_to_wake_up+0x2c2/0x5f0
[  151.104953]  ? cpu_stop_park+0x30/0x30
[  151.104956]  wake_up_q+0x4a/0x70
[  151.104959]  cpu_stop_queue_work+0x6b/0xa0
[  151.104963]  queue_stop_cpus_work+0x61/0xb0
[  151.104968]  stop_machine_from_inactive_cpu+0xd8/0x140
Quoted 15 lines
Quoted 5 lines
kernel/stop_machine.c +0 -0
index f89014a2c238..a32518c2ba4a 100644

kernel/stop_machine.c int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data, · line 657

Quoted 10 lines
kernel/stop_machine.c +4 -2
@@ -650,8 +650,10 @@ int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
 	/* Schedule work on other CPUs and execute directly for local CPU */
 	set_state(&msdata, MULTI_STOP_PREPARE);
 	cpu_stop_init_done(&done, num_active_cpus());
-	queue_stop_cpus_work(cpu_active_mask, multi_cpu_stop, &msdata,
-			     &done);
+
+	RCU_NONIDLE(queue_stop_cpus_work(cpu_active_mask, multi_cpu_stop,
+				         &msdata, &done));
+
 	ret = multi_cpu_stop(&msdata);

Paul, any clue on what else to try here? The whole MTRR setup is radically crazy but it's something we're stuck with (yay hardware) :/

So the issue is that we're doing wakeups from an offline CPU (very early during bringup) and RCU (rightfully) complains about that. I thought RCU_NONIDLE() was the magic incantation that makes RCU 'watch', but clearly it's not enough here.

#11 lore raw
Quoted 5 lines · Peter Zijlstra
Quoted 1 line · Mike Galbraith

Dang. With $subject fix applied as well..

That's a NO then... :-(

Could say who cares about oddball offline wakeup stat. <cringe>

maintainer
#12 lore raw
Quoted 8 lines · Mike Galbraith
Quoted 5 lines · Peter Zijlstra
Quoted 1 line · Mike Galbraith

Dang. With $subject fix applied as well..

That's a NO then... :-(

Could say who cares about oddball offline wakeup stat. <cringe>

Yeah, nobody.. but I don't want to have to change the wakeup code to deal with this if at all possible. That'd just add conditions that are 'always' false, except in this exceedingly rare circumstance.

So ideally we manage to tell RCU that it needs to pay attention while we're doing this here thing, which is what I thought RCU_NONIDLE() was about.

#13 lore raw
Quoted 10 lines · Peter Zijlstra
Quoted 8 lines · Mike Galbraith
Quoted 5 lines · Peter Zijlstra
Quoted 1 line · Mike Galbraith

Dang. With $subject fix applied as well..

That's a NO then... :-(

Could say who cares about oddball offline wakeup stat. <cringe>

Quoted 7 lines

Yeah, nobody.. but I don't want to have to change the wakeup code to deal with this if at all possible. That'd just add conditions that are 'always' false, except in this exceedingly rare circumstance.

So ideally we manage to tell RCU that it needs to pay attention while we're doing this here thing, which is what I thought RCU_NONIDLE() was about.

One straightforward approach would be to provide a arch-specific Kconfig option that tells notify_cpu_starting() not to bother invoking rcu_cpu_starting(). Then x86 selects this Kconfig option and invokes rcu_cpu_starting() itself early enough to avoid splats.

See the (untested, probably does not even build) patch below.

I have no idea where to insert either the "select" or the call to rcu_cpu_starting(), so I left those out. I know that putting the call too early will cause trouble, but I have no idea what constitutes "too early". :-/

Thanx, Paul

------------------------------------------------------------------------

kernel/cpu.c +2 -1
index 0db8938fbb23..58f7ea1de247 100644
@@ -948,7 +948,8 @@ void notify_cpu_starting(unsigned int cpu)
 	enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE);
 	int ret;
 
-	rcu_cpu_starting(cpu);	/* Enables RCU usage on this CPU. */
+	if (!IS_ENABLED(CONFIG_RCU_CPU_ONLINE_EARLY))
+		rcu_cpu_starting(cpu);	/* Enables RCU usage on this CPU. */
 	while (st->state < target) {
 		st->state++;
 		ret = cpuhp_invoke_callback(cpu, st->state, true, NULL, NULL);
kernel/rcu/Kconfig +3 -0
index 9210379c0353..a874c0d74797 100644
@@ -238,4 +238,7 @@ config RCU_NOCB_CPU
 	  Say Y here if you want to help to debug reduced OS jitter.
 	  Say N here if you are unsure.
 
+config RCU_CPU_ONLINE_EARLY
+       bool
+
 endmenu # "RCU Subsystem"
maintainer
#14 lore raw
Quoted 24 lines · Paul E. McKenney
Quoted 10 lines · Peter Zijlstra
Quoted 8 lines · Mike Galbraith
Quoted 5 lines · Peter Zijlstra
Quoted 1 line · Mike Galbraith

Dang. With $subject fix applied as well..

That's a NO then... :-(

Could say who cares about oddball offline wakeup stat. <cringe>

Quoted 7 lines

Yeah, nobody.. but I don't want to have to change the wakeup code to deal with this if at all possible. That'd just add conditions that are 'always' false, except in this exceedingly rare circumstance.

So ideally we manage to tell RCU that it needs to pay attention while we're doing this here thing, which is what I thought RCU_NONIDLE() was about.

One straightforward approach would be to provide a arch-specific Kconfig option that tells notify_cpu_starting() not to bother invoking rcu_cpu_starting(). Then x86 selects this Kconfig option and invokes rcu_cpu_starting() itself early enough to avoid splats.

Quoted 6 lines

See the (untested, probably does not even build) patch below.

I have no idea where to insert either the "select" or the call to rcu_cpu_starting(), so I left those out. I know that putting the call too early will cause trouble, but I have no idea what constitutes "too early". :-/

Something like so perhaps? Mike, can you play around with that? Could burn your granny and eat your cookies.

arch/x86/kernel/cpu/mtrr/main.c +3 -0
index 7468de429087..07360523c3ce 100644
@@ -793,6 +793,9 @@ void mtrr_ap_init(void)
 
 	if (!use_intel() || mtrr_aps_delayed_init)
 		return;
+
+	rcu_cpu_starting(smp_processor_id());
+
 	/*
 	 * Ideally we should hold mtrr_mutex here to avoid mtrr entries
 	 * changed, but this routine will be called in cpu boot time,
kernel/rcu/tree.c +9 -0
index 2a734692a581..4dab46950fdb 100644
@@ -3775,6 +3775,8 @@ int rcutree_dead_cpu(unsigned int cpu)
 	return 0;
 }
 
+static DEFINE_PER_CPU(int, rcu_cpu_started);
+
 /*
  * Mark the specified CPU as being online so that subsequent grace periods
  * (both expedited and normal) will wait on it.  Note that this means that
@@ -3796,6 +3798,11 @@ void rcu_cpu_starting(unsigned int cpu)
 	struct rcu_node *rnp;
 	struct rcu_state *rsp;
 
+	if (per_cpu(rcu_cpu_started, cpu))
+		return;
+
+	per_cpu(rcu_cpu_started, cpu) = 1;
+
 	for_each_rcu_flavor(rsp) {
 		rdp = per_cpu_ptr(rsp->rda, cpu);
 		rnp = rdp->mynode;
@@ -3852,6 +3859,8 @@ void rcu_report_dead(unsigned int cpu)
 	preempt_enable();
 	for_each_rcu_flavor(rsp)
 		rcu_cleanup_dying_idle_cpu(cpu, rsp);
+
+	per_cpu(rcu_cpu_started, cpu) = 0;
 }
 
 /* Migrate the dead CPU's callbacks to the current CPU. */
#15 lore raw
Quoted 64 lines · Peter Zijlstra
Quoted 24 lines · Paul E. McKenney
Quoted 10 lines · Peter Zijlstra
Quoted 8 lines · Mike Galbraith
Quoted 5 lines · Peter Zijlstra
Quoted 1 line · Mike Galbraith

Dang. With $subject fix applied as well..

That's a NO then... :-(

Could say who cares about oddball offline wakeup stat. <cringe>

Quoted 7 lines

Yeah, nobody.. but I don't want to have to change the wakeup code to deal with this if at all possible. That'd just add conditions that are 'always' false, except in this exceedingly rare circumstance.

So ideally we manage to tell RCU that it needs to pay attention while we're doing this here thing, which is what I thought RCU_NONIDLE() was about.

One straightforward approach would be to provide a arch-specific Kconfig option that tells notify_cpu_starting() not to bother invoking rcu_cpu_starting(). Then x86 selects this Kconfig option and invokes rcu_cpu_starting() itself early enough to avoid splats.

Quoted 6 lines

See the (untested, probably does not even build) patch below.

I have no idea where to insert either the "select" or the call to rcu_cpu_starting(), so I left those out. I know that putting the call too early will cause trouble, but I have no idea what constitutes "too early". :-/

Something like so perhaps? Mike, can you play around with that? Could burn your granny and eat your cookies.

arch/x86/kernel/cpu/mtrr/main.c +3 -0
index 7468de429087..07360523c3ce 100644
@@ -793,6 +793,9 @@ void mtrr_ap_init(void)
 
 	if (!use_intel() || mtrr_aps_delayed_init)
 		return;
+
+	rcu_cpu_starting(smp_processor_id());
+
 	/*
 	 * Ideally we should hold mtrr_mutex here to avoid mtrr entries
 	 * changed, but this routine will be called in cpu boot time,
kernel/rcu/tree.c +2 -0
index 2a734692a581..4dab46950fdb 100644
@@ -3775,6 +3775,8 @@ int rcutree_dead_cpu(unsigned int cpu)
 	return 0;
 }
 
+static DEFINE_PER_CPU(int, rcu_cpu_started);
+
 /*
  * Mark the specified CPU as being online so that subsequent grace periods
  * (both expedited and normal) will wait on it.  Note that this means that

kernel/rcu/tree.c void rcu_cpu_starting(unsigned int cpu) · line 3801

Quoted 4 lines
kernel/rcu/tree.c +1 -0
@@ -3796,6 +3798,11 @@ void rcu_cpu_starting(unsigned int cpu)
 	struct rcu_node *rnp;
 	struct rcu_state *rsp;
 
+	if (per_cpu(rcu_cpu_started, cpu))

I would log a non-splat dmesg the first time this happened, just for my future sanity, but otherwise looks fine. I am a bit concerned about calls to rcu_cpu_starting() getting sprinkled all through the code. Or am I being excessively paranoid?

Thanx, Paul

Quoted 17 lines
kernel/rcu/tree.c +6 -0
+		return;
+
+	per_cpu(rcu_cpu_started, cpu) = 1;
+
 	for_each_rcu_flavor(rsp) {
 		rdp = per_cpu_ptr(rsp->rda, cpu);
 		rnp = rdp->mynode;
@@ -3852,6 +3859,8 @@ void rcu_report_dead(unsigned int cpu)
 	preempt_enable();
 	for_each_rcu_flavor(rsp)
 		rcu_cleanup_dying_idle_cpu(cpu, rsp);
+
+	per_cpu(rcu_cpu_started, cpu) = 0;
 }
 
 /* Migrate the dead CPU's callbacks to the current CPU. */
maintainer
#16 lore raw
Quoted 6 lines · Paul E. McKenney

kernel/rcu/tree.c void rcu_cpu_starting(unsigned int cpu) · line 3801

Quoted 1 line
kernel/rcu/tree.c +1 -0
+	if (per_cpu(rcu_cpu_started, cpu))

I would log a non-splat dmesg the first time this happened, just for my future sanity, but otherwise looks fine. I am a bit concerned about calls to rcu_cpu_starting() getting sprinkled all through the code. Or am I being excessively paranoid?

Don't think so, but lets first see if this at all works. If not we'll need to figure out something else anyway.

#17 lore raw
Quoted 10 lines · Peter Zijlstra
Quoted 6 lines · Paul E. McKenney

kernel/rcu/tree.c void rcu_cpu_starting(unsigned int cpu) · line 3801

Quoted 1 line
kernel/rcu/tree.c +1 -0
+	if (per_cpu(rcu_cpu_started, cpu))

I would log a non-splat dmesg the first time this happened, just for my future sanity, but otherwise looks fine. I am a bit concerned about calls to rcu_cpu_starting() getting sprinkled all through the code. Or am I being excessively paranoid?

Don't think so, but lets first see if this at all works. If not we'll need to figure out something else anyway.

Works for me!

Thanx, Paul

#18 lore raw
In reply to Peter Zijlstra
Quoted 3 lines · Peter Zijlstra

Something like so perhaps? Mike, can you play around with that? Could burn your granny and eat your cookies.

That worked, and nothing entertaining has happened.. yet. Hm, I could use this kernel to update my backup drive, if there's a cookie monster lurking, that might get its attention :)

Quoted 48 lines
arch/x86/kernel/cpu/mtrr/main.c +3 -0
index 7468de429087..07360523c3ce 100644
@@ -793,6 +793,9 @@ void mtrr_ap_init(void)
 
 	if (!use_intel() || mtrr_aps_delayed_init)
 		return;
+
+	rcu_cpu_starting(smp_processor_id());
+
 	/*
 	 * Ideally we should hold mtrr_mutex here to avoid mtrr entries
 	 * changed, but this routine will be called in cpu boot time,
kernel/rcu/tree.c +9 -0
index 2a734692a581..4dab46950fdb 100644
@@ -3775,6 +3775,8 @@ int rcutree_dead_cpu(unsigned int cpu)
 	return 0;
 }
 
+static DEFINE_PER_CPU(int, rcu_cpu_started);
+
 /*
  * Mark the specified CPU as being online so that subsequent grace periods
  * (both expedited and normal) will wait on it.  Note that this means that
@@ -3796,6 +3798,11 @@ void rcu_cpu_starting(unsigned int cpu)
 	struct rcu_node *rnp;
 	struct rcu_state *rsp;
 
+	if (per_cpu(rcu_cpu_started, cpu))
+		return;
+
+	per_cpu(rcu_cpu_started, cpu) = 1;
+
 	for_each_rcu_flavor(rsp) {
 		rdp = per_cpu_ptr(rsp->rda, cpu);
 		rnp = rdp->mynode;
@@ -3852,6 +3859,8 @@ void rcu_report_dead(unsigned int cpu)
 	preempt_enable();
 	for_each_rcu_flavor(rsp)
 		rcu_cleanup_dying_idle_cpu(cpu, rsp);
+
+	per_cpu(rcu_cpu_started, cpu) = 0;
 }
 
 /* Migrate the dead CPU's callbacks to the current CPU. */
#19 lore raw
In reply to Peter Zijlstra
Quoted 27 lines · Peter Zijlstra
Quoted 26 lines · Paul E. McKenney
Quoted 10 lines · Peter Zijlstra
Quoted 8 lines · Mike Galbraith
Quoted 5 lines · Peter Zijlstra
Quoted 1 line · Mike Galbraith

Dang. With $subject fix applied as well..

That's a NO then... :-(

Could say who cares about oddball offline wakeup stat. <cringe>

Quoted 7 lines

Yeah, nobody.. but I don't want to have to change the wakeup code to deal with this if at all possible. That'd just add conditions that are 'always' false, except in this exceedingly rare circumstance.

So ideally we manage to tell RCU that it needs to pay attention while we're doing this here thing, which is what I thought RCU_NONIDLE() was about.

One straightforward approach would be to provide a arch-specific Kconfig option that tells notify_cpu_starting() not to bother invoking rcu_cpu_starting(). Then x86 selects this Kconfig option and invokes rcu_cpu_starting() itself early enough to avoid splats.

See the (untested, probably does not even build) patch below.

Quoted 7 lines
Quoted 4 lines

I have no idea where to insert either the "select" or the call to rcu_cpu_starting(), so I left those out. I know that putting the call too early will cause trouble, but I have no idea what constitutes "too early". :-/

Something like so perhaps? Mike, can you play around with that? Could burn your granny and eat your cookies.

Did this get queued anywhere?

Quoted 48 lines
arch/x86/kernel/cpu/mtrr/main.c +3 -0
index 7468de429087..07360523c3ce 100644
@@ -793,6 +793,9 @@ void mtrr_ap_init(void)
 
 	if (!use_intel() || mtrr_aps_delayed_init)
 		return;
+
+	rcu_cpu_starting(smp_processor_id());
+
 	/*
 	 * Ideally we should hold mtrr_mutex here to avoid mtrr entries
 	 * changed, but this routine will be called in cpu boot time,
kernel/rcu/tree.c +9 -0
index 2a734692a581..4dab46950fdb 100644
@@ -3775,6 +3775,8 @@ int rcutree_dead_cpu(unsigned int cpu)
 	return 0;
 }
 
+static DEFINE_PER_CPU(int, rcu_cpu_started);
+
 /*
  * Mark the specified CPU as being online so that subsequent grace periods
  * (both expedited and normal) will wait on it.  Note that this means that
@@ -3796,6 +3798,11 @@ void rcu_cpu_starting(unsigned int cpu)
 	struct rcu_node *rnp;
 	struct rcu_state *rsp;
 
+	if (per_cpu(rcu_cpu_started, cpu))
+		return;
+
+	per_cpu(rcu_cpu_started, cpu) = 1;
+
 	for_each_rcu_flavor(rsp) {
 		rdp = per_cpu_ptr(rsp->rda, cpu);
 		rnp = rdp->mynode;
@@ -3852,6 +3859,8 @@ void rcu_report_dead(unsigned int cpu)
 	preempt_enable();
 	for_each_rcu_flavor(rsp)
 		rcu_cleanup_dying_idle_cpu(cpu, rsp);
+
+	per_cpu(rcu_cpu_started, cpu) = 0;
 }
 
 /* Migrate the dead CPU's callbacks to the current CPU. */
#20 lore raw
Quoted 33 lines · Mike Galbraith
Quoted 32 lines · Peter Zijlstra
Quoted 30 lines · Paul E. McKenney
Quoted 10 lines · Peter Zijlstra
Quoted 8 lines · Mike Galbraith
Quoted 5 lines · Peter Zijlstra
Quoted 1 line · Mike Galbraith

Dang. With $subject fix applied as well..

That's a NO then... :-(

Could say who cares about oddball offline wakeup stat. <cringe>

Quoted 7 lines

Yeah, nobody.. but I don't want to have to change the wakeup code to deal with this if at all possible. That'd just add conditions that are 'always' false, except in this exceedingly rare circumstance.

So ideally we manage to tell RCU that it needs to pay attention while we're doing this here thing, which is what I thought RCU_NONIDLE() was about.

One straightforward approach would be to provide a arch-specific Kconfig option that tells notify_cpu_starting() not to bother invoking rcu_cpu_starting(). Then x86 selects this Kconfig option and invokes rcu_cpu_starting() itself early enough to avoid splats.

See the (untested, probably does not even build) patch below.

I have no idea where to insert either the "select" or the call to rcu_cpu_starting(), so I left those out. I know that putting the call too early will cause trouble, but I have no idea what constitutes "too early". :-/

Quoted 4 lines
Quoted 2 lines

Something like so perhaps? Mike, can you play around with that? Could burn your granny and eat your cookies.

Did this get queued anywhere?

I have not queued it, but given Peter's Signed-off-by and your Tested-by I would be happy to do so.

Thanx, Paul

Quoted 49 lines
Quoted 48 lines
arch/x86/kernel/cpu/mtrr/main.c +3 -0
index 7468de429087..07360523c3ce 100644
@@ -793,6 +793,9 @@ void mtrr_ap_init(void)
 
 	if (!use_intel() || mtrr_aps_delayed_init)
 		return;
+
+	rcu_cpu_starting(smp_processor_id());
+
 	/*
 	 * Ideally we should hold mtrr_mutex here to avoid mtrr entries
 	 * changed, but this routine will be called in cpu boot time,
kernel/rcu/tree.c +9 -0
index 2a734692a581..4dab46950fdb 100644
@@ -3775,6 +3775,8 @@ int rcutree_dead_cpu(unsigned int cpu)
 	return 0;
 }
 
+static DEFINE_PER_CPU(int, rcu_cpu_started);
+
 /*
  * Mark the specified CPU as being online so that subsequent grace periods
  * (both expedited and normal) will wait on it.  Note that this means that
@@ -3796,6 +3798,11 @@ void rcu_cpu_starting(unsigned int cpu)
 	struct rcu_node *rnp;
 	struct rcu_state *rsp;
 
+	if (per_cpu(rcu_cpu_started, cpu))
+		return;
+
+	per_cpu(rcu_cpu_started, cpu) = 1;
+
 	for_each_rcu_flavor(rsp) {
 		rdp = per_cpu_ptr(rsp->rda, cpu);
 		rnp = rdp->mynode;
@@ -3852,6 +3859,8 @@ void rcu_report_dead(unsigned int cpu)
 	preempt_enable();
 	for_each_rcu_flavor(rsp)
 		rcu_cleanup_dying_idle_cpu(cpu, rsp);
+
+	per_cpu(rcu_cpu_started, cpu) = 0;
 }
 
 /* Migrate the dead CPU's callbacks to the current CPU. */
#21 lore raw
Quoted 9 lines · Paul E. McKenney
Quoted 4 lines · Mike Galbraith
Quoted 2 lines

Something like so perhaps? Mike, can you play around with that? Could burn your granny and eat your cookies.

Did this get queued anywhere?

I have not queued it, but given Peter's Signed-off-by and your Tested-by I would be happy to do so.

Here's the later. Tested-by: Mike Galbraith <[email protected]>

Quoted 50 lines
Quoted 49 lines
Quoted 48 lines
arch/x86/kernel/cpu/mtrr/main.c +3 -0
index 7468de429087..07360523c3ce 100644
@@ -793,6 +793,9 @@ void mtrr_ap_init(void)
 
 	if (!use_intel() || mtrr_aps_delayed_init)
 		return;
+
+	rcu_cpu_starting(smp_processor_id());
+
 	/*
 	 * Ideally we should hold mtrr_mutex here to avoid mtrr entries
 	 * changed, but this routine will be called in cpu boot time,
kernel/rcu/tree.c +9 -0
index 2a734692a581..4dab46950fdb 100644
@@ -3775,6 +3775,8 @@ int rcutree_dead_cpu(unsigned int cpu)
 	return 0;
 }
 
+static DEFINE_PER_CPU(int, rcu_cpu_started);
+
 /*
  * Mark the specified CPU as being online so that subsequent grace periods
  * (both expedited and normal) will wait on it.  Note that this means that
@@ -3796,6 +3798,11 @@ void rcu_cpu_starting(unsigned int cpu)
 	struct rcu_node *rnp;
 	struct rcu_state *rsp;
 
+	if (per_cpu(rcu_cpu_started, cpu))
+		return;
+
+	per_cpu(rcu_cpu_started, cpu) = 1;
+
 	for_each_rcu_flavor(rsp) {
 		rdp = per_cpu_ptr(rsp->rda, cpu);
 		rnp = rdp->mynode;
@@ -3852,6 +3859,8 @@ void rcu_report_dead(unsigned int cpu)
 	preempt_enable();
 	for_each_rcu_flavor(rsp)
 		rcu_cleanup_dying_idle_cpu(cpu, rsp);
+
+	per_cpu(rcu_cpu_started, cpu) = 0;
 }
 
 /* Migrate the dead CPU's callbacks to the current CPU. */
maintainer Tested-by Mike Galbraith
#22 lore raw
In reply to Paul E. McKenney
Quoted 3 lines · Paul E. McKenney

On Tue, May 15, 2018 at 06:30:26AM +0200, Mike Galbraith wrote:
I have not queued it, but given Peter's Signed-off-by and your Tested-by I would be happy to do so.

And a Changelog of course :-)

---
From: Peter Zijlstra <[email protected]>
Subject: rcu/x86: Provide early rcu_cpu_starting() callback

The x86/mtrr code does horrific things because hardware. It uses stop_machine_from_inactive_cpu(), which does a wakeup (of the stopper thread on another CPU), which uses RCU, all before the CPU is onlined.

RCU complains about this, because wakeups use RCU and RCU does (rightfully) not consider offline CPUs for grace-periods.

Fix this by initializing RCU way early in the MTRR case.

---

Quoted 50 lines
Quoted 49 lines
Quoted 48 lines
arch/x86/kernel/cpu/mtrr/main.c +3 -0
index 7468de429087..07360523c3ce 100644
@@ -793,6 +793,9 @@ void mtrr_ap_init(void)
 
 	if (!use_intel() || mtrr_aps_delayed_init)
 		return;
+
+	rcu_cpu_starting(smp_processor_id());
+
 	/*
 	 * Ideally we should hold mtrr_mutex here to avoid mtrr entries
 	 * changed, but this routine will be called in cpu boot time,
kernel/rcu/tree.c +9 -0
index 2a734692a581..4dab46950fdb 100644
@@ -3775,6 +3775,8 @@ int rcutree_dead_cpu(unsigned int cpu)
 	return 0;
 }
 
+static DEFINE_PER_CPU(int, rcu_cpu_started);
+
 /*
  * Mark the specified CPU as being online so that subsequent grace periods
  * (both expedited and normal) will wait on it.  Note that this means that
@@ -3796,6 +3798,11 @@ void rcu_cpu_starting(unsigned int cpu)
 	struct rcu_node *rnp;
 	struct rcu_state *rsp;
 
+	if (per_cpu(rcu_cpu_started, cpu))
+		return;
+
+	per_cpu(rcu_cpu_started, cpu) = 1;
+
 	for_each_rcu_flavor(rsp) {
 		rdp = per_cpu_ptr(rsp->rda, cpu);
 		rnp = rdp->mynode;
@@ -3852,6 +3859,8 @@ void rcu_report_dead(unsigned int cpu)
 	preempt_enable();
 	for_each_rcu_flavor(rsp)
 		rcu_cleanup_dying_idle_cpu(cpu, rsp);
+
+	per_cpu(rcu_cpu_started, cpu) = 0;
 }
 
 /* Migrate the dead CPU's callbacks to the current CPU. */
#23 lore raw
Quoted 6 lines · Peter Zijlstra
Quoted 3 lines · Paul E. McKenney

On Tue, May 15, 2018 at 06:30:26AM +0200, Mike Galbraith wrote:
I have not queued it, but given Peter's Signed-off-by and your Tested-by I would be happy to do so.

And a Changelog of course :-)

Thank you both!

Is this OK for 4.19, or do we need it for 4.18? I am guessing 4.18, but figured I should ask before wildly rebasing the 82 commits destined for 4.19. ;-)

Thanx, Paul

Quoted 68 lines

---
From: Peter Zijlstra <[email protected]>
Subject: rcu/x86: Provide early rcu_cpu_starting() callback

The x86/mtrr code does horrific things because hardware. It uses stop_machine_from_inactive_cpu(), which does a wakeup (of the stopper thread on another CPU), which uses RCU, all before the CPU is onlined.

RCU complains about this, because wakeups use RCU and RCU does (rightfully) not consider offline CPUs for grace-periods.

Fix this by initializing RCU way early in the MTRR case.

---

Quoted 50 lines
Quoted 49 lines
Quoted 48 lines
arch/x86/kernel/cpu/mtrr/main.c +3 -0
index 7468de429087..07360523c3ce 100644
@@ -793,6 +793,9 @@ void mtrr_ap_init(void)
 
 	if (!use_intel() || mtrr_aps_delayed_init)
 		return;
+
+	rcu_cpu_starting(smp_processor_id());
+
 	/*
 	 * Ideally we should hold mtrr_mutex here to avoid mtrr entries
 	 * changed, but this routine will be called in cpu boot time,
kernel/rcu/tree.c +9 -0
index 2a734692a581..4dab46950fdb 100644
@@ -3775,6 +3775,8 @@ int rcutree_dead_cpu(unsigned int cpu)
 	return 0;
 }
 
+static DEFINE_PER_CPU(int, rcu_cpu_started);
+
 /*
  * Mark the specified CPU as being online so that subsequent grace periods
  * (both expedited and normal) will wait on it.  Note that this means that
@@ -3796,6 +3798,11 @@ void rcu_cpu_starting(unsigned int cpu)
 	struct rcu_node *rnp;
 	struct rcu_state *rsp;
 
+	if (per_cpu(rcu_cpu_started, cpu))
+		return;
+
+	per_cpu(rcu_cpu_started, cpu) = 1;
+
 	for_each_rcu_flavor(rsp) {
 		rdp = per_cpu_ptr(rsp->rda, cpu);
 		rnp = rdp->mynode;
@@ -3852,6 +3859,8 @@ void rcu_report_dead(unsigned int cpu)
 	preempt_enable();
 	for_each_rcu_flavor(rsp)
 		rcu_cleanup_dying_idle_cpu(cpu, rsp);
+
+	per_cpu(rcu_cpu_started, cpu) = 0;
 }
 
 /* Migrate the dead CPU's callbacks to the current CPU. */
Tested-by Mike Galbraith
#24 lore raw
Quoted 6 lines · Paul E. McKenney
Quoted 5 lines · Peter Zijlstra
Quoted 3 lines · Paul E. McKenney

On Tue, May 15, 2018 at 06:30:26AM +0200, Mike Galbraith wrote:
I have not queued it, but given Peter's Signed-off-by and your Tested-by I would be happy to do so.

Quoted 7 lines
Quoted 1 line

And a Changelog of course :-)

Thank you both!

Is this OK for 4.19, or do we need it for 4.18? I am guessing 4.18, but figured I should ask before wildly rebasing the 82 commits destined for 4.19. ;-)

Hearing nothing countering my assumption, I have queued this just after my v4.18 merge point. Please see below for the commit, and please let me know if I messed anything up.

Thanx, Paul

------------------------------------------------------------------------

commit 354238a30982b817262fe6f9d00f808451694366

Author: Peter Zijlstra <[email protected]>
Date:   Tue May 22 09:50:53 2018 -0700

rcu/x86: Provide early rcu_cpu_starting() callback

The x86/mtrr code does horrific things because hardware. It uses stop_machine_from_inactive_cpu(), which does a wakeup (of the stopper thread on another CPU), which uses RCU, all before the CPU is onlined.

RCU complains about this, because wakeups use RCU and RCU does (rightfully) not consider offline CPUs for grace-periods.

Fix this by initializing RCU way early in the MTRR case.

arch/x86/kernel/cpu/mtrr/main.c +3 -0
index 7468de429087..07360523c3ce 100644
@@ -793,6 +793,9 @@ void mtrr_ap_init(void)
 
 	if (!use_intel() || mtrr_aps_delayed_init)
 		return;
+
+	rcu_cpu_starting(smp_processor_id());
+
 	/*
 	 * Ideally we should hold mtrr_mutex here to avoid mtrr entries
 	 * changed, but this routine will be called in cpu boot time,
kernel/rcu/tree.c +9 -0
index 4fccdfa25716..aa7cade1b9f3 100644
@@ -3665,6 +3665,8 @@ int rcutree_dead_cpu(unsigned int cpu)
 	return 0;
 }
 
+static DEFINE_PER_CPU(int, rcu_cpu_started);
+
 /*
  * Mark the specified CPU as being online so that subsequent grace periods
  * (both expedited and normal) will wait on it.  Note that this means that
@@ -3686,6 +3688,11 @@ void rcu_cpu_starting(unsigned int cpu)
 	struct rcu_node *rnp;
 	struct rcu_state *rsp;
 
+	if (per_cpu(rcu_cpu_started, cpu))
+		return;
+
+	per_cpu(rcu_cpu_started, cpu) = 1;
+
 	for_each_rcu_flavor(rsp) {
 		rdp = per_cpu_ptr(rsp->rda, cpu);
 		rnp = rdp->mynode;
@@ -3742,6 +3749,8 @@ void rcu_report_dead(unsigned int cpu)
 	preempt_enable();
 	for_each_rcu_flavor(rsp)
 		rcu_cleanup_dying_idle_cpu(cpu, rsp);
+
+	per_cpu(rcu_cpu_started, cpu) = 0;
 }
 
 /* Migrate the dead CPU's callbacks to the current CPU. */
#25 lore raw
In reply to Peter Zijlstra
Quoted 55 lines · Peter Zijlstra
Quoted 1 line · Mike Galbraith

Dang. With $subject fix applied as well..

That's a NO then... :-(

Quoted 30 lines
[  151.103732] smpboot: Booting Node 0 Processor 2 APIC 0x4
[  151.104908] =============================
[  151.104909] WARNING: suspicious RCU usage
[  151.104910] 4.17.0.g66d489e-tip-default #84 Tainted: G            E    
[  151.104911] -----------------------------
[  151.104912] kernel/sched/core.c:1625 suspicious rcu_dereference_check() usage!
[  151.104913] 
               other info that might help us debug this:
[  151.104914] 
               RCU used illegally from offline CPU!
               rcu_scheduler_active = 2, debug_locks = 0
[  151.104916] 3 locks held by swapper/2/0:
[  151.104916]  #0: 00000000560adb60 (stop_cpus_mutex){+.+.}, at: stop_machine_from_inactive_cpu+0x86/0x140
[  151.104923]  #1: 00000000e4fb0238 (&p->pi_lock){-.-.}, at: try_to_wake_up+0x2d/0x5f0
[  151.104929]  #2: 000000003341403b (rcu_read_lock){....}, at: rcu_read_lock+0x0/0x80
[  151.104934] 
               stack backtrace:
[  151.104937] CPU: 2 PID: 0 Comm: swapper/2 Kdump: loaded Tainted: G            E     4.17.0.g66d489e-tip-default #84
[  151.104938] Hardware name: MEDION MS-7848/MS-7848, BIOS M7848W08.20C 09/23/2013
[  151.104938] Call Trace:
[  151.104942]  dump_stack+0x78/0xb3
[  151.104945]  ttwu_stat+0x121/0x130
[  151.104949]  try_to_wake_up+0x2c2/0x5f0
[  151.104953]  ? cpu_stop_park+0x30/0x30
[  151.104956]  wake_up_q+0x4a/0x70
[  151.104959]  cpu_stop_queue_work+0x6b/0xa0
[  151.104963]  queue_stop_cpus_work+0x61/0xb0
[  151.104968]  stop_machine_from_inactive_cpu+0xd8/0x140
Quoted 15 lines
Quoted 5 lines
kernel/stop_machine.c +0 -0
index f89014a2c238..a32518c2ba4a 100644

kernel/stop_machine.c int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data, · line 657

Quoted 10 lines
kernel/stop_machine.c +4 -2
@@ -650,8 +650,10 @@ int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
 	/* Schedule work on other CPUs and execute directly for local CPU */
 	set_state(&msdata, MULTI_STOP_PREPARE);
 	cpu_stop_init_done(&done, num_active_cpus());
-	queue_stop_cpus_work(cpu_active_mask, multi_cpu_stop, &msdata,
-			     &done);
+
+	RCU_NONIDLE(queue_stop_cpus_work(cpu_active_mask, multi_cpu_stop,
+				         &msdata, &done));
+
 	ret = multi_cpu_stop(&msdata);

Paul, any clue on what else to try here? The whole MTRR setup is radically crazy but it's something we're stuck with (yay hardware) :/

Quoted 4 lines

So the issue is that we're doing wakeups from an offline CPU (very early during bringup) and RCU (rightfully) complains about that. I thought RCU_NONIDLE() was the magic incantation that makes RCU 'watch', but clearly it's not enough here.

Huh.

No, RCU_NONIDLE() only works for idle, not for offline.

Maybe... Let me take a look. There must be some way to mark a specific lock acquisition and release as being lockdep-invisible...

Another approach would be to have an architecture-specific thing that caused RCU to be enabled way earlier on x86.

Thanx, Paul

maintainer
#26 lore raw
Quoted 3 lines · Paul E. McKenney

Huh.

No, RCU_NONIDLE() only works for idle, not for offline.

Oh bummer..

Quoted 2 lines

Maybe... Let me take a look. There must be some way to mark a specific lock acquisition and release as being lockdep-invisible...

But I suspect it flags a real issue. Shutting it up isn't the issue as such. There could be a concurrent sched domain rebuild while we do this setup, and if we free that domain while we're looking at it, bad things happen.

... I wonder what brought this failure to pass now. This code has been like this a for a long time.

#27 lore raw

[tip:sched/urgent] stop_machine, sched: Fix migrate_swap() vs. active_balance() deadlock

In reply to Peter Zijlstra
stop_machine, sched: Fix migrate_swap() vs. active_balance() deadlock
Commit-ID:  0b26351b910fb8fe6a056f8a1bbccabe50c0e19f
Gitweb:     https://git.kernel.org/tip/0b26351b910fb8fe6a056f8a1bbccabe50c0e19f
Author:     Peter Zijlstra <[email protected]>
AuthorDate: Fri, 20 Apr 2018 11:50:05 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Thu, 3 May 2018 07:38:03 +0200

stop_machine, sched: Fix migrate_swap() vs. active_balance() deadlock

Matt reported the following deadlock:

CPU0 CPU1

schedule(.prev=migrate/0) <fault>
pick_next_task() ...

    idle_balance()			    migrate_swap()
      active_balance()			      stop_two_cpus()
						spin_lock(stopper0->lock)
						spin_lock(stopper1->lock)
						ttwu(migrate/0)
						  smp_cond_load_acquire() -- waits for schedule()
        stop_one_cpu(1)
	  spin_lock(stopper1->lock) -- waits for stopper lock

Fix this deadlock by taking the wakeups out from under stopper->lock. This allows the active_balance() to queue the stop work and finish the context switch, which in turn allows the wakeup from migrate_swap() to observe the context and complete the wakeup.

---
 kernel/stop_machine.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)
kernel/stop_machine.c +14 -5
index b7591261652d..64c0291b579c 100644
@@ -21,6 +21,7 @@
 #include <linux/smpboot.h>
 #include <linux/atomic.h>
 #include <linux/nmi.h>
+#include <linux/sched/wake_q.h>
 
 /*
  * Structure to determine completion condition and record errors.  May
@@ -65,27 +66,31 @@ static void cpu_stop_signal_done(struct cpu_stop_done *done)
 }
 
 static void __cpu_stop_queue_work(struct cpu_stopper *stopper,
-					struct cpu_stop_work *work)
+					struct cpu_stop_work *work,
+					struct wake_q_head *wakeq)
 {
 	list_add_tail(&work->list, &stopper->works);
-	wake_up_process(stopper->thread);
+	wake_q_add(wakeq, stopper->thread);
 }
 
 /* queue @work to @stopper.  if offline, @work is completed immediately */
 static bool cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work)
 {
 	struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
+	DEFINE_WAKE_Q(wakeq);
 	unsigned long flags;
 	bool enabled;
 
 	spin_lock_irqsave(&stopper->lock, flags);
 	enabled = stopper->enabled;
 	if (enabled)
-		__cpu_stop_queue_work(stopper, work);
+		__cpu_stop_queue_work(stopper, work, &wakeq);
 	else if (work->done)
 		cpu_stop_signal_done(work->done);
 	spin_unlock_irqrestore(&stopper->lock, flags);
 
+	wake_up_q(&wakeq);
+
 	return enabled;
 }
 
@@ -229,6 +234,7 @@ static int cpu_stop_queue_two_works(int cpu1, struct cpu_stop_work *work1,
 {
 	struct cpu_stopper *stopper1 = per_cpu_ptr(&cpu_stopper, cpu1);
 	struct cpu_stopper *stopper2 = per_cpu_ptr(&cpu_stopper, cpu2);
+	DEFINE_WAKE_Q(wakeq);
 	int err;
 retry:
 	spin_lock_irq(&stopper1->lock);
@@ -252,8 +258,8 @@ retry:
 			goto unlock;
 
 	err = 0;
-	__cpu_stop_queue_work(stopper1, work1);
-	__cpu_stop_queue_work(stopper2, work2);
+	__cpu_stop_queue_work(stopper1, work1, &wakeq);
+	__cpu_stop_queue_work(stopper2, work2, &wakeq);
 unlock:
 	spin_unlock(&stopper2->lock);
 	spin_unlock_irq(&stopper1->lock);
@@ -263,6 +269,9 @@ unlock:
 			cpu_relax();
 		goto retry;
 	}
+
+	wake_up_q(&wakeq);
+
 	return err;
 }
 /**