5.10-stable review patch. If anyone has any objections, please let me know. ------------------ From: Chuck Lever <chuck.lever@xxxxxxxxxx> Temporarily revert commit 0849f83e4782 ("fget: clarify and improve __fget_files() implementation") to enable subsequent upstream commits to apply and build cleanly. Stable-dep-of: bebf684bf330 ("file: Rename __fcheck_files to files_lookup_fd_raw") Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> --- fs/file.c | 72 +++++++++++++------------------------------------------ 1 file changed, 16 insertions(+), 56 deletions(-) diff --git a/fs/file.c b/fs/file.c index 5065252bb474e..fea693acc065e 100644 --- a/fs/file.c +++ b/fs/file.c @@ -849,68 +849,28 @@ void do_close_on_exec(struct files_struct *files) spin_unlock(&files->file_lock); } -static inline struct file *__fget_files_rcu(struct files_struct *files, - unsigned int fd, fmode_t mask, unsigned int refs) -{ - for (;;) { - struct file *file; - struct fdtable *fdt = rcu_dereference_raw(files->fdt); - struct file __rcu **fdentry; - - if (unlikely(fd >= fdt->max_fds)) - return NULL; - - fdentry = fdt->fd + array_index_nospec(fd, fdt->max_fds); - file = rcu_dereference_raw(*fdentry); - if (unlikely(!file)) - return NULL; - - if (unlikely(file->f_mode & mask)) - return NULL; - - /* - * Ok, we have a file pointer. However, because we do - * this all locklessly under RCU, we may be racing with - * that file being closed. - * - * Such a race can take two forms: - * - * (a) the file ref already went down to zero, - * and get_file_rcu_many() fails. Just try - * again: - */ - if (unlikely(!get_file_rcu_many(file, refs))) - continue; - - /* - * (b) the file table entry has changed under us. - * Note that we don't need to re-check the 'fdt->fd' - * pointer having changed, because it always goes - * hand-in-hand with 'fdt'. - * - * If so, we need to put our refs and try again. - */ - if (unlikely(rcu_dereference_raw(files->fdt) != fdt) || - unlikely(rcu_dereference_raw(*fdentry) != file)) { - fput_many(file, refs); - continue; - } - - /* - * Ok, we have a ref to the file, and checked that it - * still exists. - */ - return file; - } -} - static struct file *__fget_files(struct files_struct *files, unsigned int fd, fmode_t mask, unsigned int refs) { struct file *file; rcu_read_lock(); - file = __fget_files_rcu(files, fd, mask, refs); +loop: + file = fcheck_files(files, fd); + if (file) { + /* File object ref couldn't be taken. + * dup2() atomicity guarantee is the reason + * we loop to catch the new file (or NULL pointer) + */ + if (file->f_mode & mask) + file = NULL; + else if (!get_file_rcu_many(file, refs)) + goto loop; + else if (__fcheck_files(files, fd) != file) { + fput_many(file, refs); + goto loop; + } + } rcu_read_unlock(); return file; -- 2.43.0