From: Eric W. Biederman In de_thread we move pids from one process to another, a rather ugly case. The function transfer_pid makes it clear what we are doing, and makes the action atomic. This is useful we ever want to atomically traverse the process group and session lists, in a rcu safe manner. Even if the atomic properties this change should be a win as transfer_pid should be less code to execute than executing both attach_pid and detach_pid, and this should make de_thread slightly smaller as only a single function call needs to be emitted. The only downside is that the code might be slower to execute as the odds are against transfer_pid being in cache. Signed-off-by: Eric W. Biederman Cc: Oleg Nesterov Signed-off-by: Andrew Morton --- fs/exec.c | 11 ++++------- include/linux/pid.h | 2 ++ kernel/pid.c | 9 +++++++++ 3 files changed, 15 insertions(+), 7 deletions(-) diff -puN fs/exec.c~pid-implement-transfer_pid-and-use-it-to-simplify-de_thread fs/exec.c --- a/fs/exec.c~pid-implement-transfer_pid-and-use-it-to-simplify-de_thread +++ a/fs/exec.c @@ -696,23 +696,20 @@ static int de_thread(struct task_struct */ /* Become a process group leader with the old leader's pid. - * Note: The old leader also uses thispid until release_task + * The old leader becomes a thread of the this thread group. + * Note: The old leader also uses this pid until release_task * is called. Odd but simple and correct. */ detach_pid(current, PIDTYPE_PID); current->pid = leader->pid; attach_pid(current, PIDTYPE_PID, current->pid); - attach_pid(current, PIDTYPE_PGID, current->signal->pgrp); - attach_pid(current, PIDTYPE_SID, current->signal->session); + transfer_pid(leader, current, PIDTYPE_PGID); + transfer_pid(leader, current, PIDTYPE_SID); list_replace_rcu(&leader->tasks, ¤t->tasks); current->group_leader = current; leader->group_leader = current; - /* Reduce leader to a thread */ - detach_pid(leader, PIDTYPE_PGID); - detach_pid(leader, PIDTYPE_SID); - current->exit_signal = SIGCHLD; BUG_ON(leader->exit_state != EXIT_ZOMBIE); diff -puN include/linux/pid.h~pid-implement-transfer_pid-and-use-it-to-simplify-de_thread include/linux/pid.h --- a/include/linux/pid.h~pid-implement-transfer_pid-and-use-it-to-simplify-de_thread +++ a/include/linux/pid.h @@ -76,6 +76,8 @@ extern int FASTCALL(attach_pid(struct ta enum pid_type type, int nr)); extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type)); +extern void FASTCALL(transfer_pid(struct task_struct *old, + struct task_struct *new, enum pid_type)); /* * look up a PID in the hash table. Must be called with the tasklist_lock diff -puN kernel/pid.c~pid-implement-transfer_pid-and-use-it-to-simplify-de_thread kernel/pid.c --- a/kernel/pid.c~pid-implement-transfer_pid-and-use-it-to-simplify-de_thread +++ a/kernel/pid.c @@ -252,6 +252,15 @@ void fastcall detach_pid(struct task_str free_pid(pid); } +/* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */ +void fastcall transfer_pid(struct task_struct *old, struct task_struct *new, + enum pid_type type) +{ + new->pids[type].pid = old->pids[type].pid; + hlist_replace_rcu(&old->pids[type].node, &new->pids[type].node); + old->pids[type].pid = NULL; +} + struct task_struct * fastcall pid_task(struct pid *pid, enum pid_type type) { struct task_struct *result = NULL; _