]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.19.51/fuse-retrieve-cap-requested-size-to-negotiated-max_w.patch
Linux 4.19.51
[thirdparty/kernel/stable-queue.git] / releases / 4.19.51 / fuse-retrieve-cap-requested-size-to-negotiated-max_w.patch
1 From b6c08a50275ea43daaea0ca1c977b768c3329484 Mon Sep 17 00:00:00 2001
2 From: Kirill Smelkov <kirr@nexedi.com>
3 Date: Wed, 27 Mar 2019 10:15:19 +0000
4 Subject: fuse: retrieve: cap requested size to negotiated max_write
5
6 [ Upstream commit 7640682e67b33cab8628729afec8ca92b851394f ]
7
8 FUSE filesystem server and kernel client negotiate during initialization
9 phase, what should be the maximum write size the client will ever issue.
10 Correspondingly the filesystem server then queues sys_read calls to read
11 requests with buffer capacity large enough to carry request header + that
12 max_write bytes. A filesystem server is free to set its max_write in
13 anywhere in the range between [1*page, fc->max_pages*page]. In particular
14 go-fuse[2] sets max_write by default as 64K, wheres default fc->max_pages
15 corresponds to 128K. Libfuse also allows users to configure max_write, but
16 by default presets it to possible maximum.
17
18 If max_write is < fc->max_pages*page, and in NOTIFY_RETRIEVE handler we
19 allow to retrieve more than max_write bytes, corresponding prepared
20 NOTIFY_REPLY will be thrown away by fuse_dev_do_read, because the
21 filesystem server, in full correspondence with server/client contract, will
22 be only queuing sys_read with ~max_write buffer capacity, and
23 fuse_dev_do_read throws away requests that cannot fit into server request
24 buffer. In turn the filesystem server could get stuck waiting indefinitely
25 for NOTIFY_REPLY since NOTIFY_RETRIEVE handler returned OK which is
26 understood by clients as that NOTIFY_REPLY was queued and will be sent
27 back.
28
29 Cap requested size to negotiate max_write to avoid the problem. This
30 aligns with the way NOTIFY_RETRIEVE handler works, which already
31 unconditionally caps requested retrieve size to fuse_conn->max_pages. This
32 way it should not hurt NOTIFY_RETRIEVE semantic if we return less data than
33 was originally requested.
34
35 Please see [1] for context where the problem of stuck filesystem was hit
36 for real, how the situation was traced and for more involving patch that
37 did not make it into the tree.
38
39 [1] https://marc.info/?l=linux-fsdevel&m=155057023600853&w=2
40 [2] https://github.com/hanwen/go-fuse
41
42 Signed-off-by: Kirill Smelkov <kirr@nexedi.com>
43 Cc: Han-Wen Nienhuys <hanwen@google.com>
44 Cc: Jakob Unterwurzacher <jakobunt@gmail.com>
45 Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
46 Signed-off-by: Sasha Levin <sashal@kernel.org>
47 ---
48 fs/fuse/dev.c | 2 +-
49 1 file changed, 1 insertion(+), 1 deletion(-)
50
51 --- a/fs/fuse/dev.c
52 +++ b/fs/fuse/dev.c
53 @@ -1681,7 +1681,7 @@ static int fuse_retrieve(struct fuse_con
54 offset = outarg->offset & ~PAGE_MASK;
55 file_size = i_size_read(inode);
56
57 - num = outarg->size;
58 + num = min(outarg->size, fc->max_write);
59 if (outarg->offset > file_size)
60 num = 0;
61 else if (outarg->offset + num > file_size)