All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] copy_process/attach_pid minor fix + cleanups
@ 2013-06-09 17:00 Oleg Nesterov
  2013-06-09 17:00 ` [PATCH 1/4] de_thread: use change_pid() rather than detach_pid/attach_pid Oleg Nesterov
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Oleg Nesterov @ 2013-06-09 17:00 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Eric W. Biederman, Michal Hocko, Pavel Emelyanov, Sergey Dyasly,
	linux-kernel

Hello.

1/4 and 2/4 look like the obvious cleanups.

3/4 tries to fix the minor problem. I have to admit, initially
I thought that this problem is more serious. But it seems that
nothing really bad can happen if the new task has the wrong pid
or group_leader. Still I think this makes sense.

4/4 is offtopic minor cleanup.


This is also another preparation for while_each_thread() fixes.

Oleg.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/4] de_thread: use change_pid() rather than detach_pid/attach_pid
  2013-06-09 17:00 [PATCH v2 0/4] copy_process/attach_pid minor fix + cleanups Oleg Nesterov
@ 2013-06-09 17:00 ` Oleg Nesterov
  2013-06-10  4:07   ` Eric W. Biederman
  2013-06-09 17:00 ` [PATCH 2/4] copy_process: unify CLONE_THREAD-or-thread_group_leader code Oleg Nesterov
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Oleg Nesterov @ 2013-06-09 17:00 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Eric W. Biederman, Michal Hocko, Pavel Emelyanov, Sergey Dyasly,
	linux-kernel

de_thread() can use change_pid() instead of detach + attach.
This looks better and this ensures that, say, next_thread()
can never see a task with ->pid == NULL.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 fs/exec.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index 6430195..00eaba7 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -945,9 +945,8 @@ static int de_thread(struct task_struct *tsk)
 		 * Note: The old leader also uses this pid until release_task
 		 *       is called.  Odd but simple and correct.
 		 */
-		detach_pid(tsk, PIDTYPE_PID);
 		tsk->pid = leader->pid;
-		attach_pid(tsk, PIDTYPE_PID,  task_pid(leader));
+		change_pid(tsk, PIDTYPE_PID, task_pid(leader));
 		transfer_pid(leader, tsk, PIDTYPE_PGID);
 		transfer_pid(leader, tsk, PIDTYPE_SID);
 
-- 
1.5.5.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/4] copy_process: unify CLONE_THREAD-or-thread_group_leader code
  2013-06-09 17:00 [PATCH v2 0/4] copy_process/attach_pid minor fix + cleanups Oleg Nesterov
  2013-06-09 17:00 ` [PATCH 1/4] de_thread: use change_pid() rather than detach_pid/attach_pid Oleg Nesterov
@ 2013-06-09 17:00 ` Oleg Nesterov
  2013-06-09 17:00 ` [PATCH 3/4] copy_process: don't add the uninitialized child to thread/task/pid lists Oleg Nesterov
  2013-06-09 17:00 ` [PATCH 4/4] copy_process: consolidate the lockless CLONE_THREAD checks Oleg Nesterov
  3 siblings, 0 replies; 6+ messages in thread
From: Oleg Nesterov @ 2013-06-09 17:00 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Eric W. Biederman, Michal Hocko, Pavel Emelyanov, Sergey Dyasly,
	linux-kernel

Cleanup and preparation for the next changes.

Move the "if (clone_flags & CLONE_THREAD)" code down under
"if (likely(p->pid))" and turn it into into the "else" branch.
This makes the process/thread initialization more symmetrical
and removes one check.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 kernel/fork.c |   15 +++++++--------
 1 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/kernel/fork.c b/kernel/fork.c
index 987b28a..7bc4146 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1446,14 +1446,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 		goto bad_fork_free_pid;
 	}
 
-	if (clone_flags & CLONE_THREAD) {
-		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);
-	}
-
 	if (likely(p->pid)) {
 		ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace);
 
@@ -1470,6 +1462,13 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 			list_add_tail(&p->sibling, &p->real_parent->children);
 			list_add_tail_rcu(&p->tasks, &init_task.tasks);
 			__this_cpu_inc(process_counts);
+		} else {
+			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);
 		}
 		attach_pid(p, PIDTYPE_PID, pid);
 		nr_threads++;
-- 
1.5.5.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/4] copy_process: don't add the uninitialized child to thread/task/pid lists
  2013-06-09 17:00 [PATCH v2 0/4] copy_process/attach_pid minor fix + cleanups Oleg Nesterov
  2013-06-09 17:00 ` [PATCH 1/4] de_thread: use change_pid() rather than detach_pid/attach_pid Oleg Nesterov
  2013-06-09 17:00 ` [PATCH 2/4] copy_process: unify CLONE_THREAD-or-thread_group_leader code Oleg Nesterov
