kernel/fork.c:copy_process(): consolidate the lockless CLONE_THREAD checks
authorOleg Nesterov <oleg@redhat.com>
Wed, 3 Jul 2013 22:08:32 +0000 (15:08 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Jul 2013 23:08:03 +0000 (16:08 -0700)
copy_process() does a lot of "chaotic" initializations and checks
CLONE_THREAD twice before it takes tasklist.  In particular it sets
"p->group_leader = p" and then changes it again under tasklist if
!thread_group_leader(p).

This looks a bit confusing, lets create a single "if (CLONE_THREAD)" block
which initializes ->exit_signal, ->group_leader, and ->tgid.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Michal Hocko <mhocko@suse.cz>
Cc: Pavel Emelyanov <xemul@parallels.com>
Cc: Sergey Dyasly <dserrg@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
kernel/fork.c

index 7d6962fb61561f8bdf62ecccedb472352676e0f3..6e6a1c11b3e5939bda764882801a5dd28e904f30 100644 (file)
@@ -1360,11 +1360,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                        goto bad_fork_cleanup_io;
        }
 
-       p->pid = pid_nr(pid);
-       p->tgid = p->pid;
-       if (clone_flags & CLONE_THREAD)
-               p->tgid = current->tgid;
-
        p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
        /*
         * Clear TID on mm_release()?
@@ -1400,12 +1395,19 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        clear_all_latency_tracing(p);
 
        /* ok, now we should be set up.. */
-       if (clone_flags & CLONE_THREAD)
+       p->pid = pid_nr(pid);
+       if (clone_flags & CLONE_THREAD) {
                p->exit_signal = -1;
-       else if (clone_flags & CLONE_PARENT)
-               p->exit_signal = current->group_leader->exit_signal;
-       else
-               p->exit_signal = (clone_flags & CSIGNAL);
+               p->group_leader = current->group_leader;
+               p->tgid = current->tgid;
+       } else {
+               if (clone_flags & CLONE_PARENT)
+                       p->exit_signal = current->group_leader->exit_signal;
+               else
+                       p->exit_signal = (clone_flags & CSIGNAL);
+               p->group_leader = p;
+               p->tgid = p->pid;
+       }
 
        p->pdeath_signal = 0;
        p->exit_state = 0;
@@ -1414,15 +1416,13 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        p->nr_dirtied_pause = 128 >> (PAGE_SHIFT - 10);
        p->dirty_paused_when = 0;
 
-       /*
-        * Ok, make it visible to the rest of the system.
-        * We dont wake it up yet.
-        */
-       p->group_leader = p;
        INIT_LIST_HEAD(&p->thread_group);
        p->task_works = NULL;
 
-       /* Need tasklist lock for parent etc handling! */
+       /*
+        * Make it visible to the rest of the system, but dont wake it up yet.
+        * Need tasklist lock for parent etc handling!
+        */
        write_lock_irq(&tasklist_lock);
 
        /* CLONE_PARENT re-uses the old parent */
@@ -1476,7 +1476,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                        current->signal->nr_threads++;
                        atomic_inc(&current->signal->live);
                        atomic_inc(&current->signal->sigcnt);
-                       p->group_leader = current->group_leader;
                        list_add_tail_rcu(&p->thread_group,
                                          &p->group_leader->thread_group);
                }