From: "Steven Rostedt (VMware)" Allow get_online_cpus() to be recursive. If a lock is taken while under "get_online_cpus()", it can call get_online_cpus() as well, just as long as it is never held without being under get_online_cpus(), but then calling it. GOC() -> Lock(X) -> GOC() is OK, as long as Lock(X) -> GOC() does not exist. Signed-off-by: Steven Rostedt (VMware) --- include/linux/sched.h | 1 + kernel/cpu.c | 9 +++++++++ kernel/fork.c | 1 + 3 files changed, 11 insertions(+) diff --git a/include/linux/sched.h b/include/linux/sched.h index 993e7e25a3a5..8f272ab57685 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -813,6 +813,7 @@ struct task_struct { unsigned int lockdep_recursion; struct held_lock held_locks[MAX_LOCK_DEPTH]; gfp_t lockdep_reclaim_gfp; + int goc_depth; #endif #ifdef CONFIG_UBSAN diff --git a/kernel/cpu.c b/kernel/cpu.c index 983163ef36ee..0dbdf1e69715 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -209,12 +209,21 @@ DEFINE_STATIC_PERCPU_RWSEM(cpu_hotplug_lock); void get_online_cpus(void) { +#ifdef CONFIG_LOCKDEP + if (current->goc_depth++) + return; +#endif percpu_down_read(&cpu_hotplug_lock); } EXPORT_SYMBOL_GPL(get_online_cpus); void put_online_cpus(void) { +#ifdef CONFIG_LOCKDEP + WARN_ON_ONCE(current->goc_depth < 1); + if (--current->goc_depth) + return; +#endif percpu_up_read(&cpu_hotplug_lock); } EXPORT_SYMBOL_GPL(put_online_cpus); diff --git a/kernel/fork.c b/kernel/fork.c index dd5a371c392a..8aedcd011ccc 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1658,6 +1658,7 @@ static __latent_entropy struct task_struct *copy_process( p->lockdep_depth = 0; /* no locks held yet */ p->curr_chain_key = 0; p->lockdep_recursion = 0; + p->goc_depth = 0; #endif #ifdef CONFIG_DEBUG_MUTEXES -- 2.10.2