]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Revert "fget: clarify and improve __fget_files() implementation"
authorChuck Lever <chuck.lever@oracle.com>
Thu, 29 Feb 2024 23:19:36 +0000 (18:19 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 21 Jun 2024 12:52:47 +0000 (14:52 +0200)
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@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/file.c

index 5065252bb474e4a1ffac77a71bd0bb66dda685c8..fea693acc065eb7e8cae518c30285e74cd18fcc1 100644 (file)
--- 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;