EXP: Fine-grained timer diagnostics
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 3c07ace..5bfdeabe 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -289,6 +289,8 @@ extern struct cred init_cred;
INIT_FTRACE_GRAPH \
INIT_TRACE_RECURSION \
INIT_TASK_RCU_PREEMPT(tsk) \
+ .rcu_trace_timers = 0, \
+ .rcu_timer = NULL, \
INIT_TASK_RCU_TASKS(tsk) \
INIT_CPUSET_SEQ(tsk) \
INIT_RT_MUTEXES(tsk) \
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4d3a2a7..68d98e6 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -586,6 +586,8 @@ struct task_struct {
struct list_head rcu_node_entry;
struct rcu_node *rcu_blocked_node;
#endif /* #ifdef CONFIG_PREEMPT_RCU */
+ u8 rcu_trace_timers;
+ struct timer_list *rcu_timer;
#ifdef CONFIG_TASKS_RCU
unsigned long rcu_tasks_nvcsw;
diff --git a/include/linux/timer.h b/include/linux/timer.h
index e6789b8..ee8534c 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -19,6 +19,7 @@ struct timer_list {
void (*function)(unsigned long);
unsigned long data;
u32 flags;
+ struct task_struct *rcu_timer_task;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
diff --git a/kernel/fork.c b/kernel/fork.c
index 1064618..88167d4 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1504,6 +1504,8 @@ static inline void rcu_copy_process(struct task_struct *p)
INIT_LIST_HEAD(&p->rcu_tasks_holdout_list);
p->rcu_tasks_idle_cpu = -1;
#endif /* #ifdef CONFIG_TASKS_RCU */
+ p->rcu_trace_timers = 0;
+ p->rcu_timer = NULL;
}
/*
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index e4fe06d..b871f51 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -4058,6 +4058,7 @@ static int __init rcu_spawn_gp_kthread(void)
rnp = rcu_get_root(rsp);
raw_spin_lock_irqsave_rcu_node(rnp, flags);
rsp->gp_kthread = t;
+ t->rcu_trace_timers = 1;
if (kthread_prio) {
sp.sched_priority = kthread_prio;
sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index f2674a0..3c92414 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -1739,11 +1739,16 @@ signed long __sched schedule_timeout(signed long timeout)
expire = timeout + jiffies;
setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
+ if (current->rcu_trace_timers) {
+ current->rcu_timer = &timer;
+ timer.rcu_timer_task = current;
+ }
__mod_timer(&timer, expire, false);
schedule();
del_singleshot_timer_sync(&timer);
/* Remove the timer from the object tracker */
+ current->rcu_timer = NULL;
destroy_timer_on_stack(&timer);
timeout = expire - jiffies;
@@ -1799,6 +1804,8 @@ static void migrate_timer_list(struct timer_base *new_base, struct hlist_head *h
timer = hlist_entry(head->first, struct timer_list, entry);
detach_timer(timer, false);
timer->flags = (timer->flags & ~TIMER_BASEMASK) | cpu;
+ if (timer->rcu_timer_task)
+ pr_info("Migrated GP kthread timer\n");
internal_add_timer(new_base, timer);
}
}