commit bf679f65284b834b455e8453d10616073ff58d2c Author: Srikar Dronamraju <sri...@linux.vnet.ibm.com> Date: Tue Aug 18 18:15:49 2009 +0530
detach fix Saw a Oops message BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 IP: [<ffffffff8107a8cd>] get_utrace_lock+0x43/0x115 I figured out the reason for the oops message as "2nd parameter (engine) to utrace_set_events as NULL." Call sequence is as below: - traced process exits resulting in gdb_utrace_report_death being called. - gdb_utrace_report_death sets p->engine to NULL and returns UTRACE_DETACH. - gdb calls release callback (proc_gdb_release() which results in - utrace_set_events and utrace_control(..,UTRACE_DETACH) with engine being set to NULL resulting in OOPS. Also we were explicitly decrementing reference to engine even when we havent explicitly incremented a reference. This patch - Doesnt detach from release callback if the engine is already detached. - removes explicit reference decrement. - removes setting engine to NULL in gdb_utrace_report_death(). Signed-off-by: Srikar Dronamraju <sri...@linux.vnet.ibm.com> diff --git a/kernel/utrace-gdb.c b/kernel/utrace-gdb.c index f7833dc..8cf2b0f 100644 --- a/kernel/utrace-gdb.c +++ b/kernel/utrace-gdb.c @@ -497,8 +497,6 @@ u32 gdb_utrace_report_death(struct utrace_engine *engine, snprintf (p->stopcode, GDB_BUFMAX, "X%2x", (unsigned)(signal & 0xFF)); push_output_packet (p, p->stopcode); - p->engine = NULL; - #ifdef CONFIG_HAVE_UPROBES { struct list_head *l; @@ -1245,11 +1243,11 @@ static int proc_gdb_release(struct inode *inode, struct file *filp) } #endif /* CONFIG_HAVE_UPROBES */ - if (task == NULL) { + if (task == NULL) { /* The thread is already gone; report_death was already called. */ - pr_debug ("gdb %d releasing old\n", p->target); - } else { - pr_debug ("gdb %d releasing current\n", p->target); + pr_debug("gdb %d releasing old\n", p->target); + } else if (p->at_quiesce_do != UTRACE_DETACH) { + pr_debug("gdb %d releasing current\n", p->target); ret = utrace_set_events(task, p->engine, 0); if (ret == -EINPROGRESS) @@ -1259,8 +1257,6 @@ static int proc_gdb_release(struct inode *inode, struct file *filp) ret = utrace_control(task, p->engine, UTRACE_DETACH); /* => RESUME */ if (ret == -EINPROGRESS) ret = utrace_barrier(task, p->engine); - - utrace_engine_put (p->engine); } list_del(&p->link);