Miscellaneous fixes for 4.7
Subsystems (2)
cover Miscellaneous fixes for 4.7
Hello!
This series provides miscellaneous fixes for RCU:
1. Consolidate RCU's single-shot dumping of the ftrace buffer.
This is a bit widespread, so the upcoming documentation, expedited-grace-period, and torture patchsets are also based on this patch.
2. Awaken grace-period kthread at RCU CPU stall-warning time.
3. Move the FQS timeout farther into the future only if the current
wakeup actually resulted in an FQS scan.
4. Awaken grace-period kthread if too long since FQS.
5. Remove superfluous versions of rcu_read_lock_sched_held(),
courtesy of Boqun Feng.
6. Dump ftrace buffer when kicking grace-period kthread.
Thanx, Paul
------------------------------------------------------------------------
include/linux/rcupdate.h | 30 +++++++++---------- kernel/rcu/rcutorture.c | 17 +---------- kernel/rcu/tree.c | 71 ++++++++++++++++++++++++++++++++++++++--------- kernel/rcu/tree.h | 2 + kernel/rcu/update.c | 4 +- 5 files changed, 79 insertions(+), 45 deletions(-)
PATCH 1/6 rcu: Consolidate dumping of ftrace buffer
This commit consolidates a couple definitions and several calls for single-shot ftrace-buffer dumping.
--- include/linux/rcupdate.h | 13 +++++++++++++ kernel/rcu/rcutorture.c | 17 +++-------------- kernel/rcu/tree.c | 4 ++-- 3 files changed, 18 insertions(+), 16 deletions(-)
include/linux/rcupdate.h +13 -0
@@ -1144,4 +1144,17 @@ static inline void rcu_sysidle_force_exit(void)#endif /* #else #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */ +/* +* Dump the ftrace buffer, but only one time per callsite per boot. +*/ +#define rcu_ftrace_dump (oops_dump_mode) \ +do { \ + static atomic_t ___rfd_beenhere = ATOMIC_INIT(0); \ + \ + if (!atomic_read(&___rfd_beenhere) && \ + !atomic_xchg(&___rfd_beenhere, 1)) \ + ftrace_dump(oops_dump_mode); \ +} while (0) + +#endif /* __LINUX_RCUPDATE_H */
kernel/rcu/rcutorture.c +3 -14
@@ -1082,17 +1082,6 @@ rcu_torture_fakewriter(void *arg)return 0 ; } -static void rcutorture_trace_dump (void ) -{ -static atomic_t beenhere =ATOMIC_INIT (0 ); - -if (atomic_read (&beenhere)) -return ; -if (atomic_xchg (&beenhere,1 ) !=0 ) -return ; -ftrace_dump (DUMP_ALL ); -} -/* * RCU torture reader from timer handler. Dereferences rcu_torture_current, * incrementing the corresponding element of the pipeline array. The
@@ -1142,7 +1131,7 @@ static void rcu_torture_timer(unsigned long unused)if (pipe_count >1 ) {do_trace_rcu_torture_read (cur_ops->name, &p->rtort_rcu, ts, started, completed); -rcutorture_trace_dump (); +rcu_ftrace_dump (DUMP_ALL ); }__this_cpu_inc (rcu_torture_count[pipe_count]); completed = completed - started;
@@ -1215,7 +1204,7 @@ rcu_torture_reader(void *arg)if (pipe_count >1 ) {do_trace_rcu_torture_read (cur_ops->name, &p->rtort_rcu, ts, started, completed); -rcutorture_trace_dump (); +rcu_ftrace_dump (DUMP_ALL ); }__this_cpu_inc (rcu_torture_count[pipe_count]); completed = completed - started;
@@ -1333,7 +1322,7 @@ rcu_torture_stats_print(void) rcu_torture_writer_state, gpnum, completed, flags);show_rcu_gp_kthreads (); -rcutorture_trace_dump (); +rcu_ftrace_dump (DUMP_ALL ); } rtcv_snap = rcu_torture_current_version; }
kernel/rcu/tree.c +2 -2
@@ -637,7 +637,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user)idle_task (smp_processor_id ());trace_rcu_dyntick (TPS ("Error on entry: not idle task" ), oldval,0 ); -ftrace_dump (DUMP_ORIG ); +rcu_ftrace_dump (DUMP_ORIG );WARN_ONCE (1 ,"Current pid: %d comm: %s / Idle pid: %d comm: %s" , current->pid, current->comm, idle->pid, idle->comm);/* must be idle task! */
@@ -799,7 +799,7 @@ static void rcu_eqs_exit_common(long long oldval, int user)trace_rcu_dyntick (TPS ("Error on exit: not idle task" ), oldval, rdtp->dynticks_nesting); -ftrace_dump (DUMP_ORIG ); +rcu_ftrace_dump (DUMP_ORIG );WARN_ONCE (1 ,"Current pid: %d comm: %s / Idle pid: %d comm: %s" , current->pid, current->comm, idle->pid, idle->comm);/* must be idle task! */
Signature · 1 line
2.5.2
PATCH 2/6 rcu: Awaken grace-period kthread when stalled
In reply to Paul E. McKenneyRecent kernels can fail to awaken the grace-period kthread for quiescent-state forcing. This commit is a crude hack that does a wakeup any time a stall is detected.
--- kernel/rcu/tree.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/rcu/tree.c +3 -1
@@ -1224,8 +1224,10 @@ static void rcu_check_gp_kthread_starvation(struct rcu_state *rsp) rsp->gp_flags,gp_state_getname (rsp->gp_state), rsp->gp_state, rsp->gp_kthread ? rsp->gp_kthread->state : ~0); -if (rsp->gp_kthread) +if (rsp->gp_kthread) {sched_show_task (rsp->gp_kthread); +wake_up_process (rsp->gp_kthread); + } } }
Signature · 1 line
2.5.2
PATCH 3/6 rcu: Make FQS schedule advance only if FQS happened
In reply to Paul E. McKenneyCurrently, the force-quiescent-state (FQS) code in rcu_gp_kthread() can advance the next FQS even if one was not executed last time. This can happen due timeout-duration uncertainty. This commit therefore avoids advancing the FQS schedule unless an FQS was just executed. In the corner case where an FQS was not executed, but is due now, the code does a one-jiffy wait.
This change prepares for kthread kicking.
--- kernel/rcu/tree.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)
kernel/rcu/tree.c +15 -8
@@ -2146,6 +2146,15 @@ static int __noreturn rcu_gp_kthread(void *arg) TPS("fqsend"));cond_resched_rcu_qs ();WRITE_ONCE (rsp->gp_activity, jiffies); + ret =0 ;/* Force full wait till next FQS. */ + j = jiffies_till_next_fqs; +if (j >HZ ) { + j =HZ ; + jiffies_till_next_fqs =HZ ; + }else if (j <1 ) { + j =1 ; + jiffies_till_next_fqs =1 ; + } }else {/* Deal with stray signal. */ cond_resched_rcu_qs ();
@@ -2154,14 +2163,12 @@ static int __noreturn rcu_gp_kthread(void *arg)trace_rcu_grace_period (rsp->name,READ_ONCE (rsp->gpnum),TPS ("fqswaitsig" )); - } - j = jiffies_till_next_fqs; -if (j >HZ ) { - j =HZ ; - jiffies_till_next_fqs =HZ ; - }else if (j <1 ) { - j =1 ; - jiffies_till_next_fqs =1 ; + ret =1 ;/* Keep old FQS timing. */ + j = jiffies; +if (time_after (jiffies, rsp->jiffies_force_qs)) + j =1 ; +else + j = rsp->jiffies_force_qs - j; } }
Signature · 1 line
2.5.2
PATCH 4/6 rcu: Awaken grace-period kthread if too long since FQS
In reply to Paul E. McKenneyRecent kernels can fail to awaken the grace-period kthread for quiescent-state forcing. This commit is a crude hack that does a wakeup if a scheduling-clock interrupt sees that it has been too long since force-quiescent-state (FQS) processing.
--- kernel/rcu/tree.c | 39 +++++++++++++++++++++++++++++++++++++-- kernel/rcu/tree.h | 2 ++ 2 files changed, 39 insertions(+), 2 deletions(-)
kernel/rcu/tree.c +37 -2
@@ -385,9 +385,11 @@ module_param(qlowmark, long, 0444);static ulong jiffies_till_first_fqs =ULONG_MAX ;static ulong jiffies_till_next_fqs =ULONG_MAX ; +static bool rcu_kick_kthreads;module_param (jiffies_till_first_fqs, ulong,0644 );module_param (jiffies_till_next_fqs, ulong,0644 ); +module_param (rcu_kick_kthreads, bool,0644 );/* * How long the grace period must be before we start recruiting
@@ -1251,6 +1253,24 @@ static void rcu_dump_cpu_stacks(struct rcu_state *rsp) } } +/* +* If too much time has passed in the current grace period, and if +* so configured, go kick the relevant kthreads. +*/ +static void rcu_stall_kick_kthreads (struct rcu_state *rsp) +{ +unsigned long j; + +if (!rcu_kick_kthreads) +return ; + j =READ_ONCE (rsp->jiffies_kick_kthreads); +if (time_after (jiffies, j) && rsp->gp_kthread) { +WARN_ONCE (1 ,"Kicking %s grace-period kthread\n" , rsp->name); +wake_up_process (rsp->gp_kthread); +WRITE_ONCE (rsp->jiffies_kick_kthreads, j +HZ ); + } +} +static void print_other_cpu_stall (struct rcu_state *rsp,unsigned long gpnum) {int cpu;
@@ -1262,6 +1282,11 @@ static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum)struct rcu_node *rnp =rcu_get_root (rsp);long totqlen =0 ; +/* Kick and suppress, if so configured. */ +rcu_stall_kick_kthreads (rsp); +if (rcu_cpu_stall_suppress) +return ; +/* Only let one CPU complain about others per time interval. */ raw_spin_lock_irqsave_rcu_node (rnp, flags);
@@ -1335,6 +1360,11 @@ static void print_cpu_stall(struct rcu_state *rsp)struct rcu_node *rnp =rcu_get_root (rsp);long totqlen =0 ; +/* Kick and suppress, if so configured. */ +rcu_stall_kick_kthreads (rsp); +if (rcu_cpu_stall_suppress) +return ; +/* * OK, time to rat on ourselves... * See Documentation/RCU/stallwarn.txt for info on how to debug
@@ -1379,8 +1409,10 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)unsigned long js;struct rcu_node *rnp; -if (rcu_cpu_stall_suppress || !rcu_gp_in_progress (rsp)) +if ((rcu_cpu_stall_suppress && !rcu_kick_kthreads) || + !rcu_gp_in_progress (rsp))return ; +rcu_stall_kick_kthreads (rsp); j = jiffies;/*
@@ -2119,8 +2151,11 @@ static int __noreturn rcu_gp_kthread(void *arg) } ret =0 ;for (;;) { -if (!ret) +if (!ret) { rsp->jiffies_force_qs = jiffies + j; +WRITE_ONCE (rsp->jiffies_kick_kthreads, + jiffies +3 * j); + }trace_rcu_grace_period (rsp->name,READ_ONCE (rsp->gpnum),TPS ("fqswait" ));
kernel/rcu/tree.h +2 -0
@@ -513,6 +513,8 @@ struct rcu_state {unsigned long jiffies_force_qs;/* Time at which to invoke */ /* force_quiescent_state(). */ +unsigned long jiffies_kick_kthreads;/* Time at which to kick */ +/* kthreads, if configured. */ unsigned long n_force_qs;/* Number of calls to */ /* force_quiescent_state(). */ unsigned long n_force_qs_lh;/* ~Number of calls leaving */
Signature · 1 line
2.5.2
PATCH 5/6 rcu: Remove superfluous versions of rcu_read_lock_sched_held()
In reply to Paul E. McKenneyFrom: Boqun Feng <[email protected]>
Currently, we have four versions of rcu_read_lock_sched_held(), depending on the combined choices on PREEMPT_COUNT and DEBUG_LOCK_ALLOC. However, there is an existing function preemptible() that already distinguishes between the PREEMPT_COUNT=y and PREEMPT_COUNT=n cases, and allows these four implementations to be consolidated down to two.
This commit therefore uses preemptible() to achieve this consolidation.
Note that there could be a small performance regression in the case of CONFIG_DEBUG_LOCK_ALLOC=y && PREEMPT_COUNT=n. However, given the overhead associated with CONFIG_DEBUG_LOCK_ALLOC=y, this should be down in the noise.
--- include/linux/rcupdate.h | 17 +---------------- kernel/rcu/update.c | 4 ++-- 2 files changed, 3 insertions(+), 18 deletions(-)
include/linux/rcupdate.h +1 -16
@@ -508,14 +508,7 @@ int rcu_read_lock_bh_held(void);* CONFIG_DEBUG_LOCK_ALLOC, this assumes we are in an RCU-sched read-side * critical section unless it can prove otherwise. */ -#ifdef CONFIG_PREEMPT_COUNT int rcu_read_lock_sched_held (void ); -#else /* #ifdef CONFIG_PREEMPT_COUNT */ -static inline int rcu_read_lock_sched_held (void ) -{ -return 1 ; -} -#endif /* #else #ifdef CONFIG_PREEMPT_COUNT */ #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
@@ -532,18 +525,10 @@ static inline int rcu_read_lock_bh_held(void) return 1; } -#ifdef CONFIG_PREEMPT_COUNT static inline int rcu_read_lock_sched_held (void ) { -return preempt_count () !=0 ||irqs_disabled (); +return !preemptible (); } -#else /* #ifdef CONFIG_PREEMPT_COUNT */ -static inline int rcu_read_lock_sched_held (void ) -{ -return 1 ; -} -#endif /* #else #ifdef CONFIG_PREEMPT_COUNT */ -#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ #ifdef CONFIG_PROVE_RCU
kernel/rcu/update.c +2 -2
@@ -67,7 +67,7 @@ static int rcu_normal_after_boot;module_param (rcu_normal_after_boot, int,0 );#endif /* #ifndef CONFIG_TINY_RCU */ -#if defined(CONFIG_DEBUG_LOCK_ALLOC ) && defined(CONFIG_PREEMPT_COUNT ) +#ifdef CONFIG_DEBUG_LOCK_ALLOC /** * rcu_read_lock_sched_held() - might we be in RCU-sched read-side critical section? *
@@ -111,7 +111,7 @@ int rcu_read_lock_sched_held(void)return 0 ;if (debug_locks) lockdep_opinion =lock_is_held (&rcu_sched_lock_map); - return lockdep_opinion || preempt_count() != 0 || irqs_disabled(); + return lockdep_opinion || !preemptible(); }EXPORT_SYMBOL (rcu_read_lock_sched_held);#endif
Signature · 1 line
2.5.2
PATCH 6/6 rcu: Dump ftrace buffer when kicking grace-period kthread
In reply to Paul E. McKenneyIf it is necessary to kick the grace-period kthread, that is a good time to dump the trace buffer in order to learn why kicking was needed. This commit therefore does the dump.
--- kernel/rcu/tree.c | 1 + 1 file changed, 1 insertion(+)
kernel/rcu/tree.c +1 -0
@@ -1266,6 +1266,7 @@ static void rcu_stall_kick_kthreads(struct rcu_state *rsp) j =READ_ONCE (rsp->jiffies_kick_kthreads);if (time_after (jiffies, j) && rsp->gp_kthread) {WARN_ONCE (1 ,"Kicking %s grace-period kthread\n" , rsp->name); +rcu_ftrace_dump (DUMP_ALL );wake_up_process (rsp->gp_kthread);WRITE_ONCE (rsp->jiffies_kick_kthreads, j +HZ ); }
Signature · 1 line
2.5.2