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:
parent
18a2264e27
commit
2013b723d3
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -473,10 +473,10 @@ retry:
|
||||
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 @@ again:
|
||||
|
||||
err = fuse_vnode_setsize(vp, cred,
|
||||
uio->uio_offset + n);
|
||||
fvdat->flag |= FN_SIZECHANGE;
|
||||
|
||||
if (err) {
|
||||
brelse(bp);
|
||||
break;
|
||||
@ -617,10 +620,11 @@ again:
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) &&
|
||||
|
Loading…
x
Reference in New Issue
Block a user