diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-10-24 06:56:05 +0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-10-25 04:24:11 +0400 |
commit | 3d268c9b136f51385f9d041f3f2424501b257388 (patch) | |
tree | f2dcbda16c82c4215ccf104915e9541e1c785b85 /fs | |
parent | 1be47b387a717a1d3edf29c80b6e7f3a72ab236e (diff) | |
download | linux-3d268c9b136f51385f9d041f3f2424501b257388.tar.xz |
overlayfs: don't hold ->i_mutex over opening the real directory
just use it to serialize the assignment
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/overlayfs/readdir.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index c6787f84ece9..b7d9fb098840 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -458,20 +458,27 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) { struct inode *inode = file_inode(file); - mutex_lock(&inode->i_mutex); realfile = od->upperfile; if (!realfile) { struct path upperpath; ovl_path_upper(dentry, &upperpath); realfile = ovl_path_open(&upperpath, O_RDONLY); - if (IS_ERR(realfile)) { - mutex_unlock(&inode->i_mutex); - return PTR_ERR(realfile); + mutex_lock(&inode->i_mutex); + if (!od->upperfile) { + if (IS_ERR(realfile)) { + mutex_unlock(&inode->i_mutex); + return PTR_ERR(realfile); + } + od->upperfile = realfile; + } else { + /* somebody has beaten us to it */ + if (!IS_ERR(realfile)) + fput(realfile); + realfile = od->upperfile; } - od->upperfile = realfile; + mutex_unlock(&inode->i_mutex); } - mutex_unlock(&inode->i_mutex); } return vfs_fsync_range(realfile, start, end, datasync); |