summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.ibm.com>2019-06-25 16:32:51 -0400
committerPaul E. McKenney <paulmck@linux.ibm.com>2019-08-13 17:38:24 -0400
commitf7a81b12d6af42a9d09be1e5f041169f04b0b67a (patch)
tree6bac3cfa8d0b88bd7b8091a88c20fc09694774ed
parent6aacd88d1721e12b013ae4ccf4f17609bd5091f3 (diff)
rcu/nocb: Print no-CBs diagnostics when rcutorture writer unduly delayed
This commit causes locking, sleeping, and callback state to be printed for no-CBs CPUs when the rcutorture writer is delayed sufficiently for rcutorture to complain. Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
-rw-r--r--kernel/rcu/rcutorture.c1
-rw-r--r--kernel/rcu/tree.h7
-rw-r--r--kernel/rcu/tree_plugin.h82
-rw-r--r--kernel/rcu/tree_stall.h5
4 files changed, 94 insertions, 1 deletions
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index b22947324423..3c9feca1eab1 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -2176,6 +2176,7 @@ rcu_torture_cleanup(void)
2176 return; 2176 return;
2177 } 2177 }
2178 2178
2179 show_rcu_gp_kthreads();
2179 rcu_torture_barrier_cleanup(); 2180 rcu_torture_barrier_cleanup();
2180 torture_stop_kthread(rcu_torture_fwd_prog, fwd_prog_task); 2181 torture_stop_kthread(rcu_torture_fwd_prog, fwd_prog_task);
2181 torture_stop_kthread(rcu_torture_stall, stall_task); 2182 torture_stop_kthread(rcu_torture_stall, stall_task);
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
index e4df86db8137..c612f306fe89 100644
--- a/kernel/rcu/tree.h
+++ b/kernel/rcu/tree.h
@@ -212,7 +212,11 @@ struct rcu_data {
212 /* The following fields are used by GP kthread, hence own cacheline. */ 212 /* The following fields are used by GP kthread, hence own cacheline. */
213 raw_spinlock_t nocb_gp_lock ____cacheline_internodealigned_in_smp; 213 raw_spinlock_t nocb_gp_lock ____cacheline_internodealigned_in_smp;
214 struct timer_list nocb_bypass_timer; /* Force nocb_bypass flush. */ 214 struct timer_list nocb_bypass_timer; /* Force nocb_bypass flush. */
215 bool nocb_gp_sleep; /* Is the nocb GP thread asleep? */ 215 u8 nocb_gp_sleep; /* Is the nocb GP thread asleep? */
216 u8 nocb_gp_bypass; /* Found a bypass on last scan? */
217 u8 nocb_gp_gp; /* GP to wait for on last scan? */
218 unsigned long nocb_gp_seq; /* If so, ->gp_seq to wait for. */
219 unsigned long nocb_gp_loops; /* # passes through wait code. */
216 struct swait_queue_head nocb_gp_wq; /* For nocb kthreads to sleep on. */ 220 struct swait_queue_head nocb_gp_wq; /* For nocb kthreads to sleep on. */
217 bool nocb_cb_sleep; /* Is the nocb CB thread asleep? */ 221 bool nocb_cb_sleep; /* Is the nocb CB thread asleep? */
218 struct task_struct *nocb_cb_kthread; 222 struct task_struct *nocb_cb_kthread;
@@ -438,6 +442,7 @@ static void do_nocb_deferred_wakeup(struct rcu_data *rdp);
438static void rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp); 442static void rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp);
439static void rcu_spawn_cpu_nocb_kthread(int cpu); 443static void rcu_spawn_cpu_nocb_kthread(int cpu);
440static void __init rcu_spawn_nocb_kthreads(void); 444static void __init rcu_spawn_nocb_kthreads(void);
445static void show_rcu_nocb_state(struct rcu_data *rdp);
441static void rcu_nocb_lock(struct rcu_data *rdp); 446static void rcu_nocb_lock(struct rcu_data *rdp);
442static void rcu_nocb_unlock(struct rcu_data *rdp); 447static void rcu_nocb_unlock(struct rcu_data *rdp);
443static void rcu_nocb_unlock_irqrestore(struct rcu_data *rdp, 448static void rcu_nocb_unlock_irqrestore(struct rcu_data *rdp,
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 97c730753a6d..25a53742ca68 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -2021,6 +2021,9 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
2021 rcu_gp_kthread_wake(); 2021 rcu_gp_kthread_wake();
2022 } 2022 }
2023 2023
2024 my_rdp->nocb_gp_bypass = bypass;
2025 my_rdp->nocb_gp_gp = needwait_gp;
2026 my_rdp->nocb_gp_seq = needwait_gp ? wait_gp_seq : 0;
2024 if (bypass && !rcu_nocb_poll) { 2027 if (bypass && !rcu_nocb_poll) {
2025 // At least one child with non-empty ->nocb_bypass, so set 2028 // At least one child with non-empty ->nocb_bypass, so set
2026 // timer in order to avoid stranding its callbacks. 2029 // timer in order to avoid stranding its callbacks.
@@ -2055,6 +2058,7 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
2055 WRITE_ONCE(my_rdp->nocb_gp_sleep, true); 2058 WRITE_ONCE(my_rdp->nocb_gp_sleep, true);
2056 raw_spin_unlock_irqrestore(&my_rdp->nocb_gp_lock, flags); 2059 raw_spin_unlock_irqrestore(&my_rdp->nocb_gp_lock, flags);
2057 } 2060 }
2061 my_rdp->nocb_gp_seq = -1;
2058 WARN_ON(signal_pending(current)); 2062 WARN_ON(signal_pending(current));
2059} 2063}
2060 2064
@@ -2071,6 +2075,7 @@ static int rcu_nocb_gp_kthread(void *arg)
2071 struct rcu_data *rdp = arg; 2075 struct rcu_data *rdp = arg;
2072 2076
2073 for (;;) { 2077 for (;;) {
2078 WRITE_ONCE(rdp->nocb_gp_loops, rdp->nocb_gp_loops + 1);
2074 nocb_gp_wait(rdp); 2079 nocb_gp_wait(rdp);
2075 cond_resched_tasks_rcu_qs(); 2080 cond_resched_tasks_rcu_qs();
2076 } 2081 }
@@ -2362,6 +2367,79 @@ void rcu_bind_current_to_nocb(void)
2362} 2367}
2363EXPORT_SYMBOL_GPL(rcu_bind_current_to_nocb); 2368EXPORT_SYMBOL_GPL(rcu_bind_current_to_nocb);
2364 2369
2370/*
2371 * Dump out nocb grace-period kthread state for the specified rcu_data
2372 * structure.
2373 */
2374static void show_rcu_nocb_gp_state(struct rcu_data *rdp)
2375{
2376 struct rcu_node *rnp = rdp->mynode;
2377
2378 pr_info("nocb GP %d %c%c%c%c%c%c %c[%c%c] %c%c:%ld rnp %d:%d %lu\n",
2379 rdp->cpu,
2380 "kK"[!!rdp->nocb_gp_kthread],
2381 "lL"[raw_spin_is_locked(&rdp->nocb_gp_lock)],
2382 "dD"[!!rdp->nocb_defer_wakeup],
2383 "tT"[timer_pending(&rdp->nocb_timer)],
2384 "bB"[timer_pending(&rdp->nocb_bypass_timer)],
2385 "sS"[!!rdp->nocb_gp_sleep],
2386 ".W"[swait_active(&rdp->nocb_gp_wq)],
2387 ".W"[swait_active(&rnp->nocb_gp_wq[0])],
2388 ".W"[swait_active(&rnp->nocb_gp_wq[1])],
2389 ".B"[!!rdp->nocb_gp_bypass],
2390 ".G"[!!rdp->nocb_gp_gp],
2391 (long)rdp->nocb_gp_seq,
2392 rnp->grplo, rnp->grphi, READ_ONCE(rdp->nocb_gp_loops));
2393}
2394
2395/* Dump out nocb kthread state for the specified rcu_data structure. */
2396static void show_rcu_nocb_state(struct rcu_data *rdp)
2397{
2398 struct rcu_segcblist *rsclp = &rdp->cblist;
2399 bool waslocked;
2400 bool wastimer;
2401 bool wassleep;
2402
2403 if (rdp->nocb_gp_rdp == rdp)
2404 show_rcu_nocb_gp_state(rdp);
2405
2406 pr_info(" CB %d->%d %c%c%c%c%c%c F%ld L%ld C%d %c%c%c%c%c q%ld\n",
2407 rdp->cpu, rdp->nocb_gp_rdp->cpu,
2408 "kK"[!!rdp->nocb_cb_kthread],
2409 "bB"[raw_spin_is_locked(&rdp->nocb_bypass_lock)],
2410 "cC"[!!atomic_read(&rdp->nocb_lock_contended)],
2411 "lL"[raw_spin_is_locked(&rdp->nocb_lock)],
2412 "sS"[!!rdp->nocb_cb_sleep],
2413 ".W"[swait_active(&rdp->nocb_cb_wq)],
2414 jiffies - rdp->nocb_bypass_first,
2415 jiffies - rdp->nocb_nobypass_last,
2416 rdp->nocb_nobypass_count,
2417 ".D"[rcu_segcblist_ready_cbs(rsclp)],
2418 ".W"[!rcu_segcblist_restempty(rsclp, RCU_DONE_TAIL)],
2419 ".R"[!rcu_segcblist_restempty(rsclp, RCU_WAIT_TAIL)],
2420 ".N"[!rcu_segcblist_restempty(rsclp, RCU_NEXT_READY_TAIL)],
2421 ".B"[!!rcu_cblist_n_cbs(&rdp->nocb_bypass)],
2422 rcu_segcblist_n_cbs(&rdp->cblist));
2423
2424 /* It is OK for GP kthreads to have GP state. */
2425 if (rdp->nocb_gp_rdp == rdp)
2426 return;
2427
2428 waslocked = raw_spin_is_locked(&rdp->nocb_gp_lock);
2429 wastimer = timer_pending(&rdp->nocb_timer);
2430 wassleep = swait_active(&rdp->nocb_gp_wq);
2431 if (!rdp->nocb_defer_wakeup && !rdp->nocb_gp_sleep &&
2432 !waslocked && !wastimer && !wassleep)
2433 return; /* Nothing untowards. */
2434
2435 pr_info(" !!! %c%c%c%c %c\n",
2436 "lL"[waslocked],
2437 "dD"[!!rdp->nocb_defer_wakeup],
2438 "tT"[wastimer],
2439 "sS"[!!rdp->nocb_gp_sleep],
2440 ".W"[wassleep]);
2441}
2442
2365#else /* #ifdef CONFIG_RCU_NOCB_CPU */ 2443#else /* #ifdef CONFIG_RCU_NOCB_CPU */
2366 2444
2367/* No ->nocb_lock to acquire. */ 2445/* No ->nocb_lock to acquire. */
@@ -2439,6 +2517,10 @@ static void __init rcu_spawn_nocb_kthreads(void)
2439{ 2517{
2440} 2518}
2441 2519
2520static void show_rcu_nocb_state(struct rcu_data *rdp)
2521{
2522}
2523
2442#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */ 2524#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
2443 2525
2444/* 2526/*
diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h
index 0627a66699a6..841ab43f3e60 100644
--- a/kernel/rcu/tree_stall.h
+++ b/kernel/rcu/tree_stall.h
@@ -589,6 +589,11 @@ void show_rcu_gp_kthreads(void)
589 cpu, (long)rdp->gp_seq_needed); 589 cpu, (long)rdp->gp_seq_needed);
590 } 590 }
591 } 591 }
592 for_each_possible_cpu(cpu) {
593 rdp = per_cpu_ptr(&rcu_data, cpu);
594 if (rcu_segcblist_is_offloaded(&rdp->cblist))
595 show_rcu_nocb_state(rdp);
596 }
592 /* sched_show_task(rcu_state.gp_kthread); */ 597 /* sched_show_task(rcu_state.gp_kthread); */
593} 598}
594EXPORT_SYMBOL_GPL(show_rcu_gp_kthreads); 599EXPORT_SYMBOL_GPL(show_rcu_gp_kthreads);