Skip to content

Commit c2c54b5

Browse files
committed
ovl: do not open non-data lower file for fsync
ovl_fsync() with !datasync opens a backing file from the top most dentry in the stack, checks if this dentry is non-upper and skips the fsync. In case of an overlay dentry stack with lower data and lower metadata above it, but without an upper metadata above it, the backing file is opened from the top most lower metadata dentry and never used. Refactor the helper ovl_real_fdget_meta() into ovl_real_fdget_path() and open code the checks for non-upper inode in ovl_fsync(), so in that case we can avoid the unneeded backing file open. Signed-off-by: Amir Goldstein <amir73il@gmail.com>
1 parent c5b28fc commit c2c54b5

File tree

1 file changed

+31
-27
lines changed

1 file changed

+31
-27
lines changed

fs/overlayfs/file.c

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -89,32 +89,19 @@ static int ovl_change_flags(struct file *file, unsigned int flags)
8989
return 0;
9090
}
9191

92-
static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
93-
bool allow_meta)
92+
static int ovl_real_fdget_path(const struct file *file, struct fd *real,
93+
struct path *realpath)
9494
{
95-
struct dentry *dentry = file_dentry(file);
9695
struct file *realfile = file->private_data;
97-
struct path realpath;
98-
int err;
9996

10097
real->word = (unsigned long)realfile;
10198

102-
if (allow_meta) {
103-
ovl_path_real(dentry, &realpath);
104-
} else {
105-
/* lazy lookup and verify of lowerdata */
106-
err = ovl_verify_lowerdata(dentry);
107-
if (err)
108-
return err;
109-
110-
ovl_path_realdata(dentry, &realpath);
111-
}
112-
if (!realpath.dentry)
99+
if (WARN_ON_ONCE(!realpath->dentry))
113100
return -EIO;
114101

115102
/* Has it been copied up since we'd opened it? */
116-
if (unlikely(file_inode(realfile) != d_inode(realpath.dentry))) {
117-
struct file *f = ovl_open_realfile(file, &realpath);
103+
if (unlikely(file_inode(realfile) != d_inode(realpath->dentry))) {
104+
struct file *f = ovl_open_realfile(file, realpath);
118105
if (IS_ERR(f))
119106
return PTR_ERR(f);
120107
real->word = (unsigned long)f | FDPUT_FPUT;
@@ -130,15 +117,26 @@ static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
130117

131118
static int ovl_real_fdget(const struct file *file, struct fd *real)
132119
{
133-
if (d_is_dir(file_dentry(file))) {
120+
struct dentry *dentry = file_dentry(file);
121+
struct path realpath;
122+
int err;
123+
124+
if (d_is_dir(dentry)) {
134125
struct file *f = ovl_dir_real_file(file, false);
135126
if (IS_ERR(f))
136127
return PTR_ERR(f);
137128
real->word = (unsigned long)f;
138129
return 0;
139130
}
140131

141-
return ovl_real_fdget_meta(file, real, false);
132+
/* lazy lookup and verify of lowerdata */
133+
err = ovl_verify_lowerdata(dentry);
134+
if (err)
135+
return err;
136+
137+
ovl_path_realdata(dentry, &realpath);
138+
139+
return ovl_real_fdget_path(file, real, &realpath);
142140
}
143141

144142
static int ovl_open(struct inode *inode, struct file *file)
@@ -396,6 +394,9 @@ static ssize_t ovl_splice_write(struct pipe_inode_info *pipe, struct file *out,
396394

397395
static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
398396
{
397+
struct dentry *dentry = file_dentry(file);
398+
enum ovl_path_type type;
399+
struct path upperpath;
399400
struct fd real;
400401
const struct cred *old_cred;
401402
int ret;
@@ -404,16 +405,19 @@ static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
404405
if (ret <= 0)
405406
return ret;
406407

407-
ret = ovl_real_fdget_meta(file, &real, !datasync);
408+
/* Don't sync lower file for fear of receiving EROFS error */
409+
type = ovl_path_type(dentry);
410+
if (!OVL_TYPE_UPPER(type) || (datasync && OVL_TYPE_MERGE(type)))
411+
return 0;
412+
413+
ovl_path_upper(dentry, &upperpath);
414+
ret = ovl_real_fdget_path(file, &real, &upperpath);
408415
if (ret)
409416
return ret;
410417

411-
/* Don't sync lower file for fear of receiving EROFS error */
412-
if (file_inode(fd_file(real)) == ovl_inode_upper(file_inode(file))) {
413-
old_cred = ovl_override_creds(file_inode(file)->i_sb);
414-
ret = vfs_fsync_range(fd_file(real), start, end, datasync);
415-
ovl_revert_creds(old_cred);
416-
}
418+
old_cred = ovl_override_creds(file_inode(file)->i_sb);
419+
ret = vfs_fsync_range(fd_file(real), start, end, datasync);
420+
ovl_revert_creds(old_cred);
417421

418422
fdput(real);
419423

0 commit comments

Comments
 (0)