fusefs: improve attribute cacheing

Consolidate all calls to fuse_vnode_setsize as a result of a file attribute
change to one location in fuse_internal_setattr.  There are still a few
calls elsewhere that happen as a result of a write.

Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Alan Somers 2019-05-23 00:22:03 +00:00
parent 18a2264e27
commit 2013b723d3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/fuse2/; revision=348134
5 changed files with 66 additions and 71 deletions

View File

@ -193,8 +193,9 @@ fuse_internal_access(struct vnode *vp,
* return the result to the caller).
*/
void
fuse_internal_cache_attrs(struct vnode *vp, struct fuse_attr *attr,
uint64_t attr_valid, uint32_t attr_valid_nsec, struct vattr *vap)
fuse_internal_cache_attrs(struct vnode *vp, struct ucred *cred,
struct fuse_attr *attr, uint64_t attr_valid, uint32_t attr_valid_nsec,
struct vattr *vap)
{
struct mount *mp;
struct fuse_vnode_data *fvdat;
@ -204,45 +205,53 @@ fuse_internal_cache_attrs(struct vnode *vp, struct fuse_attr *attr,
mp = vnode_mount(vp);
fvdat = VTOFUD(vp);
data = fuse_get_mpdata(mp);
if (!cred)
cred = curthread->td_ucred;
ASSERT_VOP_ELOCKED(*vpp, "fuse_internal_cache_attrs");
fuse_validity_2_bintime(attr_valid, attr_valid_nsec,
&fvdat->attr_cache_timeout);
vp_cache_at = VTOVA(vp);
/* Fix our buffers if the filesize changed without us knowing */
if (vnode_isreg(vp) && attr->size != fvdat->cached_attrs.va_size) {
(void)fuse_vnode_setsize(vp, cred, attr->size);
fvdat->cached_attrs.va_size = attr->size;
}
if (vap == NULL && vp_cache_at == NULL)
if (attr_valid > 0 || attr_valid_nsec > 0)
vp_cache_at = &(fvdat->cached_attrs);
else if (vap != NULL)
vp_cache_at = vap;
else
return;
if (vap == NULL)
vap = vp_cache_at;
vattr_null(vap);
vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
vap->va_fileid = attr->ino;
vap->va_mode = attr->mode & ~S_IFMT;
vap->va_nlink = attr->nlink;
vap->va_uid = attr->uid;
vap->va_gid = attr->gid;
vap->va_rdev = attr->rdev;
vap->va_size = attr->size;
vattr_null(vp_cache_at);
vp_cache_at->va_fsid = mp->mnt_stat.f_fsid.val[0];
vp_cache_at->va_fileid = attr->ino;
vp_cache_at->va_mode = attr->mode & ~S_IFMT;
vp_cache_at->va_nlink = attr->nlink;
vp_cache_at->va_uid = attr->uid;
vp_cache_at->va_gid = attr->gid;
vp_cache_at->va_rdev = attr->rdev;
vp_cache_at->va_size = attr->size;
/* XXX on i386, seconds are truncated to 32 bits */
vap->va_atime.tv_sec = attr->atime;
vap->va_atime.tv_nsec = attr->atimensec;
vap->va_mtime.tv_sec = attr->mtime;
vap->va_mtime.tv_nsec = attr->mtimensec;
vap->va_ctime.tv_sec = attr->ctime;
vap->va_ctime.tv_nsec = attr->ctimensec;
vp_cache_at->va_atime.tv_sec = attr->atime;
vp_cache_at->va_atime.tv_nsec = attr->atimensec;
vp_cache_at->va_mtime.tv_sec = attr->mtime;
vp_cache_at->va_mtime.tv_nsec = attr->mtimensec;
vp_cache_at->va_ctime.tv_sec = attr->ctime;
vp_cache_at->va_ctime.tv_nsec = attr->ctimensec;
if (fuse_libabi_geq(data, 7, 9) && attr->blksize > 0)
vap->va_blocksize = attr->blksize;
vp_cache_at->va_blocksize = attr->blksize;
else
vap->va_blocksize = PAGE_SIZE;
vap->va_type = IFTOVT(attr->mode);
vap->va_bytes = attr->blocks * S_BLKSIZE;
vap->va_flags = 0;
vp_cache_at->va_blocksize = PAGE_SIZE;
vp_cache_at->va_type = IFTOVT(attr->mode);
vp_cache_at->va_bytes = attr->blocks * S_BLKSIZE;
vp_cache_at->va_flags = 0;
if (vap != vp_cache_at && vp_cache_at != NULL)
memcpy(vp_cache_at, vap, sizeof(*vap));
if (vap != vp_cache_at && vap != NULL)
memcpy(vap, vp_cache_at, sizeof(*vap));
}
@ -560,7 +569,7 @@ fuse_internal_newentry_core(struct vnode *dvp,
*/
fuse_vnode_clear_attr_cache(dvp);
fuse_internal_cache_attrs(*vpp, &feo->attr, feo->attr_valid,
fuse_internal_cache_attrs(*vpp, NULL, &feo->attr, feo->attr_valid,
feo->attr_valid_nsec, NULL);
return err;
@ -646,25 +655,15 @@ fuse_internal_do_getattr(struct vnode *vp, struct vattr *vap,
fao = (struct fuse_attr_out *)fdi.answ;
vtyp = IFTOVT(fao->attr.mode);
fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid,
if (fvdat->flag & FN_SIZECHANGE)
fao->attr.size = old_filesize;
fuse_internal_cache_attrs(vp, NULL, &fao->attr, fao->attr_valid,
fao->attr_valid_nsec, vap);
if (vtyp != vnode_vtype(vp)) {
fuse_internal_vnode_disappear(vp);
err = ENOENT;
}
if ((fvdat->flag & FN_SIZECHANGE) != 0)
fvdat->cached_attrs.va_size = old_filesize;
if (vnode_isreg(vp) && (fvdat->flag & FN_SIZECHANGE) == 0) {
/*
* This is for those cases when the file size changed without us
* knowing, and we want to catch up.
*/
if (old_filesize != fao->attr.size)
fuse_vnode_setsize(vp, cred, fao->attr.size);
}
out:
fdisp_destroy(&fdi);
return err;
@ -675,14 +674,10 @@ int
fuse_internal_getattr(struct vnode *vp, struct vattr *vap, struct ucred *cred,
struct thread *td)
{
struct fuse_vnode_data *fvdat = VTOFUD(vp);
struct vattr *attrs;
off_t old_filesize = vap->va_size;
if ((attrs = VTOVA(vp)) != NULL) {
*vap = *attrs; /* struct copy */
if ((fvdat->flag & FN_SIZECHANGE) != 0)
vap->va_size = old_filesize;
return 0;
}
@ -829,6 +824,7 @@ int fuse_internal_setattr(struct vnode *vp, struct vattr *vap,
fsai->fh = fufh->fh_id;
fsai->valid |= FATTR_FH;
}
VTOFUD(vp)->flag &= ~FN_SIZECHANGE;
}
if (vap->va_atime.tv_sec != VNOVAL) {
fsai->atime = vap->va_atime.tv_sec;
@ -875,16 +871,12 @@ int fuse_internal_setattr(struct vnode *vp, struct vattr *vap,
}
if (err == 0) {
struct fuse_attr_out *fao = (struct fuse_attr_out*)fdi.answ;
fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid,
fuse_internal_cache_attrs(vp, cred, &fao->attr, fao->attr_valid,
fao->attr_valid_nsec, NULL);
}
out:
fdisp_destroy(&fdi);
if (!err && sizechanged) {
fuse_vnode_setsize(vp, cred, newsize);
VTOFUD(vp)->flag &= ~FN_SIZECHANGE;
}
return err;
}

View File

@ -209,8 +209,9 @@ int fuse_internal_access(struct vnode *vp, accmode_t mode,
struct thread *td, struct ucred *cred);
/* attributes */
void fuse_internal_cache_attrs(struct vnode *vp, struct fuse_attr *attr,
uint64_t attr_valid, uint32_t attr_valid_nsec, struct vattr *vap);
void fuse_internal_cache_attrs(struct vnode *vp, struct ucred *cred,
struct fuse_attr *attr, uint64_t attr_valid, uint32_t attr_valid_nsec,
struct vattr *vap);
/* fsync */

View File

@ -473,10 +473,10 @@ fuse_write_directbackend(struct vnode *vp, struct uio *uio,
as_written_offset = uio->uio_offset - diff;
if (as_written_offset - diff > filesize &&
fuse_data_cache_mode != FUSE_CACHE_UC) {
fuse_data_cache_mode != FUSE_CACHE_UC)
fuse_vnode_setsize(vp, cred, as_written_offset);
if (as_written_offset - diff >= filesize)
fvdat->flag &= ~FN_SIZECHANGE;
}
if (diff < 0) {
printf("WARNING: misbehaving FUSE filesystem "
@ -528,6 +528,7 @@ static int
fuse_write_biobackend(struct vnode *vp, struct uio *uio,
struct ucred *cred, struct fuse_filehandle *fufh, int ioflag, pid_t pid)
{
struct fuse_vnode_data *fvdat = VTOFUD(vp);
struct buf *bp;
daddr_t lbn;
off_t filesize;
@ -590,6 +591,8 @@ fuse_write_biobackend(struct vnode *vp, struct uio *uio,
err = fuse_vnode_setsize(vp, cred,
uio->uio_offset + n);
fvdat->flag |= FN_SIZECHANGE;
if (err) {
brelse(bp);
break;
@ -617,10 +620,11 @@ fuse_write_biobackend(struct vnode *vp, struct uio *uio,
if (bp && uio->uio_offset + n > filesize) {
err = fuse_vnode_setsize(vp, cred,
uio->uio_offset + n);
fvdat->flag |= FN_SIZECHANGE;
if (err) {
brelse(bp);
break;
}
}
}
}

View File

@ -400,7 +400,6 @@ fuse_vnode_setsize(struct vnode *vp, struct ucred *cred, off_t newsize)
fvdat->cached_attrs.va_size = newsize;
if ((attrs = VTOVA(vp)) != NULL)
attrs->va_size = newsize;
fvdat->flag |= FN_SIZECHANGE;
if (newsize < oldsize) {
daddr_t lbn;

View File

@ -624,7 +624,7 @@ fuse_vnop_create(struct vop_create_args *ap)
goto out;
}
ASSERT_VOP_ELOCKED(*vpp, "fuse_vnop_create");
fuse_internal_cache_attrs(*vpp, &feo->attr, feo->attr_valid,
fuse_internal_cache_attrs(*vpp, cred, &feo->attr, feo->attr_valid,
feo->attr_valid_nsec, NULL);
fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, td, cred, foo);
@ -790,6 +790,7 @@ fuse_vnop_link(struct vop_link_args *ap)
struct vnode *vp = ap->a_vp;
struct vnode *tdvp = ap->a_tdvp;
struct componentname *cnp = ap->a_cnp;
struct ucred *cred = cnp->cn_cred;
struct vattr *vap = VTOVA(vp);
@ -831,7 +832,7 @@ fuse_vnop_link(struct vop_link_args *ap)
* should've updated its mtime and ctime
*/
fuse_vnode_clear_attr_cache(tdvp);
fuse_internal_cache_attrs(vp, &feo->attr, feo->attr_valid,
fuse_internal_cache_attrs(vp, cred, &feo->attr, feo->attr_valid,
feo->attr_valid_nsec, NULL);
}
out:
@ -1040,17 +1041,17 @@ fuse_vnop_lookup(struct vop_lookup_args *ap)
* 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.
* the vnode's cached size, then any cached writes
* beyond the file's current size are lost.
*
* We can get here:
* * following attribute cache expiration, or
* * due a bug in the daemon, or
* * the first time that we looked up the file.
*/
fvdat = VTOFUD(vp);
if (vnode_isreg(vp) &&
filesize != fvdat->cached_attrs.va_size) {
filesize != fvdat->cached_attrs.va_size &&
fvdat->flag & FN_SIZECHANGE) {
/*
* The FN_SIZECHANGE flag reflects a dirty
* append. If userspace lets us know our cache
@ -1060,17 +1061,15 @@ fuse_vnop_lookup(struct vop_lookup_args *ap)
*
* 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);
printf("%s: WB cache incoherent on %s!\n",
__func__,
vnode_mount(vp)->mnt_stat.f_mntonname);
(void)fuse_vnode_setsize(vp, cred, filesize);
fvdat->flag &= ~FN_SIZECHANGE;
}
MPASS(feo != NULL);
fuse_internal_cache_attrs(*vpp, &feo->attr,
fuse_internal_cache_attrs(*vpp, cred, &feo->attr,
feo->attr_valid, feo->attr_valid_nsec, NULL);
if ((nameiop == DELETE || nameiop == RENAME) &&