]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.18.6/fuse-fix-initial-parallel-dirops.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.18.6 / fuse-fix-initial-parallel-dirops.patch
CommitLineData
319b4646
GKH
1From 63576c13bd17848376c8ba4a98f5d5151140c4ac Mon Sep 17 00:00:00 2001
2From: Miklos Szeredi <mszeredi@redhat.com>
3Date: Thu, 26 Jul 2018 16:13:11 +0200
4Subject: fuse: fix initial parallel dirops
5
6From: Miklos Szeredi <mszeredi@redhat.com>
7
8commit 63576c13bd17848376c8ba4a98f5d5151140c4ac upstream.
9
10If parallel dirops are enabled in FUSE_INIT reply, then first operation may
11leave fi->mutex held.
12
13Reported-by: syzbot <syzbot+3f7b29af1baa9d0a55be@syzkaller.appspotmail.com>
14Fixes: 5c672ab3f0ee ("fuse: serialize dirops by default")
15Cc: <stable@vger.kernel.org> # v4.7
16Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
17Signed-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