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