From 3c324b9465710947abef23044cdcd8bfce8d982d Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Fri, 15 Feb 2019 22:55:13 +0000 Subject: [PATCH] FUSE: Refresh cached file size when it changes (lookup) The cached fvdat->filesize is indepedent of the (mostly unused) cached_attrs, and we failed to update it when a cached (but perhaps inactive) vnode was found during VOP_LOOKUP to have a different size than cached. As noted in the code comment, this can occur in distributed filesystems or with other kinds of irregular file behavior (anything is possible in FUSE). We do something similar in fuse_vnop_getattr already. PR: 230258 (as reported in description; other issues explored in comments are not all resolved) Reported by: MooseFS FreeBSD Team Submitted by: Jakub Kruszona-Zawadzki (earlier version) --- sys/fs/fuse/fuse_vnops.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c index 6ab93bb16f36..6a263283c6dd 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -949,12 +949,45 @@ calldaemon: vref(dvp); *vpp = dvp; } else { + struct fuse_vnode_data *fvdat; + err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp, &vp, cnp, IFTOVT(fattr->mode)); if (err) { goto out; } fuse_vnode_setparent(vp, dvp); + + /* + * In the case where we are looking up a FUSE node + * represented by an existing cached vnode, and the + * true size reported by FUSE_LOOKUP doesn't match + * the vnode's cached size, fix the vnode cache to + * match the real object size. + * + * This can occur via FUSE distributed filesystems, + * irregular files, etc. + */ + fvdat = VTOFUD(vp); + if (vnode_isreg(vp) && + fattr->size != fvdat->filesize) { + /* + * The FN_SIZECHANGE flag reflects a dirty + * append. If userspace lets us know our cache + * is invalid, that write was lost. (Dirty + * writes that do not cause append are also + * lost, but we don't detect them here.) + * + * XXX: Maybe disable WB caching on this mount. + */ + if (fvdat->flag & FN_SIZECHANGE) + printf("%s: WB cache incoherent on " + "%s!\n", __func__, + vnode_mount(vp)->mnt_stat.f_mntonname); + + (void)fuse_vnode_setsize(vp, cred, fattr->size); + fvdat->flag &= ~FN_SIZECHANGE; + } *vpp = vp; }