[PATCH] simplify exec from init's subthread
authorOleg Nesterov <oleg@tv-sign.ru>
Wed, 29 Mar 2006 00:10:59 +0000 (16:10 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 29 Mar 2006 02:36:40 +0000 (18:36 -0800)
I think it is enough to take tasklist_lock for reading while changing
child_reaper:

Reparenting needs write_lock(tasklist_lock)

Only one thread in a thread group can do exec()

sighand->siglock garantees that get_signal_to_deliver()
will not see a stale value of child_reaper.

This means that we can change child_reaper earlier, without calling
zap_other_threads() twice.

"child_reaper = current" is a NOOP when init does exec from main thread, we
don't care.

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/exec.c

index d0ecea0..dd19492 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -616,6 +616,15 @@ static int de_thread(struct task_struct *tsk)
                kmem_cache_free(sighand_cachep, newsighand);
                return -EAGAIN;
        }
+
+       /*
+        * child_reaper ignores SIGKILL, change it now.
+        * Reparenting needs write_lock on tasklist_lock,
+        * so it is safe to do it under read_lock.
+        */
+       if (unlikely(current->group_leader == child_reaper))
+               child_reaper = current;
+
        zap_other_threads(current);
        read_unlock(&tasklist_lock);
 
@@ -660,23 +669,12 @@ static int de_thread(struct task_struct *tsk)
                struct dentry *proc_dentry1, *proc_dentry2;
                unsigned long ptrace;
 
-               leader = current->group_leader;
-               /*
-                * If our leader is the child_reaper become
-                * the child_reaper and resend SIGKILL signal.
-                */
-               if (unlikely(leader == child_reaper)) {
-                       write_lock(&tasklist_lock);
-                       child_reaper = current;
-                       zap_other_threads(current);
-                       write_unlock(&tasklist_lock);
-               }
-
                /*
                 * Wait for the thread group leader to be a zombie.
                 * It should already be zombie at this point, most
                 * of the time.
                 */
+               leader = current->group_leader;
                while (leader->exit_state != EXIT_ZOMBIE)
                        yield();