overlayfs: don't hold ->i_mutex over opening the real directory
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 24 Oct 2014 02:56:05 +0000 (22:56 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 25 Oct 2014 00:24:11 +0000 (20:24 -0400)
just use it to serialize the assignment

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/overlayfs/readdir.c

index c6787f84ece940b649c4069cc302a06d322207be..b7d9fb098840146a0b6cae033aab56092d1b767f 100644 (file)
@@ -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);