Commit 63576c13 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

fuse: fix initial parallel dirops



If parallel dirops are enabled in FUSE_INIT reply, then first operation may
leave fi->mutex held.
Reported-by: default avatarsyzbot <syzbot+3f7b29af1baa9d0a55be@syzkaller.appspotmail.com>
Fixes: 5c672ab3

 ("fuse: serialize dirops by default")
Cc: <stable@vger.kernel.org> # v4.7
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent e8f3bd77
...@@ -355,11 +355,12 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, ...@@ -355,11 +355,12 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
struct inode *inode; struct inode *inode;
struct dentry *newent; struct dentry *newent;
bool outarg_valid = true; 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, err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
&outarg, &inode); &outarg, &inode);
fuse_unlock_inode(dir); fuse_unlock_inode(dir, locked);
if (err == -ENOENT) { if (err == -ENOENT) {
outarg_valid = false; outarg_valid = false;
err = 0; err = 0;
...@@ -1340,6 +1341,7 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx) ...@@ -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_conn *fc = get_fuse_conn(inode);
struct fuse_req *req; struct fuse_req *req;
u64 attr_version = 0; u64 attr_version = 0;
bool locked;
if (is_bad_inode(inode)) if (is_bad_inode(inode))
return -EIO; return -EIO;
...@@ -1367,9 +1369,9 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx) ...@@ -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_read_fill(req, file, ctx->pos, PAGE_SIZE,
FUSE_READDIR); FUSE_READDIR);
} }
fuse_lock_inode(inode); locked = fuse_lock_inode(inode);
fuse_request_send(fc, req); fuse_request_send(fc, req);
fuse_unlock_inode(inode); fuse_unlock_inode(inode, locked);
nbytes = req->out.args[0].size; nbytes = req->out.args[0].size;
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
......
...@@ -975,8 +975,8 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, ...@@ -975,8 +975,8 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
void fuse_set_initialized(struct fuse_conn *fc); void fuse_set_initialized(struct fuse_conn *fc);
void fuse_unlock_inode(struct inode *inode); void fuse_unlock_inode(struct inode *inode, bool locked);
void fuse_lock_inode(struct inode *inode); bool fuse_lock_inode(struct inode *inode);
int fuse_setxattr(struct inode *inode, const char *name, const void *value, int fuse_setxattr(struct inode *inode, const char *name, const void *value,
size_t size, int flags); size_t size, int flags);
......
...@@ -357,15 +357,21 @@ int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid, ...@@ -357,15 +357,21 @@ int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
return 0; 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); 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); mutex_unlock(&get_fuse_inode(inode)->mutex);
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment