]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
fuse: fix initial parallel dirops
authorMiklos Szeredi <mszeredi@redhat.com>
Thu, 26 Jul 2018 14:13:11 +0000 (16:13 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Thu, 26 Jul 2018 14:13:11 +0000 (16:13 +0200)
If parallel dirops are enabled in FUSE_INIT reply, then first operation may
leave fi->mutex held.

Reported-by: syzbot <syzbot+3f7b29af1baa9d0a55be@syzkaller.appspotmail.com>
Fixes: 5c672ab3f0ee ("fuse: serialize dirops by default")
Cc: <stable@vger.kernel.org> # v4.7
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/dir.c
fs/fuse/fuse_i.h
fs/fuse/inode.c

index 56231b31f806b10a15d86006b0686312b5be2cb2..606909ed5f2141bf93d8acaa518e594f9c610b64 100644 (file)
@@ -355,11 +355,12 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
        struct inode *inode;
        struct dentry *newent;
        bool outarg_valid = true;
+       bool locked;
 
-       fuse_lock_inode(dir);
+       locked = fuse_lock_inode(dir);
        err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
                               &outarg, &inode);
-       fuse_unlock_inode(dir);
+       fuse_unlock_inode(dir, locked);
        if (err == -ENOENT) {
                outarg_valid = false;
                err = 0;
@@ -1340,6 +1341,7 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx)
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_req *req;
        u64 attr_version = 0;
+       bool locked;
 
        if (is_bad_inode(inode))
                return -EIO;
@@ -1367,9 +1369,9 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx)
                fuse_read_fill(req, file, ctx->pos, PAGE_SIZE,
                               FUSE_READDIR);
        }
-       fuse_lock_inode(inode);
+       locked = fuse_lock_inode(inode);
        fuse_request_send(fc, req);
-       fuse_unlock_inode(inode);
+       fuse_unlock_inode(inode, locked);
        nbytes = req->out.args[0].size;
        err = req->out.h.error;
        fuse_put_request(fc, req);
index 582b1756a01133b02129ef8fadf01186a25f20c7..f78e9614bb5f712d2936bffa2fa886c7027ba7c1 100644 (file)
@@ -975,8 +975,8 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
 
 void fuse_set_initialized(struct fuse_conn *fc);
 
-void fuse_unlock_inode(struct inode *inode);
-void fuse_lock_inode(struct inode *inode);
+void fuse_unlock_inode(struct inode *inode, bool locked);
+bool fuse_lock_inode(struct inode *inode);
 
 int fuse_setxattr(struct inode *inode, const char *name, const void *value,
                  size_t size, int flags);
index 0115c2f0a4281e7c1f380fa5598439d11d80a432..2dbd487390a34824b52c5ffa9e99163c119c5ecf 100644 (file)
@@ -357,15 +357,21 @@ int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
        return 0;
 }
 
-void fuse_lock_inode(struct inode *inode)
+bool fuse_lock_inode(struct inode *inode)
 {
-       if (!get_fuse_conn(inode)->parallel_dirops)
+       bool locked = false;
+
+       if (!get_fuse_conn(inode)->parallel_dirops) {
                mutex_lock(&get_fuse_inode(inode)->mutex);
+               locked = true;
+       }
+
+       return locked;
 }
 
-void fuse_unlock_inode(struct inode *inode)
+void fuse_unlock_inode(struct inode *inode, bool locked)
 {
-       if (!get_fuse_conn(inode)->parallel_dirops)
+       if (locked)
                mutex_unlock(&get_fuse_inode(inode)->mutex);
 }