commit 90cc0931707c99459aea0f6601d7f5ce2756dbd8 Author: Srikar Dronamraju <sri...@linux.vnet.ibm.com> Date: Wed Aug 19 10:26:00 2009 +0530
While releasing, unregister uprobes if any after detach Currently because of the way uprobes works, (register/unregister may deadlock if one of the threads of this process is expecting a singlestep to complete and someother engine as already stopped that thread. [ I am looking into this issue]) gdb requests register and unregister of all probes when it hits any breakpoints. However gdb through another engine stops the thread. At this time uprobes may have initiated singlestep but yet to be completed. Frank has converted register/unregister of breakpoints to setting/unsetting a flag. Hence once registered, unregister of probes occurs at closing of gdb connection. At that time the deadlock situation may again occur. This patch moves the unregister of uprobes (which is independent of the gdbstub engine) to after detach. This is a simple and harmless workaround for now. Signed-off-by: Srikar Dronamraju <sri...@linux.vnet.ibm.com> diff --git a/kernel/utrace-gdb.c b/kernel/utrace-gdb.c index 8cf2b0f..7d32264 100644 --- a/kernel/utrace-gdb.c +++ b/kernel/utrace-gdb.c @@ -1228,21 +1228,6 @@ static int proc_gdb_release(struct inode *inode, struct file *filp) int ret = 0; mutex_lock (& gdb_connections_mutex); - -#ifdef CONFIG_HAVE_UPROBES - { - struct list_head *l; - struct list_head *l2; - list_for_each_safe(l, l2, & p->uprobes) { - struct gdb_uprobe *gup = list_entry (l, struct gdb_uprobe, link); - if (task) /* Not dead yet. */ - unregister_uprobe (& gup->up); - list_del (& gup->link); - kfree (gup); - } - } -#endif /* CONFIG_HAVE_UPROBES */ - if (task == NULL) { /* The thread is already gone; report_death was already called. */ pr_debug("gdb %d releasing old\n", p->target); @@ -1259,6 +1244,20 @@ static int proc_gdb_release(struct inode *inode, struct file *filp) ret = utrace_barrier(task, p->engine); } +#ifdef CONFIG_HAVE_UPROBES + { + struct list_head *l, *l2; + list_for_each_safe(l, l2, &p->uprobes) { + struct gdb_uprobe *gup = + list_entry(l, struct gdb_uprobe, link); + if (task) /* Not dead yet. */ + unregister_uprobe(&gup->up); + list_del(&gup->link); + kfree(gup); + } + } +#endif /* CONFIG_HAVE_UPROBES */ + list_del(&p->link); kfree(p);