diff options
author | Alan Somers <asomers@FreeBSD.org> | 2021-10-03 17:51:14 +0000 |
---|---|---|
committer | Alan Somers <asomers@FreeBSD.org> | 2021-10-06 20:07:33 +0000 |
commit | 032a5bd55b3a003d3560435422a95f27f91685fe (patch) | |
tree | b9ceb38584c6989cf7383a410df9078c4f1c3022 /sys/fs | |
parent | 7430017b9978cae054ed99e5160f739e5ca021d5 (diff) | |
download | src-032a5bd55b3a003d3560435422a95f27f91685fe.tar.gz src-032a5bd55b3a003d3560435422a95f27f91685fe.zip |
fusefs: Fix a bug during VOP_STRATEGY when the server changes file size
If the FUSE server tells the kernel that a file's size has changed, then
the kernel must invalidate any portion of that file in cache. But the
kernel can't do that during VOP_STRATEGY, because the file's buffers are
already locked. Instead, proceed with the write.
PR: 256937
Reported by: Agata <chogata@moosefs.pro>
Tested by: Agata <chogata@moosefs.pro>
MFC after: 2 weeks
Reviewed by: pfg
Differential Revision: https://reviews.freebsd.org/D32332
Diffstat (limited to 'sys/fs')
-rw-r--r-- | sys/fs/fuse/fuse_io.c | 19 |
1 files changed, 12 insertions, 7 deletions
diff --git a/sys/fs/fuse/fuse_io.c b/sys/fs/fuse/fuse_io.c index 637c36424d3f..f818fbd52869 100644 --- a/sys/fs/fuse/fuse_io.c +++ b/sys/fs/fuse/fuse_io.c @@ -1007,13 +1007,18 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp) /* * Setup for actual write */ - error = fuse_vnode_size(vp, &filesize, cred, curthread); - if (error) { - bp->b_ioflags |= BIO_ERROR; - bp->b_error = error; - bufdone(bp); - return (error); - } + /* + * If the file's size is cached, use that value, even if the + * cache is expired. At this point we're already committed to + * writing something. If the FUSE server has changed the + * file's size behind our back, it's too late for us to do + * anything about it. In particular, we can't invalidate any + * part of the file's buffers because VOP_STRATEGY is called + * with them already locked. + */ + filesize = fvdat->cached_attrs.va_size; + /* filesize must've been cached by fuse_vnop_open. */ + KASSERT(filesize != VNOVAL, ("filesize should've been cached")); if ((off_t)bp->b_lblkno * biosize + bp->b_dirtyend > filesize) bp->b_dirtyend = filesize - |