public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] fix ->shm_file leak
@ 2013-06-14 19:09 Oleg Nesterov
  2013-06-14 19:09 ` [PATCH 1/2] fput: task_work_add() can fail if the caller has passed exit_task_work() Oleg Nesterov
  2013-06-14 19:09 ` [PATCH 2/2] move exit_task_namespaces() outside of exit_notify() Oleg Nesterov
  0 siblings, 2 replies; 9+ messages in thread
From: Oleg Nesterov @ 2013-06-14 19:09 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Al Viro, Andrey Vagin, Eric W. Biederman, David Howells,
	linux-kernel

Andrew,

These 2 patches are completely orthogonal, and either patch can
fix the problem reported by Andrey. However, I think they both
make sense.

The 2nd patch was already acked by Eric/Andrey. However it is
not as trivial as it looks.

The 1st one looks more straightforward, and perhaps it is 3.10
material.

Oleg.


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

* [PATCH 1/2] fput: task_work_add() can fail if the caller has passed exit_task_work()
  2013-06-14 19:09 [PATCH 0/2] fix ->shm_file leak Oleg Nesterov
@ 2013-06-14 19:09 ` Oleg Nesterov
  2013-06-14 21:58   ` Andrew Morton
  2013-06-14 19:09 ` [PATCH 2/2] move exit_task_namespaces() outside of exit_notify() Oleg Nesterov
  1 sibling, 1 reply; 9+ messages in thread
From: Oleg Nesterov @ 2013-06-14 19:09 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Al Viro, Andrey Vagin, Eric W. Biederman, David Howells,
	linux-kernel

fput() assumes that it can't be called after exit_task_work() but
this is not true, for example free_ipc_ns()->shm_destroy() can do
this. In this case fput() silently leaks the file.

Change it to fallback to delayed_fput_work if task_work_add() fails.
The patch looks complicated but it is not, it changes the code from

	if (PF_KTHREAD) {
		schedule_work(...);
		return;
	}
	task_work_add(...)

to
	if (!PF_KTHREAD) {
		if (!task_work_add(...))
			return;
		/* fallback */
	}
	schedule_work(...);

As for shm_destroy() in particular, we could make another fix but I
think this change makes sense anyway. There could be another similar
user, it is not safe to assume that task_work_add() can't fail.

Reported-by: Andrey Vagin <avagin@openvz.org>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 fs/file_table.c |   19 ++++++++++---------
 1 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/fs/file_table.c b/fs/file_table.c
index cd4d87a..485dc0e 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -306,17 +306,18 @@ void fput(struct file *file)
 {
 	if (atomic_long_dec_and_test(&file->f_count)) {
 		struct task_struct *task = current;
+		unsigned long flags;
+
 		file_sb_list_del(file);
-		if (unlikely(in_interrupt() || task->flags & PF_KTHREAD)) {
-			unsigned long flags;
-			spin_lock_irqsave(&delayed_fput_lock, flags);
-			list_add(&file->f_u.fu_list, &delayed_fput_list);
-			schedule_work(&delayed_fput_work);
-			spin_unlock_irqrestore(&delayed_fput_lock, flags);
-			return;
+		if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) {
+			init_task_work(&file->f_u.fu_rcuhead, ____fput);
+			if (!task_work_add(task, &file->f_u.fu_rcuhead, true))
+				return;
 		}
-		init_task_work(&file->f_u.fu_rcuhead, ____fput);
-		task_work_add(task, &file->f_u.fu_rcuhead, true);
+		spin_lock_irqsave(&delayed_fput_lock, flags);
+		list_add(&file->f_u.fu_list, &delayed_fput_list);
+		schedule_work(&delayed_fput_work);
+		spin_unlock_irqrestore(&delayed_fput_lock, flags);
 	}
 }
 
-- 
1.5.5.1


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

* [PATCH 2/2] move exit_task_namespaces() outside of exit_notify()
  2013-06-14 19:09 [PATCH 0/2] fix ->shm_file leak Oleg Nesterov
  2013-06-14 19:09 ` [PATCH 1/2] fput: task_work_add() can fail if the caller has passed exit_task_work() Oleg Nesterov