@ 2013-06-09 17:00 ` Oleg Nesterov
  2013-06-09 17:00 ` [PATCH 4/4] copy_process: consolidate the lockless CLONE_THREAD checks Oleg Nesterov
  3 siblings, 0 replies; 6+ messages in thread
From: Oleg Nesterov @ 2013-06-09 17:00 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Eric W. Biederman, Michal Hocko, Pavel Emelyanov, Sergey Dyasly,
	linux-kernel

copy_process() adds the new child to thread_group/init_task.tasks
list and then does attach_pid(child, PIDTYPE_PID). This means that
the lockless next_thread() or next_task() can see this thread with
the wrong pid. Say, "ls /proc/pid/task" can list the same inode
twice.

We could move attach_pid(child, PIDTYPE_PID) up, but in this case
find_task_by_vpid() can find the new thread before it was fully
initialized. And this is already true for PIDTYPE_PGID/PIDTYPE_SID,

With this patch copy_process() initializes child->pids[*].pid first,
then calls attach_pid() to insert the task into the pid->tasks list.

attach_pid() no longer need the "struct pid*" argument, it is always
called after pid_link->pid was already set.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 include/linux/pid.h |    6 ++----
 kernel/fork.c       |   16 +++++++++++++---
 kernel/pid.c        |   12 ++++--------
 3 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/include/linux/pid.h b/include/linux/pid.h
index a089a3c..23705a5 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -86,11 +86,9 @@ extern struct task_struct *get_pid_task(struct pid *pid, enum pid_type);
 extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type);
 
 /*
- * attach_pid() and detach_pid() must be called with the tasklist_lock
- * write-held.
+ * these helpers must be called with the tasklist_lock write-held.
  */
-extern void attach_pid(struct task_struct *task, enum pid_type type,
-			struct pid *pid);
+extern void attach_pid(struct task_struct *task, enum pid_type);
 extern void detach_pid(struct task_struct *task, enum pid_type);
 extern void change_pid(struct task_struct *task, enum pid_type,
 			struct pid *pid);
diff --git a/kernel/fork.c b/kernel/fork.c
index 7bc4146..c836e3c 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1121,6 +1121,12 @@ static void posix_cpu_timers_init(struct task_struct *tsk)
 	INIT_LIST_HEAD(&tsk->cpu_timers[2]);
 }
 
+static inline void
+init_task_pid(struct task_struct *task, enum pid_type type, struct pid *pid)
+{
+	 task->pids[type].pid = pid;
+}
+
 /*
  * This creates a new process as a copy of the old one,
  * but does not actually start it yet.
@@ -1449,7 +1455,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	if (likely(p->pid)) {
 		ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace);
 
+		init_task_pid(p, PIDTYPE_PID, pid);
 		if (thread_group_leader(p)) {
+			init_task_pid(p, PIDTYPE_PGID, task_pgrp(current));
+			init_task_pid(p, PIDTYPE_SID, task_session(current));
+
 			if (is_child_reaper(pid)) {
 				ns_of_pid(pid)->child_reaper = p;
 				p->signal->flags |= SIGNAL_UNKILLABLE;
@@ -1457,10 +1467,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
 			p->signal->leader_pid = pid;
 			p->signal->tty = tty_kref_get(current->signal->tty);
-			attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
-			attach_pid(p, PIDTYPE_SID, task_session(current));
 			list_add_tail(&p->sibling, &p->real_parent->children);
 			list_add_tail_rcu(&p->tasks, &init_task.tasks);
+			attach_pid(p, PIDTYPE_PGID);
+			attach_pid(p, PIDTYPE_SID);
 			__this_cpu_inc(process_counts);
 		} else {
 			current->signal->nr_threads++;
@@ -1470,7 +1480,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 			list_add_tail_rcu(&p->thread_group,
 					  &p->group_leader->thread_group);
 		}
-		attach_pid(p, PIDTYPE_PID, pid);
+		attach_pid(p, PIDTYPE_PID);
 		nr_threads++;
 	}
 
diff --git a/kernel/pid.c b/kernel/pid.c
index 0db3e79..61980ce 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -373,14 +373,10 @@ EXPORT_SYMBOL_GPL(find_vpid);
 /*
  * attach_pid() must be called with the tasklist_lock write-held.
  */
