* [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
* 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
* [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
* 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
* [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 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.