@ 2013-06-14 19:09 ` Oleg Nesterov
  1 sibling, 0 replies; 9+ messages in thread
From: Oleg Nesterov @ 2013-06-14 19:09 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Al Viro, Andrey Vagin, Eric W. Biederman, David Howells,
	linux-kernel

exit_notify() does exit_task_namespaces() after
forget_original_parent(). This was needed to ensure that ->nsproxy
can't be cleared prematurely, an exiting child we are going to
reparent can do do_notify_parent() and use the parent's (ours) pid_ns.

However, after 32084504 "pidns: use task_active_pid_ns in
do_notify_parent" ->nsproxy != NULL is no longer needed, we rely
on task_active_pid_ns().

Move exit_task_namespaces() from exit_notify() to do_exit(), after
exit_fs() and before exit_task_work().

This solves the problem reported by Andrey, free_ipc_ns()->shm_destroy()
does fput() which needs task_work_add().

Note: this particular problem can be fixed if we change fput(), and
that change makes sense anyway. But there is another reason to move
the callsite. The original reason for exit_task_namespaces() from
the middle of exit_notify() was subtle and it has already gone away,
now this looks confusing. And this allows us do simplify exit_notify(),
we can avoid unlock/lock(tasklist) and we can use ->exit_state instead
of PF_EXITING in forget_original_parent().

Reported-by: Andrey Vagin <avagin@openvz.org>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Acked-by: Andrey Vagin <avagin@openvz.org>
---
 kernel/exit.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/kernel/exit.c b/kernel/exit.c
index 8fc3c8f..c623cd3 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -644,7 +644,6 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
 	 *	jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
 	 */
 	forget_original_parent(tsk);
-	exit_task_namespaces(tsk);
 
 	write_lock_irq(&tasklist_lock);
 	if (group_dead)
@@ -790,6 +789,7 @@ void do_exit(long code)
 	exit_shm(tsk);
 	exit_files(tsk);
 	exit_fs(tsk);
+	exit_task_namespaces(tsk);
 	exit_task_work(tsk);
 	check_stack_usage();
 	exit_thread();
-- 
1.5.5.1


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

* Re: [PATCH 1/2] fput: task_work_add() can fail if the caller has passed exit_task_work()
  2013-06-14 19:09 ` [PATCH 1/2] fput: task_work_add() can fail if the caller has passed exit_task_work() Oleg Nesterov
@ 2013-06-14 21:58   ` Andrew Morton
  2013-06-15 17:29     ` [PATCH 0/3] (Was: fput: task_work_add() can fail if the caller has passed exit_task_work()) Oleg Nesterov
  0 siblings, 1 reply; 9+ messages in thread
From: Andrew Morton @ 2013-06-14 21:58 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Al Viro, Andrey Vagin, Eric W. Biederman, David Howells,
	linux-kernel

On Fri, 14 Jun 2013 21:09:47 +0200 Oleg Nesterov <oleg@redhat.com> wrote:

