forked from luck/tmp_suning_uos_patched
3fc3d1709f
The RCU CPU stall-warning code for normal grace periods is currently scattered across two files, due to earlier Tiny RCU support for RCU CPU stall warnings and for old Kconfig options that have long since been retired. Given that it is hard for the lead RCU maintainer to find relevant stall-warning code, it would be good to consolidate it. This commit continues this process by moving stall-warning code from kernel/rcu/tree_plugin.c to a new kernel/rcu/tree_stall.h file. Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
159 lines
3.7 KiB
C
159 lines
3.7 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* RCU CPU stall warnings for normal RCU grace periods
|
|
*
|
|
* Copyright IBM Corporation, 2019
|
|
*
|
|
* Author: Paul E. McKenney <paulmck@linux.ibm.com>
|
|
*/
|
|
|
|
|
|
#ifdef CONFIG_PROVE_RCU
|
|
#define RCU_STALL_DELAY_DELTA (5 * HZ)
|
|
#else
|
|
#define RCU_STALL_DELAY_DELTA 0
|
|
#endif
|
|
|
|
int rcu_jiffies_till_stall_check(void)
|
|
{
|
|
int till_stall_check = READ_ONCE(rcu_cpu_stall_timeout);
|
|
|
|
/*
|
|
* Limit check must be consistent with the Kconfig limits
|
|
* for CONFIG_RCU_CPU_STALL_TIMEOUT.
|
|
*/
|
|
if (till_stall_check < 3) {
|
|
WRITE_ONCE(rcu_cpu_stall_timeout, 3);
|
|
till_stall_check = 3;
|
|
} else if (till_stall_check > 300) {
|
|
WRITE_ONCE(rcu_cpu_stall_timeout, 300);
|
|
till_stall_check = 300;
|
|
}
|
|
return till_stall_check * HZ + RCU_STALL_DELAY_DELTA;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rcu_jiffies_till_stall_check);
|
|
|
|
void rcu_sysrq_start(void)
|
|
{
|
|
if (!rcu_cpu_stall_suppress)
|
|
rcu_cpu_stall_suppress = 2;
|
|
}
|
|
|
|
void rcu_sysrq_end(void)
|
|
{
|
|
if (rcu_cpu_stall_suppress == 2)
|
|
rcu_cpu_stall_suppress = 0;
|
|
}
|
|
|
|
static int rcu_panic(struct notifier_block *this, unsigned long ev, void *ptr)
|
|
{
|
|
rcu_cpu_stall_suppress = 1;
|
|
return NOTIFY_DONE;
|
|
}
|
|
|
|
static struct notifier_block rcu_panic_block = {
|
|
.notifier_call = rcu_panic,
|
|
};
|
|
|
|
static int __init check_cpu_stall_init(void)
|
|
{
|
|
atomic_notifier_chain_register(&panic_notifier_list, &rcu_panic_block);
|
|
return 0;
|
|
}
|
|
early_initcall(check_cpu_stall_init);
|
|
|
|
#ifdef CONFIG_PREEMPT
|
|
|
|
/*
|
|
* Dump detailed information for all tasks blocking the current RCU
|
|
* grace period on the specified rcu_node structure.
|
|
*/
|
|
static void rcu_print_detail_task_stall_rnp(struct rcu_node *rnp)
|
|
{
|
|
unsigned long flags;
|
|
struct task_struct *t;
|
|
|
|
raw_spin_lock_irqsave_rcu_node(rnp, flags);
|
|
if (!rcu_preempt_blocked_readers_cgp(rnp)) {
|
|
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
|
|
return;
|
|
}
|
|
t = list_entry(rnp->gp_tasks->prev,
|
|
struct task_struct, rcu_node_entry);
|
|
list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) {
|
|
/*
|
|
* We could be printing a lot while holding a spinlock.
|
|
* Avoid triggering hard lockup.
|
|
*/
|
|
touch_nmi_watchdog();
|
|
sched_show_task(t);
|
|
}
|
|
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
|
|
}
|
|
|
|
/*
|
|
* Dump detailed information for all tasks blocking the current RCU
|
|
* grace period.
|
|
*/
|
|
static void rcu_print_detail_task_stall(void)
|
|
{
|
|
struct rcu_node *rnp = rcu_get_root();
|
|
|
|
rcu_print_detail_task_stall_rnp(rnp);
|
|
rcu_for_each_leaf_node(rnp)
|
|
rcu_print_detail_task_stall_rnp(rnp);
|
|
}
|
|
|
|
static void rcu_print_task_stall_begin(struct rcu_node *rnp)
|
|
{
|
|
pr_err("\tTasks blocked on level-%d rcu_node (CPUs %d-%d):",
|
|
rnp->level, rnp->grplo, rnp->grphi);
|
|
}
|
|
|
|
static void rcu_print_task_stall_end(void)
|
|
{
|
|
pr_cont("\n");
|
|
}
|
|
|
|
/*
|
|
* Scan the current list of tasks blocked within RCU read-side critical
|
|
* sections, printing out the tid of each.
|
|
*/
|
|
static int rcu_print_task_stall(struct rcu_node *rnp)
|
|
{
|
|
struct task_struct *t;
|
|
int ndetected = 0;
|
|
|
|
if (!rcu_preempt_blocked_readers_cgp(rnp))
|
|
return 0;
|
|
rcu_print_task_stall_begin(rnp);
|
|
t = list_entry(rnp->gp_tasks->prev,
|
|
struct task_struct, rcu_node_entry);
|
|
list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) {
|
|
pr_cont(" P%d", t->pid);
|
|
ndetected++;
|
|
}
|
|
rcu_print_task_stall_end();
|
|
return ndetected;
|
|
}
|
|
|
|
#else /* #ifdef CONFIG_PREEMPT */
|
|
|
|
/*
|
|
* Because preemptible RCU does not exist, we never have to check for
|
|
* tasks blocked within RCU read-side critical sections.
|
|
*/
|
|
static void rcu_print_detail_task_stall(void)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* Because preemptible RCU does not exist, we never have to check for
|
|
* tasks blocked within RCU read-side critical sections.
|
|
*/
|
|
static int rcu_print_task_stall(struct rcu_node *rnp)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif /* #else #ifdef CONFIG_PREEMPT */
|