]>
Commit | Line | Data |
---|---|---|
1e6a8e33 GKH |
1 | From bbd84f33652f852ce5992d65db4d020aba21f882 Mon Sep 17 00:00:00 2001 |
2 | From: Kirill Smelkov <kirr@nexedi.com> | |
3 | Date: Wed, 24 Apr 2019 07:13:57 +0000 | |
4 | Subject: fuse: Add FOPEN_STREAM to use stream_open() | |
5 | ||
6 | From: Kirill Smelkov <kirr@nexedi.com> | |
7 | ||
8 | commit bbd84f33652f852ce5992d65db4d020aba21f882 upstream. | |
9 | ||
10 | Starting from commit 9c225f2655e3 ("vfs: atomic f_pos accesses as per | |
11 | POSIX") files opened even via nonseekable_open gate read and write via lock | |
12 | and do not allow them to be run simultaneously. This can create read vs | |
13 | write deadlock if a filesystem is trying to implement a socket-like file | |
14 | which is intended to be simultaneously used for both read and write from | |
15 | filesystem client. See commit 10dce8af3422 ("fs: stream_open - opener for | |
16 | stream-like files so that read and write can run simultaneously without | |
17 | deadlock") for details and e.g. commit 581d21a2d02a ("xenbus: fix deadlock | |
18 | on writes to /proc/xen/xenbus") for a similar deadlock example on | |
19 | /proc/xen/xenbus. | |
20 | ||
21 | To avoid such deadlock it was tempting to adjust fuse_finish_open to use | |
22 | stream_open instead of nonseekable_open on just FOPEN_NONSEEKABLE flags, | |
23 | but grepping through Debian codesearch shows users of FOPEN_NONSEEKABLE, | |
24 | and in particular GVFS which actually uses offset in its read and write | |
25 | handlers | |
26 | ||
27 | https://codesearch.debian.net/search?q=-%3Enonseekable+%3D | |
28 | https://gitlab.gnome.org/GNOME/gvfs/blob/1.40.0-6-gcbc54396/client/gvfsfusedaemon.c#L1080 | |
29 | https://gitlab.gnome.org/GNOME/gvfs/blob/1.40.0-6-gcbc54396/client/gvfsfusedaemon.c#L1247-1346 | |
30 | https://gitlab.gnome.org/GNOME/gvfs/blob/1.40.0-6-gcbc54396/client/gvfsfusedaemon.c#L1399-1481 | |
31 | ||
32 | so if we would do such a change it will break a real user. | |
33 | ||
34 | Add another flag (FOPEN_STREAM) for filesystem servers to indicate that the | |
35 | opened handler is having stream-like semantics; does not use file position | |
36 | and thus the kernel is free to issue simultaneous read and write request on | |
37 | opened file handle. | |
38 | ||
39 | This patch together with stream_open() should be added to stable kernels | |
40 | starting from v3.14+. This will allow to patch OSSPD and other FUSE | |
41 | filesystems that provide stream-like files to return FOPEN_STREAM | | |
42 | FOPEN_NONSEEKABLE in open handler and this way avoid the deadlock on all | |
43 | kernel versions. This should work because fuse_finish_open ignores unknown | |
44 | open flags returned from a filesystem and so passing FOPEN_STREAM to a | |
45 | kernel that is not aware of this flag cannot hurt. In turn the kernel that | |
46 | is not aware of FOPEN_STREAM will be < v3.14 where just FOPEN_NONSEEKABLE | |
47 | is sufficient to implement streams without read vs write deadlock. | |
48 | ||
49 | Cc: stable@vger.kernel.org # v3.14+ | |
50 | Signed-off-by: Kirill Smelkov <kirr@nexedi.com> | |
51 | Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> | |
52 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
53 | ||
54 | --- | |
55 | fs/fuse/file.c | 4 +++- | |
56 | include/uapi/linux/fuse.h | 2 ++ | |
57 | 2 files changed, 5 insertions(+), 1 deletion(-) | |
58 | ||
59 | --- a/fs/fuse/file.c | |
60 | +++ b/fs/fuse/file.c | |
61 | @@ -179,7 +179,9 @@ void fuse_finish_open(struct inode *inod | |
62 | file->f_op = &fuse_direct_io_file_operations; | |
63 | if (!(ff->open_flags & FOPEN_KEEP_CACHE)) | |
64 | invalidate_inode_pages2(inode->i_mapping); | |
65 | - if (ff->open_flags & FOPEN_NONSEEKABLE) | |
66 | + if (ff->open_flags & FOPEN_STREAM) | |
67 | + stream_open(inode, file); | |
68 | + else if (ff->open_flags & FOPEN_NONSEEKABLE) | |
69 | nonseekable_open(inode, file); | |
70 | if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) { | |
71 | struct fuse_inode *fi = get_fuse_inode(inode); | |
72 | --- a/include/uapi/linux/fuse.h | |
73 | +++ b/include/uapi/linux/fuse.h | |
74 | @@ -219,10 +219,12 @@ struct fuse_file_lock { | |
75 | * FOPEN_DIRECT_IO: bypass page cache for this open file | |
76 | * FOPEN_KEEP_CACHE: don't invalidate the data cache on open | |
77 | * FOPEN_NONSEEKABLE: the file is not seekable | |
78 | + * FOPEN_STREAM: the file is stream-like (no file position at all) | |
79 | */ | |
80 | #define FOPEN_DIRECT_IO (1 << 0) | |
81 | #define FOPEN_KEEP_CACHE (1 << 1) | |
82 | #define FOPEN_NONSEEKABLE (1 << 2) | |
83 | +#define FOPEN_STREAM (1 << 4) | |
84 | ||
85 | /** | |
86 | * INIT request/reply flags |