> fput() assumes that it can't be called after exit_task_work() but
> this is not true, for example free_ipc_ns()->shm_destroy() can do
> this. In this case fput() silently leaks the file.
> 
> Change it to fallback to delayed_fput_work if task_work_add() fails.
> The patch looks complicated but it is not, it changes the code from
> 
> 	if (PF_KTHREAD) {
> 		schedule_work(...);
> 		return;
> 	}
> 	task_work_add(...)
> 
> to
> 	if (!PF_KTHREAD) {
> 		if (!task_work_add(...))
> 			return;
> 		/* fallback */
> 	}
> 	schedule_work(...);
> 
> As for shm_destroy() in particular, we could make another fix but I
> think this change makes sense anyway. There could be another similar
> user, it is not safe to assume that task_work_add() can't fail.
> 
> ...
>
> --- a/fs/file_table.c
> +++ b/fs/file_table.c
> @@ -306,17 +306,18 @@ void fput(struct file *file)
>  {
>  	if (atomic_long_dec_and_test(&file->f_count)) {
>  		struct task_struct *task = current;
> +		unsigned long flags;
> +
>  		file_sb_list_del(file);
> -		if (unlikely(in_interrupt() || task->flags & PF_KTHREAD)) {
> -			unsigned long flags;
> -			spin_lock_irqsave(&delayed_fput_lock, flags);
> -			list_add(&file->f_u.fu_list, &delayed_fput_list);
> -			schedule_work(&delayed_fput_work);
> -			spin_unlock_irqrestore(&delayed_fput_lock, flags);
> -			return;
> +		if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) {
> +			init_task_work(&file->f_u.fu_rcuhead, ____fput);
> +			if (!task_work_add(task, &file->f_u.fu_rcuhead, true))
> +				return;

A comment here would be useful, explaining the circumstances under
which we fall through to the delayed fput.  This is particularly needed
because kernel/task_work.c is such undocumented crap.

This?

--- a/fs/file_table.c~fput-task_work_add-can-fail-if-the-caller-has-passed-exit_task_work-fix
+++ a/fs/file_table.c
@@ -313,6 +313,12 @@ void fput(struct file *file)
 			init_task_work(&file->f_u.fu_rcuhead, ____fput);
 			if (!task_work_add(task, &file->f_u.fu_rcuhead, true))
 				return;
+			/*
+			 * After this task has run exit_task_work(),
+			 * task_work_add() will fail.  free_ipc_ns()->
+			 * shm_destroy() can do this.  Fall through to delayed
+			 * fput to avoid leaking *file.
+			 */
 		}
 		spin_lock_irqsave(&delayed_fput_lock, flags);
 		list_add(&file->f_u.fu_list, &delayed_fput_list);


>  		}
> -		init_task_work(&file->f_u.fu_rcuhead, ____fput);
> -		task_work_add(task, &file->f_u.fu_rcuhead, true);
> +		spin_lock_irqsave(&delayed_fput_lock, flags);
> +		list_add(&file->f_u.fu_list, &delayed_fput_list);
> +		schedule_work(&delayed_fput_work);
> +		spin_unlock_irqrestore(&delayed_fput_lock, flags);

OT: I don't think that schedule_work() needs to be inside the locked
region.  Scalability improvements beckon!

>  	}
>  }


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

* [PATCH 0/3] (Was: fput: task_work_add() can fail if the caller has passed exit_task_work())
  2013-06-14 21:58   ` Andrew Morton
@ 2013-06-15 17:29     ` Oleg Nesterov
  2013-06-15 17:30       ` [PATCH 1/3] fput: turn "list_head delayed_fput_list" into llist_head Oleg Nesterov
                         ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Oleg Nesterov @ 2013-06-15 17:29 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Al Viro, Andrey Vagin, Eric W. Biederman, David Howells,
	linux-kernel, Huang Ying, Peter Zijlstra

On 06/14, Andrew Morton wrote:
>
> On Fri, 14 Jun 2013 21:09:47 +0200 Oleg Nesterov <oleg@redhat.com> wrote:
>
> > +		if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) {
> > +			init_task_work(&file->f_u.fu_rcuhead, ____fput);
> > +			if (!task_work_add(task, &file->f_u.fu_rcuhead, true))
> > +				return;
>
> A comment here would be useful, explaining the circumstances under
> which we fall through to the delayed fput.

Thanks!

> This is particularly needed
> because kernel/task_work.c is such undocumented crap.

It seems that you are trying to force me to make the doc patch ;)
OK, I'll try. task_work.c needs a couple of cosmetic cleanups anyway.

> > +		spin_lock_irqsave(&delayed_fput_lock, flags);
> > +		list_add(&file->f_u.fu_list, &delayed_fput_list);
> > +		schedule_work(&delayed_fput_work);
> > +		spin_unlock_irqrestore(&delayed_fput_lock, flags);
>
> OT: I don't think that schedule_work() needs to be inside the locked
> region.  Scalability improvements beckon!

Yeees, I thought about this too.

Performance-wise this can't really help, this case is unlikely. But
I think this change makes this code a bit simpler, so please see 1/3.

2/3 fixes the (theoretical) bug in llist_add() and imho cleanups the
code.

3/3 comes as a separate change because I do not want to argue if
someone dislike the non-inline llist_add(). But once again, we can
make llist_add_batch() inline, and I believe it is never good to
duplicate the code even if it is simple.

Oleg.


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

* [PATCH 1/3] fput: turn "list_head delayed_fput_list" into llist_head
  2013-06-15 17:29     ` [PATCH 0/3] (Was: fput: task_work_add() can fail if the caller has passed exit_task_work()) Oleg Nesterov
