]>
Commit | Line | Data |
---|---|---|
319b4646 GKH |
1 | From 63576c13bd17848376c8ba4a98f5d5151140c4ac Mon Sep 17 00:00:00 2001 |
2 | From: Miklos Szeredi <mszeredi@redhat.com> | |
3 | Date: Thu, 26 Jul 2018 16:13:11 +0200 | |
4 | Subject: fuse: fix initial parallel dirops | |
5 | ||
6 | From: Miklos Szeredi <mszeredi@redhat.com> | |
7 | ||
8 | commit 63576c13bd17848376c8ba4a98f5d5151140c4ac upstream. | |
9 | ||
10 | If parallel dirops are enabled in FUSE_INIT reply, then first operation may | |
11 | leave fi->mutex held. | |
12 | ||
13 | Reported-by: syzbot <syzbot+3f7b29af1baa9d0a55be@syzkaller.appspotmail.com> | |
14 | Fixes: 5c672ab3f0ee ("fuse: serialize dirops by default") | |
15 | Cc: <stable@vger.kernel.org> # v4.7 | |
16 | Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> | |
17 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
18 | ||
19 | --- | |
20 | fs/fuse/dir.c | 10 ++++++---- | |
21 | fs/fuse/fuse_i.h | 4 ++-- | |
22 | fs/fuse/inode.c | 14 ++++++++++---- | |
23 | 3 files changed, 18 insertions(+), 10 deletions(-) | |
24 | ||
25 | --- a/fs/fuse/dir.c | |
26 | +++ b/fs/fuse/dir.c | |
27 | @@ -355,11 +355,12 @@ static struct dentry *fuse_lookup(struct | |
28 | struct inode *inode; | |
29 | struct dentry *newent; | |
30 | bool outarg_valid = true; | |
31 | + bool locked; | |
32 | ||
33 | - fuse_lock_inode(dir); | |
34 | + locked = fuse_lock_inode(dir); | |
35 | err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name, | |
36 | &outarg, &inode); | |
37 | - fuse_unlock_inode(dir); | |
38 | + fuse_unlock_inode(dir, locked); | |
39 | if (err == -ENOENT) { | |
40 | outarg_valid = false; | |
41 | err = 0; | |
42 | @@ -1340,6 +1341,7 @@ static int fuse_readdir(struct file *fil | |
43 | struct fuse_conn *fc = get_fuse_conn(inode); | |
44 | struct fuse_req *req; | |
45 | u64 attr_version = 0; | |
46 | + bool locked; | |
47 | ||
48 | if (is_bad_inode(inode)) | |
49 | return -EIO; | |
50 | @@ -1367,9 +1369,9 @@ static int fuse_readdir(struct file *fil | |
51 | fuse_read_fill(req, file, ctx->pos, PAGE_SIZE, | |
52 | FUSE_READDIR); | |
53 | } | |
54 | - fuse_lock_inode(inode); | |
55 | + locked = fuse_lock_inode(inode); | |
56 | fuse_request_send(fc, req); | |
57 | - fuse_unlock_inode(inode); | |
58 | + fuse_unlock_inode(inode, locked); | |
59 | nbytes = req->out.args[0].size; | |
60 | err = req->out.h.error; | |
61 | fuse_put_request(fc, req); | |
62 | --- a/fs/fuse/fuse_i.h | |
63 | +++ b/fs/fuse/fuse_i.h | |
64 | @@ -974,8 +974,8 @@ int fuse_do_setattr(struct dentry *dentr | |
65 | ||
66 | void fuse_set_initialized(struct fuse_conn *fc); | |
67 | ||
68 | -void fuse_unlock_inode(struct inode *inode); | |
69 | -void fuse_lock_inode(struct inode *inode); | |
70 | +void fuse_unlock_inode(struct inode *inode, bool locked); | |
71 | +bool fuse_lock_inode(struct inode *inode); | |
72 | ||
73 | int fuse_setxattr(struct inode *inode, const char *name, const void *value, | |
74 | size_t size, int flags); | |
75 | --- a/fs/fuse/inode.c | |
76 | +++ b/fs/fuse/inode.c | |
77 | @@ -357,15 +357,21 @@ int fuse_reverse_inval_inode(struct supe | |
78 | return 0; | |
79 | } | |
80 | ||
81 | -void fuse_lock_inode(struct inode *inode) | |
82 | +bool fuse_lock_inode(struct inode *inode) | |
83 | { | |
84 | - if (!get_fuse_conn(inode)->parallel_dirops) | |
85 | + bool locked = false; | |
86 | + | |
87 | + if (!get_fuse_conn(inode)->parallel_dirops) { | |
88 | mutex_lock(&get_fuse_inode(inode)->mutex); | |
89 | + locked = true; | |
90 | + } | |
91 | + | |
92 | + return locked; | |
93 | } | |
94 | ||
95 | -void fuse_unlock_inode(struct inode *inode) | |
96 | +void fuse_unlock_inode(struct inode *inode, bool locked) | |
97 | { | |
98 | - if (!get_fuse_conn(inode)->parallel_dirops) | |
99 | + if (locked) | |
100 | mutex_unlock(&get_fuse_inode(inode)->mutex); | |
101 | } | |
102 |