fs: get mnt_writers count for an open backing file's real path
authorAmir Goldstein <amir73il@gmail.com>
Mon, 9 Oct 2023 15:37:10 +0000 (18:37 +0300)
committerChristian Brauner <brauner@kernel.org>
Thu, 19 Oct 2023 09:03:15 +0000 (11:03 +0200)
A writeable mapped backing file can perform writes to the real inode.
Therefore, the real path mount must be kept writable so long as the
writable map exists.

This may not be strictly needed for ovelrayfs private upper mount,
but it is correct to take the mnt_writers count in the vfs helper.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Link: https://lore.kernel.org/r/20231009153712.1566422-2-amir73il@gmail.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/internal.h
fs/open.c

index f08d8fe3ae5e81d4252087d5553ae309a4136761..4e93a685bdaa6e88e4f8d6f0e4b2b5d082a5148c 100644 (file)
@@ -96,13 +96,20 @@ struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred);
 struct file *alloc_empty_backing_file(int flags, const struct cred *cred);
 void release_empty_file(struct file *f);
 
+static inline void file_put_write_access(struct file *file)
+{
+       put_write_access(file->f_inode);
+       mnt_put_write_access(file->f_path.mnt);
+       if (unlikely(file->f_mode & FMODE_BACKING))
+               mnt_put_write_access(backing_file_real_path(file)->mnt);
+}
+
 static inline void put_file_access(struct file *file)
 {
        if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
                i_readcount_dec(file->f_inode);
        } else if (file->f_mode & FMODE_WRITER) {
-               put_write_access(file->f_inode);
-               mnt_put_write_access(file->f_path.mnt);
+               file_put_write_access(file);
        }
 }
 
index a65ce47810cfc033e21d71836288633a44772ff0..fe63e236da2225e1ac4579d8b5b41dea06cd51a3 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -870,6 +870,30 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
        return ksys_fchown(fd, user, group);
 }
 
+static inline int file_get_write_access(struct file *f)
+{
+       int error;
+
+       error = get_write_access(f->f_inode);
+       if (unlikely(error))
+               return error;
+       error = mnt_get_write_access(f->f_path.mnt);
+       if (unlikely(error))
+               goto cleanup_inode;
+       if (unlikely(f->f_mode & FMODE_BACKING)) {
+               error = mnt_get_write_access(backing_file_real_path(f)->mnt);
+               if (unlikely(error))
+                       goto cleanup_mnt;
+       }
+       return 0;
+
+cleanup_mnt:
+       mnt_put_write_access(f->f_path.mnt);
+cleanup_inode:
+       put_write_access(f->f_inode);
+       return error;
+}
+
 static int do_dentry_open(struct file *f,
                          struct inode *inode,
                          int (*open)(struct inode *, struct file *))
@@ -892,14 +916,9 @@ static int do_dentry_open(struct file *f,
        if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
                i_readcount_inc(inode);
        } else if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) {
-               error = get_write_access(inode);
+               error = file_get_write_access(f);
                if (unlikely(error))
                        goto cleanup_file;
-               error = mnt_get_write_access(f->f_path.mnt);
-               if (unlikely(error)) {
-                       put_write_access(inode);
-                       goto cleanup_file;
-               }
                f->f_mode |= FMODE_WRITER;
        }