@ 2013-06-15 17:30       ` Oleg Nesterov
  2013-06-15 17:30       ` [PATCH 2/3] llist: fix/simplify llist_add() and llist_add_batch() Oleg Nesterov
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: Oleg Nesterov @ 2013-06-15 17:30 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Al Viro, Andrey Vagin, Eric W. Biederman, David Howells,
	Huang Ying, Peter Zijlstra, linux-kernel

fput() and delayed_fput() can use llist and avoid the locking.

This is unlikely path, it is not that this change can improve
the performance, but this way the code looks simpler.

Suggested-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 fs/file_table.c    |   25 ++++++++++---------------
 include/linux/fs.h |    2 ++
 2 files changed, 12 insertions(+), 15 deletions(-)

diff --git a/fs/file_table.c b/fs/file_table.c
index 3a2bbc5..94b1bfa 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -265,18 +265,15 @@ static void __fput(struct file *file)
 	mntput(mnt);
 }
 
-static DEFINE_SPINLOCK(delayed_fput_lock);
-static LIST_HEAD(delayed_fput_list);
+static LLIST_HEAD(delayed_fput_list);
 static void delayed_fput(struct work_struct *unused)
 {
-	LIST_HEAD(head);
-	spin_lock_irq(&delayed_fput_lock);
-	list_splice_init(&delayed_fput_list, &head);
-	spin_unlock_irq(&delayed_fput_lock);
-	while (!list_empty(&head)) {
-		struct file *f = list_first_entry(&head, struct file, f_u.fu_list);
-		list_del_init(&f->f_u.fu_list);
-		__fput(f);
+	struct llist_node *node = llist_del_all(&delayed_fput_list);
+	struct llist_node *next;
+
+	for (; node; node = next) {
+		next = llist_next(node);
+		__fput(llist_entry(node, struct file, f_u.fu_llist));
 	}
 }
 
@@ -306,7 +303,6 @@ void fput(struct file *file)
 {
 	if (atomic_long_dec_and_test(&file->f_count)) {
 		struct task_struct *task = current;
-		unsigned long flags;
 
 		file_sb_list_del(file);
 		if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) {
@@ -320,10 +316,9 @@ void fput(struct file *file)
 			 * fput to avoid leaking *file.
 			 */
 		}
-		spin_lock_irqsave(&delayed_fput_lock, flags);
-		list_add(&file->f_u.fu_list, &delayed_fput_list);
-		schedule_work(&delayed_fput_work);
-		spin_unlock_irqrestore(&delayed_fput_lock, flags);
+
+		if (llist_add(&file->f_u.fu_llist, &delayed_fput_list))
+			schedule_work(&delayed_fput_work);
 	}
 }
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 43db02e..8a60d99 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -10,6 +10,7 @@
 #include <linux/stat.h>
 #include <linux/cache.h>
 #include <linux/list.h>
+#include <linux/llist.h>
 #include <linux/radix-tree.h>
 #include <linux/rbtree.h>
 #include <linux/init.h>
