Commit-ID: 7f68b6000ddf57c0cdbe94ddfc099ed12820f16a Gitweb: http://git.kernel.org/tip/7f68b6000ddf57c0cdbe94ddfc099ed12820f16a Author: Thomas Gleixner <tglx@xxxxxxxxxxxxx> AuthorDate: Sun, 23 Apr 2017 12:33:08 +0200 Committer: Thomas Gleixner <tglx@xxxxxxxxxxxxx> CommitDate: Sun, 23 Apr 2017 19:11:28 +0200 kprobes: Cure hotplug lock ordering issues The get_online_cpus() rework unearthed lock ordering issues. Reorder hotpluglock and kprobes_mutex() to avoid circular locking dependencies. Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx> Cc: Masami Hiramatsu <mhiramat@xxxxxxxxxx> Cc: Steven Rostedt <rostedt@xxxxxxxxxxx> --- kernel/kprobes.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 699c5bc..e70a197 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -498,14 +498,13 @@ static void do_optimize_kprobes(void) * This combination can cause a deadlock (cpu-hotplug try to lock * text_mutex but stop_machine can not be done because online_cpus * has been changed) - * To avoid this deadlock, we need to call get_online_cpus() + * To avoid this deadlock, caller must have locked cpu hotplug * for preventing cpu-hotplug outside of text_mutex locking. */ - get_online_cpus(); + lockdep_assert_hotplug_held(); mutex_lock(&text_mutex); arch_optimize_kprobes(&optimizing_list); mutex_unlock(&text_mutex); - put_online_cpus(); } /* @@ -521,7 +520,7 @@ static void do_unoptimize_kprobes(void) return; /* Ditto to do_optimize_kprobes */ - get_online_cpus(); + lockdep_assert_hotplug_held(); mutex_lock(&text_mutex); arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list); /* Loop free_list for disarming */ @@ -540,7 +539,6 @@ static void do_unoptimize_kprobes(void) list_del_init(&op->list); } mutex_unlock(&text_mutex); - put_online_cpus(); } /* Reclaim all kprobes on the free_list */ @@ -564,6 +562,7 @@ static void kick_kprobe_optimizer(void) /* Kprobe jump optimizer */ static void kprobe_optimizer(struct work_struct *work) { + get_online_cpus(); mutex_lock(&kprobe_mutex); /* Lock modules while optimizing kprobes */ mutex_lock(&module_mutex); @@ -595,6 +594,7 @@ static void kprobe_optimizer(struct work_struct *work) /* Step 5: Kick optimizer again if needed */ if (!list_empty(&optimizing_list) || !list_empty(&unoptimizing_list)) kick_kprobe_optimizer(); + put_online_cpus(); } /* Wait for completing optimization and unoptimization */ @@ -653,9 +653,7 @@ static void optimize_kprobe(struct kprobe *p) /* Short cut to direct unoptimizing */ static void force_unoptimize_kprobe(struct optimized_kprobe *op) { - get_online_cpus(); arch_unoptimize_kprobe(op); - put_online_cpus(); if (kprobe_disabled(&op->kp)) arch_disarm_kprobe(&op->kp); } @@ -817,6 +815,7 @@ static void optimize_all_kprobes(void) struct kprobe *p; unsigned int i; + get_online_cpus(); mutex_lock(&kprobe_mutex); /* If optimization is already allowed, just return */ if (kprobes_allow_optimization) @@ -832,6 +831,7 @@ static void optimize_all_kprobes(void) printk(KERN_INFO "Kprobes globally optimized\n"); out: mutex_unlock(&kprobe_mutex); + put_online_cpus(); } static void unoptimize_all_kprobes(void) @@ -840,6 +840,7 @@ static void unoptimize_all_kprobes(void) struct kprobe *p; unsigned int i; + get_online_cpus(); mutex_lock(&kprobe_mutex); /* If optimization is already prohibited, just return */ if (!kprobes_allow_optimization) { @@ -860,6 +861,7 @@ static void unoptimize_all_kprobes(void) /* Wait for unoptimizing completion */ wait_for_kprobe_optimizer(); printk(KERN_INFO "Kprobes globally unoptimized\n"); + put_online_cpus(); } static DEFINE_MUTEX(kprobe_sysctl_mutex); @@ -1297,10 +1299,11 @@ static int register_aggr_kprobe(struct kprobe *orig_p, struct kprobe *p) /* For preparing optimization, jump_label_text_reserved() is called */ jump_label_lock(); /* - * Get online CPUs to avoid text_mutex deadlock.with stop machine, - * which is invoked by unoptimize_kprobe() in add_new_kprobe() + * Caller must have locked CPUs to avoid text_mutex deadlock.with stop + * machine, which is invoked by unoptimize_kprobe() in + * add_new_kprobe() */ - get_online_cpus(); + lockdep_assert_hotplug_held(); mutex_lock(&text_mutex); if (!kprobe_aggrprobe(orig_p)) { @@ -1539,6 +1542,7 @@ int register_kprobe(struct kprobe *p) if (ret) return ret; + get_online_cpus(); mutex_lock(&kprobe_mutex); old_p = get_kprobe(p->addr); @@ -1566,6 +1570,7 @@ int register_kprobe(struct kprobe *p) out: mutex_unlock(&kprobe_mutex); + put_online_cpus(); if (probed_mod) module_put(probed_mod); -- To unsubscribe from this list: send the line "unsubscribe linux-tip-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html
![]() |