utrace_set_events() is not trivial, and imho it has too much "unlock + return" cases. Change the code to use goto, this also lessens the source and compiled code a bit.
--- kernel/utrace.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) --- kstub/kernel/utrace.c~4_cleanup_ealready 2010-08-14 04:30:29.000000000 +0200 +++ kstub/kernel/utrace.c 2010-08-14 04:30:29.000000000 +0200 @@ -524,7 +524,7 @@ int utrace_set_events(struct task_struct { struct utrace *utrace; unsigned long old_flags, old_utrace_flags; - int ret; + int ret = -EALREADY; /* * We just ignore the internal bit, so callers can use @@ -542,15 +542,11 @@ int utrace_set_events(struct task_struct /* If ->death or ->reap is true we must see exit_state != 0. */ if (target->exit_state) { if (utrace->death) { - if ((old_flags & ~events) & _UTRACE_DEATH_EVENTS) { - spin_unlock(&utrace->lock); - return -EALREADY; - } + if ((old_flags & ~events) & _UTRACE_DEATH_EVENTS) + goto unlock; } else if (utrace->reap) { - if ((old_flags ^ events) & UTRACE_EVENT(REAP)) { - spin_unlock(&utrace->lock); - return -EALREADY; - } + if ((old_flags ^ events) & UTRACE_EVENT(REAP)) + goto unlock; } } @@ -568,8 +564,7 @@ int utrace_set_events(struct task_struct read_lock(&tasklist_lock); if (unlikely(target->exit_state)) { read_unlock(&tasklist_lock); - spin_unlock(&utrace->lock); - return -EALREADY; + goto unlock; } target->utrace_flags |= events; read_unlock(&tasklist_lock); @@ -597,7 +592,7 @@ int utrace_set_events(struct task_struct if (utrace->reporting == engine) ret = -EINPROGRESS; } - +unlock: spin_unlock(&utrace->lock); return ret;