]>
Commit | Line | Data |
---|---|---|
37554d48 SL |
1 | From ce9fca48a0fa1140bc35a07fced42d8580b39d8b Mon Sep 17 00:00:00 2001 |
2 | From: "J. Bruce Fields" <bfields@redhat.com> | |
3 | Date: Fri, 12 Apr 2019 16:37:30 -0400 | |
4 | Subject: nfsd: allow fh_want_write to be called twice | |
5 | ||
6 | [ Upstream commit 0b8f62625dc309651d0efcb6a6247c933acd8b45 ] | |
7 | ||
8 | A fuzzer recently triggered lockdep warnings about potential sb_writers | |
9 | deadlocks caused by fh_want_write(). | |
10 | ||
11 | Looks like we aren't careful to pair each fh_want_write() with an | |
12 | fh_drop_write(). | |
13 | ||
14 | It's not normally a problem since fh_put() will call fh_drop_write() for | |
15 | us. And was OK for NFSv3 where we'd do one operation that might call | |
16 | fh_want_write(), and then put the filehandle. | |
17 | ||
18 | But an NFSv4 protocol fuzzer can do weird things like call unlink twice | |
19 | in a compound, and then we get into trouble. | |
20 | ||
21 | I'm a little worried about this approach of just leaving everything to | |
22 | fh_put(). But I think there are probably a lot of | |
23 | fh_want_write()/fh_drop_write() imbalances so for now I think we need it | |
24 | to be more forgiving. | |
25 | ||
26 | Signed-off-by: J. Bruce Fields <bfields@redhat.com> | |
27 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
28 | --- | |
29 | fs/nfsd/vfs.h | 5 ++++- | |
30 | 1 file changed, 4 insertions(+), 1 deletion(-) | |
31 | ||
32 | diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h | |
33 | index a7e107309f76..db351247892d 100644 | |
34 | --- a/fs/nfsd/vfs.h | |
35 | +++ b/fs/nfsd/vfs.h | |
36 | @@ -120,8 +120,11 @@ void nfsd_put_raparams(struct file *file, struct raparms *ra); | |
37 | ||
38 | static inline int fh_want_write(struct svc_fh *fh) | |
39 | { | |
40 | - int ret = mnt_want_write(fh->fh_export->ex_path.mnt); | |
41 | + int ret; | |
42 | ||
43 | + if (fh->fh_want_write) | |
44 | + return 0; | |
45 | + ret = mnt_want_write(fh->fh_export->ex_path.mnt); | |
46 | if (!ret) | |
47 | fh->fh_want_write = true; | |
48 | return ret; | |
49 | -- | |
50 | 2.20.1 | |
51 |