-void attach_pid(struct task_struct *task, enum pid_type type,
-		struct pid *pid)
+void attach_pid(struct task_struct *task, enum pid_type type)
 {
-	struct pid_link *link;
-
-	link = &task->pids[type];
-	link->pid = pid;
-	hlist_add_head_rcu(&link->node, &pid->tasks[type]);
+	struct pid_link *link = &task->pids[type];
+	hlist_add_head_rcu(&link->node, &link->pid->tasks[type]);
 }
 
 static void __change_pid(struct task_struct *task, enum pid_type type,
@@ -412,7 +408,7 @@ void change_pid(struct task_struct *task, enum pid_type type,
 		struct pid *pid)
 {
 	__change_pid(task, type, pid);
-	attach_pid(task, type, pid);
+	attach_pid(task, type);
 }
 
 /* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */
-- 
1.5.5.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/4] copy_process: consolidate the lockless CLONE_THREAD checks
  2013-06-09 17:00 [PATCH v2 0/4] copy_process/attach_pid minor fix + cleanups Oleg Nesterov
                   ` (2 preceding siblings ...)
  2013-06-09 17:00 ` [PATCH 3/4] copy_process: don't add the uninitialized child to thread/task/pid lists Oleg Nesterov
@ 2013-06-09 17:00 ` Oleg Nesterov
  3 siblings, 0 replies; 6+ messages in thread
From: Oleg Nesterov @ 2013-06-09 17:00 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Eric W. Biederman, Michal Hocko, Pavel Emelyanov, Sergey Dyasly,
	linux-kernel

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>
---
 kernel/fork.c |   33 ++++++++++++++++-----------------
 1 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/kernel/fork.c b/kernel/fork.c
index c836e3c..b6818a8 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -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);
 		}
-- 
1.5.5.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/4] de_thread: use change_pid() rather than detach_pid/attach_pid
  2013-06-09 17:00 ` [PATCH 1/4] de_thread: use change_pid() rather than detach_pid/attach_pid Oleg Nesterov
@ 2013-06-10  4:07   ` Eric W. Biederman
  0 siblings, 0 replies; 6+ messages in thread
From: Eric W. Biederman @ 2013-06-10  4:07 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Andrew Morton, Michal Hocko, Pavel Emelyanov, Sergey Dyasly,
	linux-kernel

Oleg Nesterov <oleg@redhat.com> writes:

> de_thread() can use change_pid() instead of detach + attach.
> This looks better and this ensures that, say, next_thread()
> can never see a task with ->pid == NULL.

I want to say that there I though there was a good reason something
to do with the exit logic.

However I just read through attach_pid, detach_pid, and change_pid.
And the sequence detach_pid(...); attach_pid(...)  is equiavalent
to change_pid(...);

Reviewed-by: "Eric W. Biederman" <ebiederm@xmission.com>

> Signed-off-by: Oleg Nesterov <oleg@redhat.com>
> ---
>  fs/exec.c |    3 +--
>  1 files changed, 1 insertions(+), 2 deletions(-)
>
> diff --git a/fs/exec.c b/fs/exec.c
> index 6430195..00eaba7 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -945,9 +945,8 @@ static int de_thread(struct task_struct *tsk)
>  		 * Note: The old leader also uses this pid until release_task
>  		 *       is called.  Odd but simple and correct.
>  		 */
> -		detach_pid(tsk, PIDTYPE_PID);
>  		tsk->pid = leader->pid;
> -		attach_pid(tsk, PIDTYPE_PID,  task_pid(leader));
> +		change_pid(tsk, PIDTYPE_PID, task_pid(leader));
>  		transfer_pid(leader, tsk, PIDTYPE_PGID);
>  		transfer_pid(leader, tsk, PIDTYPE_SID);

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2013-06-10  4:07 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-09 17:00 [PATCH v2 0/4] copy_process/attach_pid minor fix + cleanups Oleg Nesterov
2013-06-09 17:00 ` [PATCH 1/4] de_thread: use change_pid() rather than detach_pid/attach_pid Oleg Nesterov
2013-06-10  4:07   ` Eric W. Biederman
2013-06-09 17:00 ` [PATCH 2/4] copy_process: unify CLONE_THREAD-or-thread_group_leader code Oleg Nesterov
2013-06-09 17:00 ` [PATCH 3/4] copy_process: don't add the uninitialized child to thread/task/pid lists Oleg Nesterov
2013-06-09 17:00 ` [PATCH 4/4] copy_process: consolidate the lockless CLONE_THREAD checks Oleg Nesterov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.