aboutsummaryrefslogtreecommitdiff
path: root/sys/fs
diff options
context:
space:
mode:
authorAlan Somers <asomers@FreeBSD.org>2021-10-03 17:51:14 +0000
committerAlan Somers <asomers@FreeBSD.org>2021-10-06 20:07:33 +0000
commit032a5bd55b3a003d3560435422a95f27f91685fe (patch)
treeb9ceb38584c6989cf7383a410df9078c4f1c3022 /sys/fs
parent7430017b9978cae054ed99e5160f739e5ca021d5 (diff)
downloadsrc-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.c19
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 -