@@ -767,6 +768,7 @@ struct file {
 	 */
 	union {
 		struct list_head	fu_list;
+		struct llist_node	fu_llist;
 		struct rcu_head 	fu_rcuhead;
 	} f_u;
 	struct path		f_path;
-- 
1.5.5.1


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

* [PATCH 2/3] llist: fix/simplify llist_add() and llist_add_batch()
  2013-06-15 17:29     ` [PATCH 0/3] (Was: fput: task_work_add() can fail if the caller has passed exit_task_work()) Oleg Nesterov
  2013-06-15 17:30       ` [PATCH 1/3] fput: turn "list_head delayed_fput_list" into llist_head Oleg Nesterov
@ 2013-06-15 17:30       ` Oleg Nesterov
  2013-06-15 17:30       ` [PATCH 3/3] llist: llist_add() can use llist_add_batch() Oleg Nesterov
  2013-06-15 17:46       ` [PATCH 0/3] (Was: fput: task_work_add() can fail if the caller has passed exit_task_work()) Oleg Nesterov
  3 siblings, 0 replies; 9+ messages in thread
From: Oleg Nesterov @ 2013-06-15 17:30 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Al Viro, Andrey Vagin, Eric W. Biederman, David Howells,
	Huang Ying, Peter Zijlstra, linux-kernel

1. This is mostly theoretical, but llist_add*() need ACCESS_ONCE().

   Otherwise it is not guaranteed that the first cmpxchg() uses the
   same value for old_entry and new_last->next.

2. These helpers cache the result of cmpxchg() and read the initial
   value of head->first before the main loop. I do not think this
   makes sense. In the likely case cmpxchg() succeeds, otherwise
   it doesn't hurt to reload head->first.

   I think it would be better to simplify the code and simply read
   ->first before cmpxchg().

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 include/linux/llist.h |   19 +++++++------------
 lib/llist.c           |   15 +++++----------
 2 files changed, 12 insertions(+), 22 deletions(-)

diff --git a/include/linux/llist.h b/include/linux/llist.h
index a5199f6..3e2b969 100644
--- a/include/linux/llist.h
+++ b/include/linux/llist.h
@@ -151,18 +151,13 @@ static inline struct llist_node *llist_next(struct llist_node *node)
  */
 static inline bool llist_add(struct llist_node *new, struct llist_head *head)
 {
-	struct llist_node *entry, *old_entry;
-
-	entry = head->first;
-	for (;;) {
-		old_entry = entry;
-		new->next = entry;
-		entry = cmpxchg(&head->first, old_entry, new);
-		if (entry == old_entry)
-			break;
-	}
-
-	return old_entry == NULL;
+	struct llist_node *first;
+
+	do {
+		new->next = first = ACCESS_ONCE(head->first);
+	} while (cmpxchg(&head->first, first, new) != first);
+
+	return !first;
 }
 
 /**
diff --git a/lib/llist.c b/lib/llist.c
index 4a15115..4a70d12 100644
--- a/lib/llist.c
+++ b/lib/llist.c
@@ -39,18 +39,13 @@
 bool llist_add_batch(struct llist_node *new_first, struct llist_node *new_last,
 		     struct llist_head *head)
 {
-	struct llist_node *entry, *old_entry;
+	struct llist_node *first;
 
-	entry = head->first;
-	for (;;) {
-		old_entry = entry;
-		new_last->next = entry;
-		entry = cmpxchg(&head->first, old_entry, new_first);
-		if (entry == old_entry)
-			break;
-	}
+	do {
+		new_last->next = first = ACCESS_ONCE(head->first);
+	} while (cmpxchg(&head->first, first, new_first) != first);
 
-	return old_entry == NULL;
+	return !first;
 }
 EXPORT_SYMBOL_GPL(llist_add_batch);
 
-- 
1.5.5.1


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

* [PATCH 3/3] llist: llist_add() can use llist_add_batch()
  2013-06-15 17:29     ` [PATCH 0/3] (Was: fput: task_work_add() can fail if the caller has passed exit_task_work()) Oleg Nesterov
  2013-06-15 17:30       ` [PATCH 1/3] fput: turn "list_head delayed_fput_list" into llist_head Oleg Nesterov
  2013-06-15 17:30       ` [PATCH 2/3] llist: fix/simplify llist_add() and llist_add_batch() Oleg Nesterov
@ 2013-06-15 17:30       ` Oleg Nesterov
  2013-06-15 17:46       ` [PATCH 0/3] (Was: fput: task_work_add() can fail if the caller has passed exit_task_work()) Oleg Nesterov
  3 siblings, 0 replies; 9+ messages in thread
From: Oleg Nesterov @ 2013-06-15 17:30 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Al Viro, Andrey Vagin, Eric W. Biederman, David Howells,
	Huang Ying, Peter Zijlstra, linux-kernel

llist_add(new, head) can simply use llist_add_batch(new, new, head),
no need to duplicate the code.

This obviously uninlines llist_add() and to me this is a win. But we
can make llist_add_batch() inline if this is desirable, in this case
gcc can notice that new_first == new_last if the caller is llist_add().

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 include/linux/llist.h |   14 ++++----------
 1 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/include/linux/llist.h b/include/linux/llist.h
index 3e2b969..cdaa7f0 100644
--- a/include/linux/llist.h
+++ b/include/linux/llist.h
@@ -142,6 +142,9 @@ static inline struct llist_node *llist_next(struct llist_node *node)
 	return node->next;
 }
 
