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);
 

Reply via email to