• Kirill Smelkov's avatar
    fuse: retrieve: cap requested size to negotiated max_write · 1e0a2528
    Kirill Smelkov authored
    [ Upstream commit 7640682e67b33cab8628729afec8ca92b851394f ]
    
    FUSE filesystem server and kernel client negotiate during initialization
    phase, what should be the maximum write size the client will ever issue.
    Correspondingly the filesystem server then queues sys_read calls to read
    requests with buffer capacity large enough to carry request header + that
    max_write bytes. A filesystem server is free to set its max_write in
    anywhere in the range between [1*page, fc->max_pages*page]. In particular
    go-fuse[2] sets max_write by default as 64K, wheres default fc->max_pages
    corresponds to 128K. Libfuse also allows users to configure max_write, but
    by default presets it to possible maximum.
    
    If max_write is < fc->max_pages*page, and in NOTIFY_RETRIEVE handler we
    allow to retrieve more than max_write bytes, corresponding prepared
    NOTIFY_REPLY will be thrown away by fuse_dev_do_read, because the
    filesystem server, in full correspondence with server/client contract, will
    be only queuing sys_read with ~max_write buffer capacity, and
    fuse_dev_do_read throws away requests that cannot fit into server request
    buffer. In turn the filesystem server could get stuck waiting indefinitely
    for NOTIFY_REPLY since NOTIFY_RETRIEVE handler returned OK which is
    understood by clients as that NOTIFY_REPLY was queued and will be sent
    back.
    
    Cap requested size to negotiate max_write to avoid the problem.  This
    aligns with the way NOTIFY_RETRIEVE handler works, which already
    unconditionally caps requested retrieve size to fuse_conn->max_pages.  This
    way it should not hurt NOTIFY_RETRIEVE semantic if we return less data than
    was originally requested.
    
    Please see [1] for context where the problem of stuck filesystem was hit
    for real, how the situation was traced and for more involving patch that
    did not make it into the tree.
    
    [1] https://marc.info/?l=linux-fsdevel&m=155057023600853&w=2
    [2] https://github.com/hanwen/go-fuseSigned-off-by: 's avatarKirill Smelkov <kirr@nexedi.com>
    Cc: Han-Wen Nienhuys <hanwen@google.com>
    Cc: Jakob Unterwurzacher <jakobunt@gmail.com>
    Signed-off-by: 's avatarMiklos Szeredi <mszeredi@redhat.com>
    Signed-off-by: 's avatarSasha Levin <sashal@kernel.org>
    1e0a2528
Name
Last commit
Last update
..
Kconfig Loading commit data...
Makefile Loading commit data...
acl.c Loading commit data...
control.c Loading commit data...
cuse.c Loading commit data...
dev.c Loading commit data...
dir.c Loading commit data...
file.c Loading commit data...
fuse_i.h Loading commit data...
inode.c Loading commit data...
xattr.c Loading commit data...