Convert the functions that temporarily suppress RCU CPU stall reporting: rcu_sysrq_start() rcu_sysrq_end() to more generic functions that may be called by functions other than the SysRq handler: rcu_suppress_start() rcu_suppress_end() Covert the underlying variable: rcu_cpu_stall_suppress to an atomic variable so multiple threads can manipulate it at the same time, incrementing it in start() and decrementing in end(). Expose that in sysfs in a read-only /sys/module/rcupdate/parameters/rcu_cpu_stall_suppress_dyn Keep /sys/module/rcupdate/parameters/rcu_cpu_stall_suppress as writeable by userspace, but OR that into the equations rather than directly manipulate the atomic value. Signed-off-by: Robert Elliott <elliott@xxxxxxx> --- .../RCU/Design/Requirements/Requirements.rst | 6 +++--- Documentation/RCU/stallwarn.rst | 19 +++++++++++++++---- arch/parisc/kernel/process.c | 2 +- drivers/tty/sysrq.c | 4 ++-- include/linux/rcupdate.h | 8 ++++---- kernel/rcu/rcu.h | 11 ++++++----- kernel/rcu/tree_stall.h | 18 ++++++++++-------- kernel/rcu/update.c | 11 ++++++++++- 8 files changed, 51 insertions(+), 28 deletions(-) diff --git a/Documentation/RCU/Design/Requirements/Requirements.rst b/Documentation/RCU/Design/Requirements/Requirements.rst index 49387d823619..5083490bb6fc 100644 --- a/Documentation/RCU/Design/Requirements/Requirements.rst +++ b/Documentation/RCU/Design/Requirements/Requirements.rst @@ -1639,9 +1639,9 @@ against mishaps and misuse: ``rcupdate.rcu_cpu_stall_suppress`` to suppress the splats. This kernel parameter may also be set via ``sysfs``. Furthermore, RCU CPU stall warnings are counter-productive during sysrq dumps and during - panics. RCU therefore supplies the rcu_sysrq_start() and - rcu_sysrq_end() API members to be called before and after long - sysrq dumps. RCU also supplies the rcu_panic() notifier that is + panics. RCU therefore supplies the rcu_suppress_start() and + rcu_suppress_end() API members to be called before and after long + CPU usage. RCU also supplies the rcu_panic() notifier that is automatically invoked at the beginning of a panic to suppress further RCU CPU stall warnings. diff --git a/Documentation/RCU/stallwarn.rst b/Documentation/RCU/stallwarn.rst index e38c587067fc..9e6fba72f56d 100644 --- a/Documentation/RCU/stallwarn.rst +++ b/Documentation/RCU/stallwarn.rst @@ -135,13 +135,24 @@ see include/trace/events/rcu.h. Fine-Tuning the RCU CPU Stall Detector ====================================== -The rcuupdate.rcu_cpu_stall_suppress module parameter disables RCU's -CPU stall detector, which detects conditions that unduly delay RCU grace -periods. This module parameter enables CPU stall detection by default, -but may be overridden via boot-time parameter or at runtime via sysfs. +RCU's CPU stall detector detects conditions that unduly delay RCU grace +periods. CPU stall detection is enabled by default, but may be overridden +via boot-time parameter or at runtime via sysfs (accessible via +/sys/module/rcupdate/parameters). + +The rcupdate.rcu_cpu_stall_suppress module parameter disables RCU's +CPU stall detector. + +/sys/module/rcu_cpu_stall_suppress_dyn reports an internal semaphore +used by the RCU's CPU stall detector. Functions holding a CPU for a +long time (e.g., sysrq printouts) increment this value before use +and decrement it when done, so the value reports the number of +functions currently disabling stalls. + The stall detector's idea of what constitutes "unduly delayed" is controlled by a set of kernel configuration variables and cpp macros: + CONFIG_RCU_CPU_STALL_TIMEOUT ---------------------------- diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index c4f8374c7018..038378fe7bfa 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -126,7 +126,7 @@ void machine_power_off(void) "Please power this system off now."); /* prevent soft lockup/stalled CPU messages for endless loop. */ - rcu_sysrq_start(); + rcu_suppress_start(); lockup_detector_soft_poweroff(); for (;;); } diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index d2b2720db6ca..81ab63a473a7 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -579,7 +579,7 @@ void __handle_sysrq(int key, bool check_mask) orig_suppress_printk = suppress_printk; suppress_printk = 0; - rcu_sysrq_start(); + rcu_suppress_start(); rcu_read_lock(); /* * Raise the apparent loglevel to maximum so that the sysrq header @@ -623,7 +623,7 @@ void __handle_sysrq(int key, bool check_mask) console_loglevel = orig_log_level; } rcu_read_unlock(); - rcu_sysrq_end(); + rcu_suppress_end(); suppress_printk = orig_suppress_printk; } diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 03abf883a281..c0d8a4aae7ff 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -131,11 +131,11 @@ static inline void rcu_init_tasks_generic(void) { } #endif #ifdef CONFIG_RCU_STALL_COMMON -void rcu_sysrq_start(void); -void rcu_sysrq_end(void); +void rcu_suppress_start(void); +void rcu_suppress_end(void); #else /* #ifdef CONFIG_RCU_STALL_COMMON */ -static inline void rcu_sysrq_start(void) { } -static inline void rcu_sysrq_end(void) { } +static inline void rcu_suppress_start(void) { } +static inline void rcu_suppress_end(void) { } #endif /* #else #ifdef CONFIG_RCU_STALL_COMMON */ #if defined(CONFIG_NO_HZ_FULL) && (!defined(CONFIG_GENERIC_ENTRY) || !defined(CONFIG_KVM_XFER_TO_GUEST_WORK)) diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h index c5aa934de59b..a658955a1174 100644 --- a/kernel/rcu/rcu.h +++ b/kernel/rcu/rcu.h @@ -224,24 +224,25 @@ extern int rcu_cpu_stall_ftrace_dump; extern int rcu_cpu_stall_suppress; extern int rcu_cpu_stall_timeout; extern int rcu_exp_cpu_stall_timeout; +extern atomic_t rcu_cpu_stall_suppress_dyn; int rcu_jiffies_till_stall_check(void); int rcu_exp_jiffies_till_stall_check(void); static inline bool rcu_stall_is_suppressed(void) { - return rcu_stall_is_suppressed_at_boot() || rcu_cpu_stall_suppress; + return rcu_stall_is_suppressed_at_boot() || + rcu_cpu_stall_suppress || + atomic_read(&rcu_cpu_stall_suppress_dyn); } #define rcu_ftrace_dump_stall_suppress() \ do { \ - if (!rcu_cpu_stall_suppress) \ - rcu_cpu_stall_suppress = 3; \ + atomic_inc(&rcu_cpu_stall_suppress_dyn); \ } while (0) #define rcu_ftrace_dump_stall_unsuppress() \ do { \ - if (rcu_cpu_stall_suppress == 3) \ - rcu_cpu_stall_suppress = 0; \ + atomic_dec(&rcu_cpu_stall_suppress_dyn); \ } while (0) #else /* #endif #ifdef CONFIG_RCU_STALL_COMMON */ diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h index 5653560573e2..260748bc5bc8 100644 --- a/kernel/rcu/tree_stall.h +++ b/kernel/rcu/tree_stall.h @@ -103,23 +103,25 @@ bool rcu_gp_might_be_stalled(void) return !time_before(j, READ_ONCE(rcu_state.gp_start) + d); } -/* Don't do RCU CPU stall warnings during long sysrq printouts. */ -void rcu_sysrq_start(void) +/* Don't do RCU CPU stall warnings during functions holding the CPU + * for a long period of time such as long sysrq printouts. + */ +void rcu_suppress_start(void) { - if (!rcu_cpu_stall_suppress) - rcu_cpu_stall_suppress = 2; + atomic_inc(&rcu_cpu_stall_suppress_dyn); } +EXPORT_SYMBOL_GPL(rcu_suppress_start); -void rcu_sysrq_end(void) +void rcu_suppress_end(void) { - if (rcu_cpu_stall_suppress == 2) - rcu_cpu_stall_suppress = 0; + atomic_dec(&rcu_cpu_stall_suppress_dyn); } +EXPORT_SYMBOL_GPL(rcu_suppress_end); /* Don't print RCU CPU stall warnings during a kernel panic. */ static int rcu_panic(struct notifier_block *this, unsigned long ev, void *ptr) { - rcu_cpu_stall_suppress = 1; + atomic_inc(&rcu_cpu_stall_suppress_dyn); return NOTIFY_DONE; } diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index f5e6a2f95a2a..ceee9d777384 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -501,11 +501,18 @@ EXPORT_SYMBOL_GPL(rcutorture_sched_setaffinity); #ifdef CONFIG_RCU_STALL_COMMON int rcu_cpu_stall_ftrace_dump __read_mostly; module_param(rcu_cpu_stall_ftrace_dump, int, 0644); -int rcu_cpu_stall_suppress __read_mostly; // !0 = suppress stall warnings. + +int rcu_cpu_stall_suppress __read_mostly; // !0 = suppress stall warnings from sysfs EXPORT_SYMBOL_GPL(rcu_cpu_stall_suppress); module_param(rcu_cpu_stall_suppress, int, 0644); + +atomic_t rcu_cpu_stall_suppress_dyn __read_mostly; // !0 = suppress stall warnings from functions +EXPORT_SYMBOL_GPL(rcu_cpu_stall_suppress_dyn); +module_param_named(rcu_cpu_stall_suppress_dyn, rcu_cpu_stall_suppress_dyn.counter, int, 0444); + int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT; module_param(rcu_cpu_stall_timeout, int, 0644); + int rcu_exp_cpu_stall_timeout __read_mostly = CONFIG_RCU_EXP_CPU_STALL_TIMEOUT; module_param(rcu_exp_cpu_stall_timeout, int, 0644); #endif /* #ifdef CONFIG_RCU_STALL_COMMON */ @@ -616,6 +623,8 @@ void __init rcupdate_announce_bootup_oddness(void) pr_info("\tAll grace periods are expedited (rcu_expedited).\n"); if (rcu_cpu_stall_suppress) pr_info("\tRCU CPU stall warnings suppressed (rcu_cpu_stall_suppress).\n"); + if (atomic_read(&rcu_cpu_stall_suppress_dyn)) + pr_info("\tDynamic RCU CPU stall warnings suppressed (rcu_cpu_stall_suppress_dyn).\n"); if (rcu_cpu_stall_timeout != CONFIG_RCU_CPU_STALL_TIMEOUT) pr_info("\tRCU CPU stall warnings timeout set to %d (rcu_cpu_stall_timeout).\n", rcu_cpu_stall_timeout); rcu_tasks_bootup_oddness(); -- 2.38.1