+extern bool llist_add_batch(struct llist_node *new_first,
+			    struct llist_node *new_last,
+			    struct llist_head *head);
 /**
  * llist_add - add a new entry
  * @new:	new entry to be added
@@ -151,13 +154,7 @@ static inline struct llist_node *llist_next(struct llist_node *node)
  */
 static inline bool llist_add(struct llist_node *new, struct llist_head *head)
 {
-	struct llist_node *first;
-
-	do {
-		new->next = first = ACCESS_ONCE(head->first);
-	} while (cmpxchg(&head->first, first, new) != first);
-
-	return !first;
+	return llist_add_batch(new, new, head);
 }
 
 /**
@@ -173,9 +170,6 @@ static inline struct llist_node *llist_del_all(struct llist_head *head)
 	return xchg(&head->first, NULL);
 }
 
-extern bool llist_add_batch(struct llist_node *new_first,
-			    struct llist_node *new_last,
-			    struct llist_head *head);
 extern struct llist_node *llist_del_first(struct llist_head *head);
 
 #endif /* LLIST_H */
-- 
1.5.5.1


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

* Re: [PATCH 0/3] (Was: fput: task_work_add() can fail if the caller has passed exit_task_work())
  2013-06-15 17:29     ` [PATCH 0/3] (Was: fput: task_work_add() can fail if the caller has passed exit_task_work()) Oleg Nesterov
                         ` (2 preceding siblings ...)
  2013-06-15 17:30       ` [PATCH 3/3] llist: llist_add() can use llist_add_batch() Oleg Nesterov
@ 2013-06-15 17:46       ` Oleg Nesterov
  3 siblings, 0 replies; 9+ messages in thread
From: Oleg Nesterov @ 2013-06-15 17:46 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Al Viro, Andrey Vagin, Eric W. Biederman, David Howells,
	linux-kernel, Huang Ying, Peter Zijlstra

sorry, forgot to mention...

On 06/15, Oleg Nesterov wrote:
>
> > OT: I don't think that schedule_work() needs to be inside the locked
> > region.  Scalability improvements beckon!
>
> Yeees, I thought about this too.
>
> Performance-wise this can't really help, this case is unlikely. But
> I think this change makes this code a bit simpler, so please see 1/3.

This is on top of
fput-task_work_add-can-fail-if-the-caller-has-passed-exit_task_work-fix.patch

it textually depends on the comment block in fput() added by that patch.

Oleg.


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

end of thread, other threads:[~2013-06-15 17:51 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-14 19:09 [PATCH 0/2] fix ->shm_file leak Oleg Nesterov
2013-06-14 19:09 ` [PATCH 1/2] fput: task_work_add() can fail if the caller has passed exit_task_work() Oleg Nesterov
2013-06-14 21:58   ` Andrew Morton
2013-06-15 17:29     ` [PATCH 0/3] (Was: fput: task_work_add() can fail if the caller has passed exit_task_work()) Oleg Nesterov
2013-06-15 17:30       ` [PATCH 1/3] fput: turn "list_head delayed_fput_list" into llist_head Oleg Nesterov
2013-06-15 17:30       ` [PATCH 2/3] llist: fix/simplify llist_add() and llist_add_batch() Oleg Nesterov
2013-06-15 17:30       ` [PATCH 3/3] llist: llist_add() can use llist_add_batch() Oleg Nesterov
2013-06-15 17:46       ` [PATCH 0/3] (Was: fput: task_work_add() can fail if the caller has passed exit_task_work()) Oleg Nesterov
2013-06-14 19:09 ` [PATCH 2/2] move exit_task_namespaces() outside of exit_notify() Oleg Nesterov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox