All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups
@ 2014-01-07 18:12 Oleg Nesterov
  2014-01-07 18:13 ` [PATCH 1/2] introduce __fcheck_files() to fix rcu_dereference_check_fdtable(), kill rcu_my_thread_group_empty() Oleg Nesterov
                   ` (2 more replies)
  0 siblings, 3 replies; 20+ messages in thread
From: Oleg Nesterov @ 2014-01-07 18:12 UTC (permalink / raw)
  To: Andrew Morton, Paul E. McKenney
  Cc: Al Viro, Dipankar Sarma, Eric Dumazet, linux-kernel

Hello.

I tried to audit the users of thread_group_empty() (we need
to change it) and found rcu_my_thread_group_empty() which
looks wrong.

The patches look simple, but I am not sure it is fine to use
rcu_lock_acquire() directly. Perhaps it makes sense to add a
new helper? Note that we have more users which take rcu lock
only to shut up lockdep. Please review.

And I am a bit confused. Perhaps rcu_lock_acquire() should
depend on CONFIG_PROVE_RCU, not on CONFIG_DEBUG_LOCK_ALLOC?
We only need rcu_lock_map/etc for rcu_lockdep_assert().

Oleg.

 fs/file.c                |   24 +++++++++++-------------
 include/linux/fdtable.h  |   19 +++++++++++++------
 include/linux/rcupdate.h |    2 --
 kernel/rcu/update.c      |   11 -----------
 4 files changed, 24 insertions(+), 32 deletions(-)


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

* [PATCH 1/2] introduce __fcheck_files() to fix rcu_dereference_check_fdtable(), kill rcu_my_thread_group_empty()
  2014-01-07 18:12 [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups Oleg Nesterov
@ 2014-01-07 18:13 ` Oleg Nesterov
  2014-01-07 18:13 ` [PATCH 2/2] change close_files() to use rcu_lock_acquire() to shut up RCU-lockdep Oleg Nesterov
  2014-01-08 13:28 ` [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups Paul E. McKenney
  2 siblings, 0 replies; 20+ messages in thread
From: Oleg Nesterov @ 2014-01-07 18:13 UTC (permalink / raw)
  To: Andrew Morton, Paul E. McKenney
  Cc: Al Viro, Dipankar Sarma, Eric Dumazet, linux-kernel

rcu_dereference_check_fdtable() looks very wrong,

1. rcu_my_thread_group_empty() was added by 844b9a8707f1 "vfs: fix
   RCU-lockdep false positive due to /proc" but it doesn't really
   fix the problem. A CLONE_THREAD (without CLONE_FILES) task can
   hit the same race with get_files_struct().

   And otoh rcu_my_thread_group_empty() can suppress the correct
   warning if the caller is the CLONE_FILES (without CLONE_THREAD)
   task.

2. files->count == 1 check is not really right too. Even if this
   files_struct is not shared it is not safe to access it lockless
   unless the caller is the owner.

   Otoh, this check is sub-optimal. files->count == 0 always means
   it is safe to use it lockless even if files != current->files,
   but put_files_struct() has to take rcu_read_lock(). See the next
   patch.

This patch removes the buggy checks and adds the new helper which
simply does rcu_lock_acquire/release around fcheck_files(). The
files->count == 1 callers, fget_light() and fget_raw_light(), can
use this helper to avoid the warning from RCU-lockdep.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 fs/file.c                |    4 ++--
 include/linux/fdtable.h  |   19 +++++++++++++------
 include/linux/rcupdate.h |    2 --
 kernel/rcu/update.c      |   11 -----------
 4 files changed, 15 insertions(+), 21 deletions(-)

diff --git a/fs/file.c b/fs/file.c
index 4a78f98..957cbc0 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -707,7 +707,7 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
 
 	*fput_needed = 0;
 	if (atomic_read(&files->count) == 1) {
-		file = fcheck_files(files, fd);
+		file = __fcheck_files(files, fd);
 		if (file && (file->f_mode & FMODE_PATH))
 			file = NULL;
 	} else {
@@ -735,7 +735,7 @@ struct file *fget_raw_light(unsigned int fd, int *fput_needed)
 
 	*fput_needed = 0;
 	if (atomic_read(&files->count) == 1) {
-		file = fcheck_files(files, fd);
+		file = __fcheck_files(files, fd);
 	} else {
 		rcu_read_lock();
 		file = fcheck_files(files, fd);
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index 085197b..f39d50a 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -60,10 +60,7 @@ struct files_struct {
 };
 
 #define rcu_dereference_check_fdtable(files, fdtfd) \
-	(rcu_dereference_check((fdtfd), \
-			       lockdep_is_held(&(files)->file_lock) || \
-			       atomic_read(&(files)->count) == 1 || \
-			       rcu_my_thread_group_empty()))
+	rcu_dereference_check((fdtfd), lockdep_is_held(&(files)->file_lock))
 
 #define files_fdtable(files) \
 		(rcu_dereference_check_fdtable((files), (files)->fdt))
@@ -74,9 +71,9 @@ struct dentry;
 
 extern void __init files_defer_init(void);
 
-static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
+static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd)
 {
-	struct file * file = NULL;
+	struct file *file = NULL;
 	struct fdtable *fdt = files_fdtable(files);
 
 	if (fd < fdt->max_fds)
@@ -84,6 +81,16 @@ static inline struct file * fcheck_files(struct files_struct *files, unsigned in
 	return file;
 }
 
+/* The caller must ensure that fd table isn't shared */
+static inline struct file *__fcheck_files(struct files_struct *files, unsigned int fd)
+{
+	struct file *file;
+	/* make rcu_dereference_check_fdtable() happy */
+	rcu_lock_acquire(&rcu_lock_map);
+	file = fcheck_files(files, fd);
+	rcu_lock_release(&rcu_lock_map);
+	return file;
+}
 /*
  * Check whether the specified fd has an open file.
  */
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 39cbb88..a2482cf 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -448,8 +448,6 @@ static inline int rcu_read_lock_sched_held(void)
 
 #ifdef CONFIG_PROVE_RCU
 
-extern int rcu_my_thread_group_empty(void);
-
 /**
  * rcu_lockdep_assert - emit lockdep splat if specified condition not met
  * @c: condition to check
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
index 6cb3dff..a3596c8 100644
--- a/kernel/rcu/update.c
+++ b/kernel/rcu/update.c
@@ -195,17 +195,6 @@ void wait_rcu_gp(call_rcu_func_t crf)
 }
 EXPORT_SYMBOL_GPL(wait_rcu_gp);
 
-#ifdef CONFIG_PROVE_RCU
-/*
- * wrapper function to avoid #include problems.
- */
-int rcu_my_thread_group_empty(void)
-{
-	return thread_group_empty(current);
-}
-EXPORT_SYMBOL_GPL(rcu_my_thread_group_empty);
-#endif /* #ifdef CONFIG_PROVE_RCU */
-
 #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
 static inline void debug_init_rcu_head(struct rcu_head *head)
 {
-- 
1.5.5.1


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

* [PATCH 2/2] change close_files() to use rcu_lock_acquire() to shut up RCU-lockdep
  2014-01-07 18:12 [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups Oleg Nesterov
  2014-01-07 18:13 ` [PATCH 1/2] introduce __fcheck_files() to fix rcu_dereference_check_fdtable(), kill rcu_my_thread_group_empty() Oleg Nesterov
@ 2014-01-07 18:13 ` Oleg Nesterov
  2014-01-08 13:28 ` [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups Paul E. McKenney
  2 siblings, 0 replies; 20+ messages in thread
From: Oleg Nesterov @ 2014-01-07 18:13 UTC (permalink / raw)
  To: Andrew Morton, Paul E. McKenney
  Cc: Al Viro, Dipankar Sarma, Eric Dumazet, linux-kernel

put_files_struct() and close_files() do rcu_read_lock() to make
rcu_dereference_check_fdtable() happy.

We can use rcu_lock_acquire(&rcu_lock_map) instead, this looks
self-explanatory and this is nop without CONFIG_DEBUG_LOCK_ALLOC().

While at it, change close_files() to return fdt, this avoids another
rcu_read_lock() + files_fdtable() in put_files_struct().

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 fs/file.c |   20 +++++++++-----------
 1 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/fs/file.c b/fs/file.c
index 957cbc0..716d747 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -348,7 +348,7 @@ out:
 	return NULL;
 }
 
-static void close_files(struct files_struct * files)
+static struct fdtable *close_files(struct files_struct * files)
 {
 	int i, j;
 	struct fdtable *fdt;
@@ -358,11 +358,12 @@ static void close_files(struct files_struct * files)
 	/*
 	 * It is safe to dereference the fd table without RCU or
 	 * ->file_lock because this is the last reference to the
-	 * files structure.  But use RCU to shut RCU-lockdep up.
+	 * files structure. But we need to shut RCU-lockdep up.
 	 */
-	rcu_read_lock();
+	rcu_lock_acquire(&rcu_lock_map);
 	fdt = files_fdtable(files);
-	rcu_read_unlock();
+	rcu_lock_release(&rcu_lock_map);
+
 	for (;;) {
 		unsigned long set;
 		i = j * BITS_PER_LONG;
@@ -381,6 +382,8 @@ static void close_files(struct files_struct * files)
 			set >>= 1;
 		}
 	}
+
+	return fdt;
 }
 
 struct files_struct *get_files_struct(struct task_struct *task)
@@ -398,14 +401,9 @@ struct files_struct *get_files_struct(struct task_struct *task)
 
 void put_files_struct(struct files_struct *files)
 {
-	struct fdtable *fdt;
-
 	if (atomic_dec_and_test(&files->count)) {
-		close_files(files);
-		/* not really needed, since nobody can see us */
-		rcu_read_lock();
-		fdt = files_fdtable(files);
-		rcu_read_unlock();
+		struct fdtable *fdt = close_files(files);
+
 		/* free the arrays if they are not embedded */
 		if (fdt != &files->fdtab)
 			__free_fdtable(fdt);
-- 
1.5.5.1


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

* Re: [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups
  2014-01-07 18:12 [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups Oleg Nesterov
  2014-01-07 18:13 ` [PATCH 1/2] introduce __fcheck_files() to fix rcu_dereference_check_fdtable(), kill rcu_my_thread_group_empty() Oleg Nesterov
  2014-01-07 18:13 ` [PATCH 2/2] change close_files() to use rcu_lock_acquire() to shut up RCU-lockdep Oleg Nesterov
@ 2014-01-08 13:28 ` Paul E. McKenney
  2014-01-08 15:19   ` Oleg Nesterov
  2 siblings, 1 reply; 20+ messages in thread
From: Paul E. McKenney @ 2014-01-08 13:28 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Andrew Morton, Al Viro, Dipankar Sarma, Eric Dumazet, linux-kernel

On Tue, Jan 07, 2014 at 07:12:58PM +0100, Oleg Nesterov wrote:
> Hello.
> 
> I tried to audit the users of thread_group_empty() (we need
> to change it) and found rcu_my_thread_group_empty() which
> looks wrong.
> 
> The patches look simple, but I am not sure it is fine to use
> rcu_lock_acquire() directly. Perhaps it makes sense to add a
> new helper? Note that we have more users which take rcu lock
> only to shut up lockdep. Please review.
> 
> And I am a bit confused. Perhaps rcu_lock_acquire() should
> depend on CONFIG_PROVE_RCU, not on CONFIG_DEBUG_LOCK_ALLOC?
> We only need rcu_lock_map/etc for rcu_lockdep_assert().

I am not all that excited about invoking rcu_lock_acquire() outside
of RCU...

Another approach would be to add an argument to files_fdtable()
that is zero normally and one for "we know we don't need RCU
protection."  Then rcu_dereference_check() could be something
like the following:

#define files_fdtable(files, c) \
		(rcu_dereference_check_fdtable((files), (files)->fdt) || c)

Would that work?

							Thanx, Paul

> Oleg.
> 
>  fs/file.c                |   24 +++++++++++-------------
>  include/linux/fdtable.h  |   19 +++++++++++++------
>  include/linux/rcupdate.h |    2 --
>  kernel/rcu/update.c      |   11 -----------
>  4 files changed, 24 insertions(+), 32 deletions(-)
> 


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

* Re: [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups
  2014-01-08 13:28 ` [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups Paul E. McKenney
@ 2014-01-08 15:19   ` Oleg Nesterov
  2014-01-09  1:16     ` Paul E. McKenney
  0 siblings, 1 reply; 20+ messages in thread
From: Oleg Nesterov @ 2014-01-08 15:19 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Andrew Morton, Al Viro, Dipankar Sarma, Eric Dumazet, linux-kernel

On 01/08, Paul E. McKenney wrote:
>
> I am not all that excited about invoking rcu_lock_acquire() outside
> of RCU...

Yes, me too. That is why I thought about the helper with a good name,
see below.

> Another approach would be to add an argument to files_fdtable()
> that is zero normally and one for "we know we don't need RCU
> protection."  Then rcu_dereference_check() could be something
> like the following:
>
> #define files_fdtable(files, c) \
> 		(rcu_dereference_check_fdtable((files), (files)->fdt) || c)
>
> Would that work?

Yes, I considered this optiion, but this needs much more uglifications^W
changes.

Either we need to change all users of files_fdtable(), or we need something
like

	#define __rcu_dereference_check_fdtable(files, unshared, fdtfd) \
		rcu_dereference_check((fdtfd), unshared || lockdep_is_held(&(files)->file_lock))

	#define rcu_dereference_check_fdtable(files, fdtfd)
		__rcu_dereference_check_fdtable(files, false, fdtfd)

	#define __files_fdtable(files)
		__rcu_dereference_check_fdtable((files), true, (files)->fdt)

	#define files_fdtable(files)
		__rcu_dereference_check_fdtable((files), false, (files)->fdt)

Plus we need

	static inline struct file *__fcheck_files(struct files_struct *files,
						bool unshared, unsigned int fd)
	{
		struct file *file = NULL;
		struct fdtable *fdt = __rcu_dereference_check_fdtable(files, unshared, files->fdt);

		if (fd < fdt->max_fds)
			file = __rcu_dereference_check_fdtable(files, unshared, fdt->fd[fd]);
		return file;
	}

doesn't look very nice...

As for 2/2, probably close_files() can simply do

	/*
	 * It is safe to dereference the fd table without RCU or
	 * ->file_lock because this is the last reference to the
	 * files structure.
	 */
	fdt = rcu_dereference_raw(files->fdt);

Or we can add

	#define __files_fdtable(files)	\
		 rcu_dereference_raw((files)->fdt)

but it is not clear to me what 1/1 should do. Perhaps

	static inline struct file *__fcheck_files(struct files_struct *files, unsigned int fd)
	{
		struct fdtable *fdt = rcu_dereference_raw(files->fdt);
		struct file *file = NULL;

		if (fd < fdt->max_fds)
			file = rcu_dereference_raw(fdt->fd[fd]);

		return file;
	}

	static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd)
	{
		rcu_lockdep_assert(rcu_read_lock_held() ||
				   lockdep_is_held(files->file_lock),
				   "message");
		return __fcheck_files(files, fd);
	}

?

Oleg.


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

* Re: [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups
  2014-01-08 15:19   ` Oleg Nesterov
@ 2014-01-09  1:16     ` Paul E. McKenney
  2014-01-10 15:34       ` Oleg Nesterov
  0 siblings, 1 reply; 20+ messages in thread
From: Paul E. McKenney @ 2014-01-09  1:16 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Andrew Morton, Al Viro, Dipankar Sarma, Eric Dumazet, linux-kernel

On Wed, Jan 08, 2014 at 04:19:18PM +0100, Oleg Nesterov wrote:
> On 01/08, Paul E. McKenney wrote:
> >
> > I am not all that excited about invoking rcu_lock_acquire() outside
> > of RCU...
> 
> Yes, me too. That is why I thought about the helper with a good name,
> see below.
> 
> > Another approach would be to add an argument to files_fdtable()
> > that is zero normally and one for "we know we don't need RCU
> > protection."  Then rcu_dereference_check() could be something
> > like the following:
> >
> > #define files_fdtable(files, c) \
> > 		(rcu_dereference_check_fdtable((files), (files)->fdt) || c)
> >
> > Would that work?
> 
> Yes, I considered this optiion, but this needs much more uglifications^W
> changes.
> 
> Either we need to change all users of files_fdtable(), or we need something
> like

There are only about 20 uses of files_fdtable() in 3.12, with almost all
of them in fs/file.c.  So is changing all the users really all that
problematic?

							Thanx, Paul

> 	#define __rcu_dereference_check_fdtable(files, unshared, fdtfd) \
> 		rcu_dereference_check((fdtfd), unshared || lockdep_is_held(&(files)->file_lock))
> 
> 	#define rcu_dereference_check_fdtable(files, fdtfd)
> 		__rcu_dereference_check_fdtable(files, false, fdtfd)
> 
> 	#define __files_fdtable(files)
> 		__rcu_dereference_check_fdtable((files), true, (files)->fdt)
> 
> 	#define files_fdtable(files)
> 		__rcu_dereference_check_fdtable((files), false, (files)->fdt)
> 
> Plus we need
> 
> 	static inline struct file *__fcheck_files(struct files_struct *files,
> 						bool unshared, unsigned int fd)
> 	{
> 		struct file *file = NULL;
> 		struct fdtable *fdt = __rcu_dereference_check_fdtable(files, unshared, files->fdt);
> 
> 		if (fd < fdt->max_fds)
> 			file = __rcu_dereference_check_fdtable(files, unshared, fdt->fd[fd]);
> 		return file;
> 	}
> 
> doesn't look very nice...
> 
> As for 2/2, probably close_files() can simply do
> 
> 	/*
> 	 * It is safe to dereference the fd table without RCU or
> 	 * ->file_lock because this is the last reference to the
> 	 * files structure.
> 	 */
> 	fdt = rcu_dereference_raw(files->fdt);
> 
> Or we can add
> 
> 	#define __files_fdtable(files)	\
> 		 rcu_dereference_raw((files)->fdt)
> 
> but it is not clear to me what 1/1 should do. Perhaps
> 
> 	static inline struct file *__fcheck_files(struct files_struct *files, unsigned int fd)
> 	{
> 		struct fdtable *fdt = rcu_dereference_raw(files->fdt);
> 		struct file *file = NULL;
> 
> 		if (fd < fdt->max_fds)
> 			file = rcu_dereference_raw(fdt->fd[fd]);
> 
> 		return file;
> 	}
> 
> 	static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd)
> 	{
> 		rcu_lockdep_assert(rcu_read_lock_held() ||
> 				   lockdep_is_held(files->file_lock),
> 				   "message");
> 		return __fcheck_files(files, fd);
> 	}
> 
> ?
> 
> Oleg.
> 


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

* Re: [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups
  2014-01-09  1:16     ` Paul E. McKenney
@ 2014-01-10 15:34       ` Oleg Nesterov
  2014-01-11  6:34         ` Paul E. McKenney
  0 siblings, 1 reply; 20+ messages in thread
From: Oleg Nesterov @ 2014-01-10 15:34 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Andrew Morton, Al Viro, Dipankar Sarma, Eric Dumazet, linux-kernel

On 01/08, Paul E. McKenney wrote:
>
> On Wed, Jan 08, 2014 at 04:19:18PM +0100, Oleg Nesterov wrote:
> > On 01/08, Paul E. McKenney wrote:
> > >
> > > Another approach would be to add an argument to files_fdtable()
> > > that is zero normally and one for "we know we don't need RCU
> > > protection."  Then rcu_dereference_check() could be something
> > > like the following:
> > >
> > > #define files_fdtable(files, c) \
> > > 		(rcu_dereference_check_fdtable((files), (files)->fdt) || c)
> > >
> > > Would that work?
> >
> > Yes, I considered this optiion, but this needs much more uglifications^W
> > changes.
> >
> > Either we need to change all users of files_fdtable(), or we need something
> > like
>
> There are only about 20 uses of files_fdtable() in 3.12, with almost all
> of them in fs/file.c.  So is changing all the users really all that
> problematic?

But only one user, close_files(), needs files_fdtable(files, true). Why
complicate the patch and the code? I think it would be better to simply
change close_files() to use rcu_dereference_raw().

And note that rcu_dereference_check_fdtable() needs the new argument too.

And we should also take care of fcheck_files(),

> > 	static inline struct file *__fcheck_files(struct files_struct *files, unsigned int fd)
> > 	{
> > 		struct fdtable *fdt = rcu_dereference_raw(files->fdt);
> > 		struct file *file = NULL;
> >
> > 		if (fd < fdt->max_fds)
> > 			file = rcu_dereference_raw(fdt->fd[fd]);
> >
> > 		return file;
> > 	}
> >
> > 	static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd)
> > 	{
> > 		rcu_lockdep_assert(rcu_read_lock_held() ||
> > 				   lockdep_is_held(files->file_lock),
> > 				   "message");
> > 		return __fcheck_files(files, fd);
> > 	}

doesn't this look much simpler than adding the "bool unshared" argument
and changing the callers?

Oleg.


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

* Re: [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups
  2014-01-10 15:34       ` Oleg Nesterov
@ 2014-01-11  6:34         ` Paul E. McKenney
  2014-01-11 18:19           ` [PATCH v2 " Oleg Nesterov
  0 siblings, 1 reply; 20+ messages in thread
From: Paul E. McKenney @ 2014-01-11  6:34 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Andrew Morton, Al Viro, Dipankar Sarma, Eric Dumazet, linux-kernel

On Fri, Jan 10, 2014 at 04:34:59PM +0100, Oleg Nesterov wrote:
> On 01/08, Paul E. McKenney wrote:
> >
> > On Wed, Jan 08, 2014 at 04:19:18PM +0100, Oleg Nesterov wrote:
> > > On 01/08, Paul E. McKenney wrote:
> > > >
> > > > Another approach would be to add an argument to files_fdtable()
> > > > that is zero normally and one for "we know we don't need RCU
> > > > protection."  Then rcu_dereference_check() could be something
> > > > like the following:
> > > >
> > > > #define files_fdtable(files, c) \
> > > > 		(rcu_dereference_check_fdtable((files), (files)->fdt) || c)
> > > >
> > > > Would that work?
> > >
> > > Yes, I considered this optiion, but this needs much more uglifications^W
> > > changes.
> > >
> > > Either we need to change all users of files_fdtable(), or we need something
> > > like
> >
> > There are only about 20 uses of files_fdtable() in 3.12, with almost all
> > of them in fs/file.c.  So is changing all the users really all that
> > problematic?
> 
> But only one user, close_files(), needs files_fdtable(files, true). Why
> complicate the patch and the code? I think it would be better to simply
> change close_files() to use rcu_dereference_raw().
> 
> And note that rcu_dereference_check_fdtable() needs the new argument too.
> 
> And we should also take care of fcheck_files(),
> 
> > > 	static inline struct file *__fcheck_files(struct files_struct *files, unsigned int fd)
> > > 	{
> > > 		struct fdtable *fdt = rcu_dereference_raw(files->fdt);
> > > 		struct file *file = NULL;
> > >
> > > 		if (fd < fdt->max_fds)
> > > 			file = rcu_dereference_raw(fdt->fd[fd]);
> > >
> > > 		return file;
> > > 	}
> > >
> > > 	static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd)
> > > 	{
> > > 		rcu_lockdep_assert(rcu_read_lock_held() ||
> > > 				   lockdep_is_held(files->file_lock),
> > > 				   "message");
> > > 		return __fcheck_files(files, fd);
> > > 	}
> 
> doesn't this look much simpler than adding the "bool unshared" argument
> and changing the callers?

I might be being too paranoid, but my concern with using rcu_lock_acquire()
and rcu_lock_release() is the possibility of code needing rcu_read_lock()
appearing somewhere in the function-call graph between rcu_lock_acquire()
and rcu_lock_release().  In that case, lockdep would be happy, but the
required RCU protection would not be present.

Sort of like my experience with people using RCU from idle.

							Thanx, Paul


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

* [PATCH v2 0/2] rcu_dereference_check_fdtable fix/cleanups
  2014-01-11  6:34         ` Paul E. McKenney
@ 2014-01-11 18:19           ` Oleg Nesterov
  2014-01-11 18:19             ` [PATCH v2 1/2] introduce __fcheck_files() to fix rcu_dereference_check_fdtable(), kill rcu_my_thread_group_empty() Oleg Nesterov
                               ` (2 more replies)
  0 siblings, 3 replies; 20+ messages in thread
From: Oleg Nesterov @ 2014-01-11 18:19 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Andrew Morton, Al Viro, Dipankar Sarma, Eric Dumazet, linux-kernel

On 01/10, Paul E. McKenney wrote:
>
> On Fri, Jan 10, 2014 at 04:34:59PM +0100, Oleg Nesterov wrote:
> >
> > doesn't this look much simpler than adding the "bool unshared" argument
> > and changing the callers?
>
> I might be being too paranoid, but my concern with using rcu_lock_acquire()
> and rcu_lock_release()

And I agree, I no longer suggest to use rcu_lock_acquire/release.

It seems that you misunderstood me, let me send v2 for review.

Oleg.

 fs/file.c                |   30 +++++++++++-------------------
 include/linux/fdtable.h  |   35 +++++++++++++++++++++--------------
 include/linux/rcupdate.h |    2 --
 kernel/rcu/update.c      |   11 -----------
 4 files changed, 32 insertions(+), 46 deletions(-)


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

* [PATCH v2 1/2] introduce __fcheck_files() to fix rcu_dereference_check_fdtable(), kill rcu_my_thread_group_empty()
  2014-01-11 18:19           ` [PATCH v2 " Oleg Nesterov
@ 2014-01-11 18:19             ` Oleg Nesterov
  2014-01-11 18:19             ` [PATCH v2 2/2] change close_files() to use rcu_dereference_raw(files->fdt) Oleg Nesterov
  2014-01-11 22:27             ` [PATCH v2 0/2] rcu_dereference_check_fdtable fix/cleanups Paul E. McKenney
  2 siblings, 0 replies; 20+ messages in thread
From: Oleg Nesterov @ 2014-01-11 18:19 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Andrew Morton, Al Viro, Dipankar Sarma, Eric Dumazet, linux-kernel

rcu_dereference_check_fdtable() looks very wrong,

1. rcu_my_thread_group_empty() was added by 844b9a8707f1 "vfs: fix
   RCU-lockdep false positive due to /proc" but it doesn't really
   fix the problem. A CLONE_THREAD (without CLONE_FILES) task can
   hit the same race with get_files_struct().

   And otoh rcu_my_thread_group_empty() can suppress the correct
   warning if the caller is the CLONE_FILES (without CLONE_THREAD)
   task.

2. files->count == 1 check is not really right too. Even if this
   files_struct is not shared it is not safe to access it lockless
   unless the caller is the owner.

   Otoh, this check is sub-optimal. files->count == 0 always means
   it is safe to use it lockless even if files != current->files,
   but put_files_struct() has to take rcu_read_lock(). See the next
   patch.

This patch removes the buggy checks and turns fcheck_files() into
__fcheck_files() which uses rcu_dereference_raw(), the "unshared"
callers, fget_light() and fget_raw_light(), can use it to avoid
the warning from RCU-lockdep.

fcheck_files() is trivially reimplemented as rcu_lockdep_assert()
plus __fcheck_files().

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 fs/file.c                |    4 ++--
 include/linux/fdtable.h  |   35 +++++++++++++++++++++--------------
 include/linux/rcupdate.h |    2 --
 kernel/rcu/update.c      |   11 -----------
 4 files changed, 23 insertions(+), 29 deletions(-)

diff --git a/fs/file.c b/fs/file.c
index 4a78f98..957cbc0 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -707,7 +707,7 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
 
 	*fput_needed = 0;
 	if (atomic_read(&files->count) == 1) {
-		file = fcheck_files(files, fd);
+		file = __fcheck_files(files, fd);
 		if (file && (file->f_mode & FMODE_PATH))
 			file = NULL;
 	} else {
@@ -735,7 +735,7 @@ struct file *fget_raw_light(unsigned int fd, int *fput_needed)
 
 	*fput_needed = 0;
 	if (atomic_read(&files->count) == 1) {
-		file = fcheck_files(files, fd);
+		file = __fcheck_files(files, fd);
 	} else {
 		rcu_read_lock();
 		file = fcheck_files(files, fd);
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index 085197b..70e8e21 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -59,29 +59,36 @@ struct files_struct {
 	struct file __rcu * fd_array[NR_OPEN_DEFAULT];
 };
 
-#define rcu_dereference_check_fdtable(files, fdtfd) \
-	(rcu_dereference_check((fdtfd), \
-			       lockdep_is_held(&(files)->file_lock) || \
-			       atomic_read(&(files)->count) == 1 || \
-			       rcu_my_thread_group_empty()))
-
-#define files_fdtable(files) \
-		(rcu_dereference_check_fdtable((files), (files)->fdt))
-
 struct file_operations;
 struct vfsmount;
 struct dentry;
 
 extern void __init files_defer_init(void);
 
-static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
+#define rcu_dereference_check_fdtable(files, fdtfd) \
+	rcu_dereference_check((fdtfd), lockdep_is_held(&(files)->file_lock))
+
+#define files_fdtable(files) \
+	rcu_dereference_check_fdtable((files), (files)->fdt)
+
+/*
+ * The caller must ensure that fd table isn't shared or hold rcu or file lock
+ */
+static inline struct file *__fcheck_files(struct files_struct *files, unsigned int fd)
 {
-	struct file * file = NULL;
-	struct fdtable *fdt = files_fdtable(files);
+	struct fdtable *fdt = rcu_dereference_raw(files->fdt);
 
 	if (fd < fdt->max_fds)
-		file = rcu_dereference_check_fdtable(files, fdt->fd[fd]);
-	return file;
+		return rcu_dereference_raw(fdt->fd[fd]);
+	return NULL;
+}
+
+static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd)
+{
+	rcu_lockdep_assert(rcu_read_lock_held() ||
+			   lockdep_is_held(&files->file_lock),
+			   "suspicious rcu_dereference_check() usage");
+	return __fcheck_files(files, fd);
 }
 
 /*
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 39cbb88..a2482cf 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -448,8 +448,6 @@ static inline int rcu_read_lock_sched_held(void)
 
 #ifdef CONFIG_PROVE_RCU
 
-extern int rcu_my_thread_group_empty(void);
-
 /**
  * rcu_lockdep_assert - emit lockdep splat if specified condition not met
  * @c: condition to check
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
index 6cb3dff..a3596c8 100644
--- a/kernel/rcu/update.c
+++ b/kernel/rcu/update.c
@@ -195,17 +195,6 @@ void wait_rcu_gp(call_rcu_func_t crf)
 }
 EXPORT_SYMBOL_GPL(wait_rcu_gp);
 
-#ifdef CONFIG_PROVE_RCU
-/*
- * wrapper function to avoid #include problems.
- */
-int rcu_my_thread_group_empty(void)
-{
-	return thread_group_empty(current);
-}
-EXPORT_SYMBOL_GPL(rcu_my_thread_group_empty);
-#endif /* #ifdef CONFIG_PROVE_RCU */
-
 #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
 static inline void debug_init_rcu_head(struct rcu_head *head)
 {
-- 
1.5.5.1



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

* [PATCH v2 2/2] change close_files() to use rcu_dereference_raw(files->fdt)
  2014-01-11 18:19           ` [PATCH v2 " Oleg Nesterov
  2014-01-11 18:19             ` [PATCH v2 1/2] introduce __fcheck_files() to fix rcu_dereference_check_fdtable(), kill rcu_my_thread_group_empty() Oleg Nesterov
@ 2014-01-11 18:19             ` Oleg Nesterov
  2014-01-11 22:27             ` [PATCH v2 0/2] rcu_dereference_check_fdtable fix/cleanups Paul E. McKenney
  2 siblings, 0 replies; 20+ messages in thread
From: Oleg Nesterov @ 2014-01-11 18:19 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Andrew Morton, Al Viro, Dipankar Sarma, Eric Dumazet, linux-kernel

put_files_struct() and close_files() do rcu_read_lock() to make
rcu_dereference_check_fdtable() happy.

This looks a bit ugly, files_fdtable() just reads the pointer,
we can simply use rcu_dereference_raw() to avoid the warning.

The patch also changes close_files() to return fdt, this avoids
another rcu_read_lock()/files_fdtable() in put_files_struct().

I think close_files() needs more cleanups:

	- we do not need xchg() exactly because we are the last
	  user of this files_struct

	- "if (file)" should be turned into WARN_ON(!file)

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 fs/file.c |   26 +++++++++-----------------
 1 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/fs/file.c b/fs/file.c
index 957cbc0..d34e59e 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -348,21 +348,16 @@ out:
 	return NULL;
 }
 
-static void close_files(struct files_struct * files)
+static struct fdtable *close_files(struct files_struct * files)
 {
-	int i, j;
-	struct fdtable *fdt;
-
-	j = 0;
-
 	/*
 	 * It is safe to dereference the fd table without RCU or
 	 * ->file_lock because this is the last reference to the
-	 * files structure.  But use RCU to shut RCU-lockdep up.
+	 * files structure.
 	 */
-	rcu_read_lock();
-	fdt = files_fdtable(files);
-	rcu_read_unlock();
+	struct fdtable *fdt = rcu_dereference_raw(files->fdt);
+	int i, j = 0;
+
 	for (;;) {
 		unsigned long set;
 		i = j * BITS_PER_LONG;
@@ -381,6 +376,8 @@ static void close_files(struct files_struct * files)
 			set >>= 1;
 		}
 	}
+
+	return fdt;
 }
 
 struct files_struct *get_files_struct(struct task_struct *task)
@@ -398,14 +395,9 @@ struct files_struct *get_files_struct(struct task_struct *task)
 
 void put_files_struct(struct files_struct *files)
 {
-	struct fdtable *fdt;
-
 	if (atomic_dec_and_test(&files->count)) {
-		close_files(files);
-		/* not really needed, since nobody can see us */
-		rcu_read_lock();
-		fdt = files_fdtable(files);
-		rcu_read_unlock();
+		struct fdtable *fdt = close_files(files);
+
 		/* free the arrays if they are not embedded */
 		if (fdt != &files->fdtab)
 			__free_fdtable(fdt);
-- 
1.5.5.1



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

* Re: [PATCH v2 0/2] rcu_dereference_check_fdtable fix/cleanups
  2014-01-11 18:19           ` [PATCH v2 " Oleg Nesterov
  2014-01-11 18:19             ` [PATCH v2 1/2] introduce __fcheck_files() to fix rcu_dereference_check_fdtable(), kill rcu_my_thread_group_empty() Oleg Nesterov
  2014-01-11 18:19             ` [PATCH v2 2/2] change close_files() to use rcu_dereference_raw(files->fdt) Oleg Nesterov
@ 2014-01-11 22:27             ` Paul E. McKenney
  2014-01-13 15:47               ` [PATCH 0/3] fget*() cleanups Oleg Nesterov
  2 siblings, 1 reply; 20+ messages in thread
From: Paul E. McKenney @ 2014-01-11 22:27 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Andrew Morton, Al Viro, Dipankar Sarma, Eric Dumazet, linux-kernel

On Sat, Jan 11, 2014 at 07:19:08PM +0100, Oleg Nesterov wrote:
> On 01/10, Paul E. McKenney wrote:
> >
> > On Fri, Jan 10, 2014 at 04:34:59PM +0100, Oleg Nesterov wrote:
> > >
> > > doesn't this look much simpler than adding the "bool unshared" argument
> > > and changing the callers?
> >
> > I might be being too paranoid, but my concern with using rcu_lock_acquire()
> > and rcu_lock_release()
> 
> And I agree, I no longer suggest to use rcu_lock_acquire/release.
> 
> It seems that you misunderstood me, let me send v2 for review.

Ah, I did misunderstand you.  For both:

Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

							Thanx, Paul


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

* [PATCH 0/3] fget*() cleanups
  2014-01-11 22:27             ` [PATCH v2 0/2] rcu_dereference_check_fdtable fix/cleanups Paul E. McKenney
@ 2014-01-13 15:47               ` Oleg Nesterov
  2014-01-13 15:48                 ` [PATCH 1/3] fs: factor out common code in fget() and fget_raw() Oleg Nesterov
                                   ` (3 more replies)
  0 siblings, 4 replies; 20+ messages in thread
From: Oleg Nesterov @ 2014-01-13 15:47 UTC (permalink / raw)
  To: Paul E. McKenney, Al Viro, Andrew Morton
  Cc: Dipankar Sarma, Eric Dumazet, linux-kernel

On 01/11, Paul E. McKenney wrote:
>
> On Sat, Jan 11, 2014 at 07:19:08PM +0100, Oleg Nesterov wrote:
> >
> > It seems that you misunderstood me, let me send v2 for review.
>
> Ah, I did misunderstand you.  For both:
>
> Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

Thanks!

While at it, can't we factor out the code in fget*() ?

Probably I dislike the code duplications too much, but imho fget*()
abuse the copy-and-paste.

On top of this series, saves 600 bytes.

Oleg.

 fs/file.c |   70 ++++++++++++++++--------------------------------------------
 1 files changed, 19 insertions(+), 51 deletions(-)


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

* [PATCH 1/3] fs: factor out common code in fget() and fget_raw()
  2014-01-13 15:47               ` [PATCH 0/3] fget*() cleanups Oleg Nesterov
@ 2014-01-13 15:48                 ` Oleg Nesterov
  2014-01-13 23:29                   ` Paul E. McKenney
  2014-01-13 15:48                 ` [PATCH 2/3] fs: factor out common code in fget_light() and fget_raw_light() Oleg Nesterov
                                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 20+ messages in thread
From: Oleg Nesterov @ 2014-01-13 15:48 UTC (permalink / raw)
  To: Paul E. McKenney, Al Viro, Andrew Morton
  Cc: Dipankar Sarma, Eric Dumazet, linux-kernel

Apart from FMODE_PATH check fget() and fget_raw() are identical,
shift the code into the new simple helper, __fget(fd, mask). Saves
160 bytes.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 fs/file.c |   25 ++++++++-----------------
 1 files changed, 8 insertions(+), 17 deletions(-)

diff --git a/fs/file.c b/fs/file.c
index d34e59e..4ed58a3 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -637,16 +637,16 @@ void do_close_on_exec(struct files_struct *files)
 	spin_unlock(&files->file_lock);
 }
 
-struct file *fget(unsigned int fd)
+static struct file *__fget(unsigned int fd, fmode_t mask)
 {
-	struct file *file;
 	struct files_struct *files = current->files;
+	struct file *file;
 
 	rcu_read_lock();
 	file = fcheck_files(files, fd);
 	if (file) {
 		/* File object ref couldn't be taken */
-		if (file->f_mode & FMODE_PATH ||
+		if ((file->f_mode & mask) ||
 		    !atomic_long_inc_not_zero(&file->f_count))
 			file = NULL;
 	}
@@ -655,25 +655,16 @@ struct file *fget(unsigned int fd)
 	return file;
 }
 
+struct file *fget(unsigned int fd)
+{
+	return __fget(fd, FMODE_PATH);
+}
 EXPORT_SYMBOL(fget);
 
 struct file *fget_raw(unsigned int fd)
 {
-	struct file *file;
-	struct files_struct *files = current->files;
-
-	rcu_read_lock();
-	file = fcheck_files(files, fd);
-	if (file) {
-		/* File object ref couldn't be taken */
-		if (!atomic_long_inc_not_zero(&file->f_count))
-			file = NULL;
-	}
-	rcu_read_unlock();
-
-	return file;
+	return __fget(fd, 0);
 }
-
 EXPORT_SYMBOL(fget_raw);
 
 /*
-- 
1.5.5.1



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

* [PATCH 2/3] fs: factor out common code in fget_light() and fget_raw_light()
  2014-01-13 15:47               ` [PATCH 0/3] fget*() cleanups Oleg Nesterov
  2014-01-13 15:48                 ` [PATCH 1/3] fs: factor out common code in fget() and fget_raw() Oleg Nesterov
@ 2014-01-13 15:48                 ` Oleg Nesterov
  2014-01-13 23:32                   ` Paul E. McKenney
  2014-01-13 15:49                 ` [PATCH 3/3] fs: __fget_light() can use __fget() in slow path Oleg Nesterov
  2014-01-13 23:45                 ` [PATCH 0/3] fget*() cleanups Al Viro
  3 siblings, 1 reply; 20+ messages in thread
From: Oleg Nesterov @ 2014-01-13 15:48 UTC (permalink / raw)
  To: Paul E. McKenney, Al Viro, Andrew Morton
  Cc: Dipankar Sarma, Eric Dumazet, linux-kernel

Apart from FMODE_PATH check fget_light() and fget_raw_light() are
identical, shift the code into the new helper, __fget_light(fd, mask).
Saves 208 bytes.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 fs/file.c |   33 +++++++++------------------------
 1 files changed, 9 insertions(+), 24 deletions(-)

diff --git a/fs/file.c b/fs/file.c
index 4ed58a3..50c1208 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -683,21 +683,21 @@ EXPORT_SYMBOL(fget_raw);
  * The fput_needed flag returned by fget_light should be passed to the
  * corresponding fput_light.
  */
-struct file *fget_light(unsigned int fd, int *fput_needed)
+struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed)
 {
-	struct file *file;
 	struct files_struct *files = current->files;
+	struct file *file;
 
 	*fput_needed = 0;
 	if (atomic_read(&files->count) == 1) {
 		file = __fcheck_files(files, fd);
-		if (file && (file->f_mode & FMODE_PATH))
+		if (file && (file->f_mode & mask))
 			file = NULL;
 	} else {
 		rcu_read_lock();
 		file = fcheck_files(files, fd);
 		if (file) {
-			if (!(file->f_mode & FMODE_PATH) &&
+			if (!(file->f_mode & mask) &&
 			    atomic_long_inc_not_zero(&file->f_count))
 				*fput_needed = 1;
 			else
@@ -709,30 +709,15 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
 
 	return file;
 }
+struct file *fget_light(unsigned int fd, int *fput_needed)
+{
+	return __fget_light(fd, FMODE_PATH, fput_needed);
+}
 EXPORT_SYMBOL(fget_light);
 
 struct file *fget_raw_light(unsigned int fd, int *fput_needed)
 {
-	struct file *file;
-	struct files_struct *files = current->files;
-
-	*fput_needed = 0;
-	if (atomic_read(&files->count) == 1) {
-		file = __fcheck_files(files, fd);
-	} else {
-		rcu_read_lock();
-		file = fcheck_files(files, fd);
-		if (file) {
-			if (atomic_long_inc_not_zero(&file->f_count))
-				*fput_needed = 1;
-			else
-				/* Didn't get the reference, someone's freed */
-				file = NULL;
-		}
-		rcu_read_unlock();
-	}
-
-	return file;
+	return __fget_light(fd, 0, fput_needed);
 }
 
 void set_close_on_exec(unsigned int fd, int flag)
-- 
1.5.5.1



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

* [PATCH 3/3] fs: __fget_light() can use __fget() in slow path
  2014-01-13 15:47               ` [PATCH 0/3] fget*() cleanups Oleg Nesterov
  2014-01-13 15:48                 ` [PATCH 1/3] fs: factor out common code in fget() and fget_raw() Oleg Nesterov
  2014-01-13 15:48                 ` [PATCH 2/3] fs: factor out common code in fget_light() and fget_raw_light() Oleg Nesterov
@ 2014-01-13 15:49                 ` Oleg Nesterov
  2014-01-13 23:37                   ` Paul E. McKenney
  2014-01-13 23:45                 ` [PATCH 0/3] fget*() cleanups Al Viro
  3 siblings, 1 reply; 20+ messages in thread
From: Oleg Nesterov @ 2014-01-13 15:49 UTC (permalink / raw)
  To: Paul E. McKenney, Al Viro, Andrew Morton
  Cc: Dipankar Sarma, Eric Dumazet, linux-kernel

The slow path in __fget_light() can use __fget() to avoid the
code duplication. Saves 232 bytes.

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

diff --git a/fs/file.c b/fs/file.c
index 50c1208..771578b 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -694,17 +694,9 @@ struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed)
 		if (file && (file->f_mode & mask))
 			file = NULL;
 	} else {
-		rcu_read_lock();
-		file = fcheck_files(files, fd);
-		if (file) {
-			if (!(file->f_mode & mask) &&
-			    atomic_long_inc_not_zero(&file->f_count))
-				*fput_needed = 1;
-			else
-				/* Didn't get the reference, someone's freed */
-				file = NULL;
-		}
-		rcu_read_unlock();
+		file = __fget(fd, mask);
+		if (file)
+			*fput_needed = 1;
 	}
 
 	return file;
-- 
1.5.5.1



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

* Re: [PATCH 1/3] fs: factor out common code in fget() and fget_raw()
  2014-01-13 15:48                 ` [PATCH 1/3] fs: factor out common code in fget() and fget_raw() Oleg Nesterov
@ 2014-01-13 23:29                   ` Paul E. McKenney
  0 siblings, 0 replies; 20+ messages in thread
From: Paul E. McKenney @ 2014-01-13 23:29 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Al Viro, Andrew Morton, Dipankar Sarma, Eric Dumazet, linux-kernel

On Mon, Jan 13, 2014 at 04:48:19PM +0100, Oleg Nesterov wrote:
> Apart from FMODE_PATH check fget() and fget_raw() are identical,
> shift the code into the new simple helper, __fget(fd, mask). Saves
> 160 bytes.
> 
> Signed-off-by: Oleg Nesterov <oleg@redhat.com>

Not sure why local variable "file" was moved, but regardless:

Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

> ---
>  fs/file.c |   25 ++++++++-----------------
>  1 files changed, 8 insertions(+), 17 deletions(-)
> 
> diff --git a/fs/file.c b/fs/file.c
> index d34e59e..4ed58a3 100644
> --- a/fs/file.c
> +++ b/fs/file.c
> @@ -637,16 +637,16 @@ void do_close_on_exec(struct files_struct *files)
>  	spin_unlock(&files->file_lock);
>  }
> 
> -struct file *fget(unsigned int fd)
> +static struct file *__fget(unsigned int fd, fmode_t mask)
>  {
> -	struct file *file;
>  	struct files_struct *files = current->files;
> +	struct file *file;
> 
>  	rcu_read_lock();
>  	file = fcheck_files(files, fd);
>  	if (file) {
>  		/* File object ref couldn't be taken */
> -		if (file->f_mode & FMODE_PATH ||
> +		if ((file->f_mode & mask) ||
>  		    !atomic_long_inc_not_zero(&file->f_count))
>  			file = NULL;
>  	}
> @@ -655,25 +655,16 @@ struct file *fget(unsigned int fd)
>  	return file;
>  }
> 
> +struct file *fget(unsigned int fd)
> +{
> +	return __fget(fd, FMODE_PATH);
> +}
>  EXPORT_SYMBOL(fget);
> 
>  struct file *fget_raw(unsigned int fd)
>  {
> -	struct file *file;
> -	struct files_struct *files = current->files;
> -
> -	rcu_read_lock();
> -	file = fcheck_files(files, fd);
> -	if (file) {
> -		/* File object ref couldn't be taken */
> -		if (!atomic_long_inc_not_zero(&file->f_count))
> -			file = NULL;
> -	}
> -	rcu_read_unlock();
> -
> -	return file;
> +	return __fget(fd, 0);
>  }
> -
>  EXPORT_SYMBOL(fget_raw);
> 
>  /*
> -- 
> 1.5.5.1
> 
> 


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

* Re: [PATCH 2/3] fs: factor out common code in fget_light() and fget_raw_light()
  2014-01-13 15:48                 ` [PATCH 2/3] fs: factor out common code in fget_light() and fget_raw_light() Oleg Nesterov
@ 2014-01-13 23:32                   ` Paul E. McKenney
  0 siblings, 0 replies; 20+ messages in thread
From: Paul E. McKenney @ 2014-01-13 23:32 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Al Viro, Andrew Morton, Dipankar Sarma, Eric Dumazet, linux-kernel

On Mon, Jan 13, 2014 at 04:48:40PM +0100, Oleg Nesterov wrote:
> Apart from FMODE_PATH check fget_light() and fget_raw_light() are
> identical, shift the code into the new helper, __fget_light(fd, mask).
> Saves 208 bytes.
> 
> Signed-off-by: Oleg Nesterov <oleg@redhat.com>

Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

> ---
>  fs/file.c |   33 +++++++++------------------------
>  1 files changed, 9 insertions(+), 24 deletions(-)
> 
> diff --git a/fs/file.c b/fs/file.c
> index 4ed58a3..50c1208 100644
> --- a/fs/file.c
> +++ b/fs/file.c
> @@ -683,21 +683,21 @@ EXPORT_SYMBOL(fget_raw);
>   * The fput_needed flag returned by fget_light should be passed to the
>   * corresponding fput_light.
>   */
> -struct file *fget_light(unsigned int fd, int *fput_needed)
> +struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed)
>  {
> -	struct file *file;
>  	struct files_struct *files = current->files;
> +	struct file *file;
> 
>  	*fput_needed = 0;
>  	if (atomic_read(&files->count) == 1) {
>  		file = __fcheck_files(files, fd);
> -		if (file && (file->f_mode & FMODE_PATH))
> +		if (file && (file->f_mode & mask))
>  			file = NULL;
>  	} else {
>  		rcu_read_lock();
>  		file = fcheck_files(files, fd);
>  		if (file) {
> -			if (!(file->f_mode & FMODE_PATH) &&
> +			if (!(file->f_mode & mask) &&
>  			    atomic_long_inc_not_zero(&file->f_count))
>  				*fput_needed = 1;
>  			else
> @@ -709,30 +709,15 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
> 
>  	return file;
>  }
> +struct file *fget_light(unsigned int fd, int *fput_needed)
> +{
> +	return __fget_light(fd, FMODE_PATH, fput_needed);
> +}
>  EXPORT_SYMBOL(fget_light);
> 
>  struct file *fget_raw_light(unsigned int fd, int *fput_needed)
>  {
> -	struct file *file;
> -	struct files_struct *files = current->files;
> -
> -	*fput_needed = 0;
> -	if (atomic_read(&files->count) == 1) {
> -		file = __fcheck_files(files, fd);
> -	} else {
> -		rcu_read_lock();
> -		file = fcheck_files(files, fd);
> -		if (file) {
> -			if (atomic_long_inc_not_zero(&file->f_count))
> -				*fput_needed = 1;
> -			else
> -				/* Didn't get the reference, someone's freed */
> -				file = NULL;
> -		}
> -		rcu_read_unlock();
> -	}
> -
> -	return file;
> +	return __fget_light(fd, 0, fput_needed);
>  }
> 
>  void set_close_on_exec(unsigned int fd, int flag)
> -- 
> 1.5.5.1
> 
> 


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

* Re: [PATCH 3/3] fs: __fget_light() can use __fget() in slow path
  2014-01-13 15:49                 ` [PATCH 3/3] fs: __fget_light() can use __fget() in slow path Oleg Nesterov
@ 2014-01-13 23:37                   ` Paul E. McKenney
  0 siblings, 0 replies; 20+ messages in thread
From: Paul E. McKenney @ 2014-01-13 23:37 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Al Viro, Andrew Morton, Dipankar Sarma, Eric Dumazet, linux-kernel

On Mon, Jan 13, 2014 at 04:49:06PM +0100, Oleg Nesterov wrote:
> The slow path in __fget_light() can use __fget() to avoid the
> code duplication. Saves 232 bytes.
> 
> Signed-off-by: Oleg Nesterov <oleg@redhat.com>

Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

> ---
>  fs/file.c |   14 +++-----------
>  1 files changed, 3 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/file.c b/fs/file.c
> index 50c1208..771578b 100644
> --- a/fs/file.c
> +++ b/fs/file.c
> @@ -694,17 +694,9 @@ struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed)
>  		if (file && (file->f_mode & mask))
>  			file = NULL;
>  	} else {
> -		rcu_read_lock();
> -		file = fcheck_files(files, fd);
> -		if (file) {
> -			if (!(file->f_mode & mask) &&
> -			    atomic_long_inc_not_zero(&file->f_count))
> -				*fput_needed = 1;
> -			else
> -				/* Didn't get the reference, someone's freed */
> -				file = NULL;
> -		}
> -		rcu_read_unlock();
> +		file = __fget(fd, mask);
> +		if (file)
> +			*fput_needed = 1;
>  	}
> 
>  	return file;
> -- 
> 1.5.5.1
> 
> 


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

* Re: [PATCH 0/3] fget*() cleanups
  2014-01-13 15:47               ` [PATCH 0/3] fget*() cleanups Oleg Nesterov
                                   ` (2 preceding siblings ...)
  2014-01-13 15:49                 ` [PATCH 3/3] fs: __fget_light() can use __fget() in slow path Oleg Nesterov
@ 2014-01-13 23:45                 ` Al Viro
  3 siblings, 0 replies; 20+ messages in thread
From: Al Viro @ 2014-01-13 23:45 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Paul E. McKenney, Andrew Morton, Dipankar Sarma, Eric Dumazet,
	linux-kernel

On Mon, Jan 13, 2014 at 04:47:48PM +0100, Oleg Nesterov wrote:
> On 01/11, Paul E. McKenney wrote:
> >
> > On Sat, Jan 11, 2014 at 07:19:08PM +0100, Oleg Nesterov wrote:
> > >
> > > It seems that you misunderstood me, let me send v2 for review.
> >
> > Ah, I did misunderstand you.  For both:
> >
> > Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> 
> Thanks!
> 
> While at it, can't we factor out the code in fget*() ?
> 
> Probably I dislike the code duplications too much, but imho fget*()
> abuse the copy-and-paste.
> 
> On top of this series, saves 600 bytes.

Applied, along with fcheck_files() stuff.  Sorry about late reply, I'm
digging through huge piles of mail and putting a queue for -next right
now...

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

end of thread, other threads:[~2014-01-13 23:45 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-07 18:12 [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups Oleg Nesterov
2014-01-07 18:13 ` [PATCH 1/2] introduce __fcheck_files() to fix rcu_dereference_check_fdtable(), kill rcu_my_thread_group_empty() Oleg Nesterov
2014-01-07 18:13 ` [PATCH 2/2] change close_files() to use rcu_lock_acquire() to shut up RCU-lockdep Oleg Nesterov
2014-01-08 13:28 ` [PATCH 0/2] rcu_dereference_check_fdtable fix/cleanups Paul E. McKenney
2014-01-08 15:19   ` Oleg Nesterov
2014-01-09  1:16     ` Paul E. McKenney
2014-01-10 15:34       ` Oleg Nesterov
2014-01-11  6:34         ` Paul E. McKenney
2014-01-11 18:19           ` [PATCH v2 " Oleg Nesterov
2014-01-11 18:19             ` [PATCH v2 1/2] introduce __fcheck_files() to fix rcu_dereference_check_fdtable(), kill rcu_my_thread_group_empty() Oleg Nesterov
2014-01-11 18:19             ` [PATCH v2 2/2] change close_files() to use rcu_dereference_raw(files->fdt) Oleg Nesterov
2014-01-11 22:27             ` [PATCH v2 0/2] rcu_dereference_check_fdtable fix/cleanups Paul E. McKenney
2014-01-13 15:47               ` [PATCH 0/3] fget*() cleanups Oleg Nesterov
2014-01-13 15:48                 ` [PATCH 1/3] fs: factor out common code in fget() and fget_raw() Oleg Nesterov
2014-01-13 23:29                   ` Paul E. McKenney
2014-01-13 15:48                 ` [PATCH 2/3] fs: factor out common code in fget_light() and fget_raw_light() Oleg Nesterov
2014-01-13 23:32                   ` Paul E. McKenney
2014-01-13 15:49                 ` [PATCH 3/3] fs: __fget_light() can use __fget() in slow path Oleg Nesterov
2014-01-13 23:37                   ` Paul E. McKenney
2014-01-13 23:45                 ` [PATCH 0/3] fget*() cleanups Al Viro

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.