fs: get mnt_writers count for an open backing file's real path

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>
This commit is contained in:
Amir Goldstein 2023-10-09 18:37:10 +03:00 committed by Christian Brauner
parent 6c4d1c99d2
commit 83bc1d2941
No known key found for this signature in database
GPG key ID: 91C61BC06578DCA2
2 changed files with 34 additions and 8 deletions

View 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); struct file *alloc_empty_backing_file(int flags, const struct cred *cred);
void release_empty_file(struct file *f); 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) static inline void put_file_access(struct file *file)
{ {
if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
i_readcount_dec(file->f_inode); i_readcount_dec(file->f_inode);
} else if (file->f_mode & FMODE_WRITER) { } else if (file->f_mode & FMODE_WRITER) {
put_write_access(file->f_inode); file_put_write_access(file);
mnt_put_write_access(file->f_path.mnt);
} }
} }

View file

@ -870,6 +870,30 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
return ksys_fchown(fd, user, 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, static int do_dentry_open(struct file *f,
struct inode *inode, struct inode *inode,
int (*open)(struct inode *, struct file *)) 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) { if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
i_readcount_inc(inode); i_readcount_inc(inode);
} else if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) { } 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)) if (unlikely(error))
goto cleanup_file; 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; f->f_mode |= FMODE_WRITER;
} }