svn commit: r347603 - projects/fuse2/sys/fs/fuse
Alan Somers
asomers at FreeBSD.org
Wed May 15 00:38:55 UTC 2019
Author: asomers
Date: Wed May 15 00:38:52 2019
New Revision: 347603
URL: https://svnweb.freebsd.org/changeset/base/347603
Log:
fusefs: don't track a file's size in two places
fuse_vnode_data.filesize was mostly redundant with
fuse_vnode_data.cached_attrs.st_size, but didn't have exactly the same
meaning. It was very confusing. This commit eliminates the former. It
also eliminates fuse_vnode_refreshsize, which ignored the cache timeout
value.
Sponsored by: The FreeBSD Foundation
Modified:
projects/fuse2/sys/fs/fuse/fuse_internal.c
projects/fuse2/sys/fs/fuse/fuse_internal.h
projects/fuse2/sys/fs/fuse/fuse_io.c
projects/fuse2/sys/fs/fuse/fuse_node.c
projects/fuse2/sys/fs/fuse/fuse_node.h
projects/fuse2/sys/fs/fuse/fuse_vnops.c
Modified: projects/fuse2/sys/fs/fuse/fuse_internal.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_internal.c Wed May 15 00:15:40 2019 (r347602)
+++ projects/fuse2/sys/fs/fuse/fuse_internal.c Wed May 15 00:38:52 2019 (r347603)
@@ -620,60 +620,68 @@ fuse_internal_forget_send(struct mount *mp,
fdisp_destroy(&fdi);
}
-/* Read a vnode's attributes from cache or fetch them from the fuse daemon */
+/* Fetch the vnode's attributes from the daemon*/
int
-fuse_internal_getattr(struct vnode *vp, struct vattr *vap, struct ucred *cred,
- struct thread *td)
+fuse_internal_do_getattr(struct vnode *vp, struct vattr *vap,
+ struct ucred *cred, struct thread *td)
{
struct fuse_dispatcher fdi;
struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct vattr *attrs;
struct fuse_attr_out *fao;
- int err = 0;
+ off_t old_filesize = fvdat->cached_attrs.va_size;
+ enum vtype vtyp;
+ int err;
- if ((attrs = VTOVA(vp)) != NULL) {
- /* struct copy */
- *vap = *attrs;
- if ((fvdat->flag & FN_SIZECHANGE) != 0)
- vap->va_size = fvdat->filesize;
- return 0;
- }
-
fdisp_init(&fdi, 0);
if ((err = fdisp_simple_putget_vp(&fdi, FUSE_GETATTR, vp, td, cred))) {
- if (err == ENOENT) {
+ if (err == ENOENT)
fuse_internal_vnode_disappear(vp);
- }
goto out;
}
fao = (struct fuse_attr_out *)fdi.answ;
+ vtyp = IFTOVT(fao->attr.mode);
fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid,
fao->attr_valid_nsec, vap);
- if (vap->va_type != vnode_vtype(vp)) {
+ if (vtyp != vnode_vtype(vp)) {
fuse_internal_vnode_disappear(vp);
err = ENOENT;
- goto out;
}
+
if ((fvdat->flag & FN_SIZECHANGE) != 0)
- vap->va_size = fvdat->filesize;
+ 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.
*/
- off_t new_filesize = fao->attr.size;
-
- if (fvdat->filesize != new_filesize) {
- fuse_vnode_setsize(vp, cred, new_filesize);
- fvdat->flag &= ~FN_SIZECHANGE;
- }
+ if (old_filesize != fao->attr.size)
+ fuse_vnode_setsize(vp, cred, fao->attr.size);
}
out:
fdisp_destroy(&fdi);
return err;
+}
+
+/* Read a vnode's attributes from cache or fetch them from the fuse daemon */
+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;
+ }
+
+ return fuse_internal_do_getattr(vp, vap, cred, td);
}
void
Modified: projects/fuse2/sys/fs/fuse/fuse_internal.h
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_internal.h Wed May 15 00:15:40 2019 (r347602)
+++ projects/fuse2/sys/fs/fuse/fuse_internal.h Wed May 15 00:38:52 2019 (r347603)
@@ -219,6 +219,8 @@ int fuse_internal_fsync(struct vnode *vp, struct threa
int fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio);
/* getattr */
+int fuse_internal_do_getattr(struct vnode *vp, struct vattr *vap,
+ struct ucred *cred, struct thread *td);
int fuse_internal_getattr(struct vnode *vp, struct vattr *vap,
struct ucred *cred, struct thread *td);
Modified: projects/fuse2/sys/fs/fuse/fuse_io.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_io.c Wed May 15 00:15:40 2019 (r347602)
+++ projects/fuse2/sys/fs/fuse/fuse_io.c Wed May 15 00:38:52 2019 (r347603)
@@ -118,7 +118,8 @@ fuse_read_biobackend(struct vnode *vp, struct uio *uio
struct ucred *cred, struct fuse_filehandle *fufh, pid_t pid);
static int
fuse_write_directbackend(struct vnode *vp, struct uio *uio,
- struct ucred *cred, struct fuse_filehandle *fufh, int ioflag);
+ struct ucred *cred, struct fuse_filehandle *fufh, off_t filesize,
+ int ioflag);
static int
fuse_write_biobackend(struct vnode *vp, struct uio *uio,
struct ucred *cred, struct fuse_filehandle *fufh, int ioflag, pid_t pid);
@@ -214,10 +215,15 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, in
*/
if (directio || fuse_data_cache_mode == FUSE_CACHE_WT) {
const int iosize = fuse_iosize(vp);
- off_t start, end;
+ off_t start, end, filesize;
SDT_PROBE2(fusefs, , io, trace, 1,
"direct write of vnode");
+
+ err = fuse_vnode_size(vp, &filesize, cred, curthread);
+ if (err)
+ return err;
+
start = uio->uio_offset;
end = start + uio->uio_resid;
/*
@@ -228,7 +234,7 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, in
if (!pages )
v_inval_buf_range(vp, start, end, iosize);
err = fuse_write_directbackend(vp, uio, cred, fufh,
- ioflag);
+ filesize, ioflag);
} else {
SDT_PROBE2(fusefs, , io, trace, 1,
"buffered write of vnode");
@@ -262,7 +268,9 @@ fuse_read_biobackend(struct vnode *vp, struct uio *uio
if (uio->uio_offset < 0)
return (EINVAL);
- filesize = VTOFUD(vp)->filesize;
+ err = fuse_vnode_size(vp, &filesize, cred, curthread);
+ if (err)
+ return err;
for (err = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
if (fuse_isdeadfs(vp)) {
@@ -373,7 +381,8 @@ out:
static int
fuse_write_directbackend(struct vnode *vp, struct uio *uio,
- struct ucred *cred, struct fuse_filehandle *fufh, int ioflag)
+ struct ucred *cred, struct fuse_filehandle *fufh, off_t filesize,
+ int ioflag)
{
struct fuse_vnode_data *fvdat = VTOFUD(vp);
struct fuse_write_in *fwi;
@@ -388,8 +397,9 @@ fuse_write_directbackend(struct vnode *vp, struct uio
if (uio->uio_resid == 0)
return (0);
+
if (ioflag & IO_APPEND)
- uio_setoffset(uio, fvdat->filesize);
+ uio_setoffset(uio, filesize);
fdisp_init(&fdi, 0);
@@ -436,7 +446,7 @@ retry:
diff = fwi->size - fwo->size;
as_written_offset = uio->uio_offset - diff;
- if (as_written_offset - diff > fvdat->filesize &&
+ if (as_written_offset - diff > filesize &&
fuse_data_cache_mode != FUSE_CACHE_UC) {
fuse_vnode_setsize(vp, cred, as_written_offset);
fvdat->flag &= ~FN_SIZECHANGE;
@@ -495,6 +505,7 @@ fuse_write_biobackend(struct vnode *vp, struct uio *ui
struct fuse_vnode_data *fvdat = VTOFUD(vp);
struct buf *bp;
daddr_t lbn;
+ off_t filesize;
int bcount;
int n, on, err = 0;
@@ -507,8 +518,13 @@ fuse_write_biobackend(struct vnode *vp, struct uio *ui
return (EINVAL);
if (uio->uio_resid == 0)
return (0);
+
+ err = fuse_vnode_size(vp, &filesize, cred, curthread);
+ if (err)
+ return err;
+
if (ioflag & IO_APPEND)
- uio_setoffset(uio, fvdat->filesize);
+ uio_setoffset(uio, filesize);
/*
* Find all of this file's B_NEEDCOMMIT buffers. If our writes
@@ -532,7 +548,7 @@ again:
* Handle direct append and file extension cases, calculate
* unaligned buffer size.
*/
- if (uio->uio_offset == fvdat->filesize && n) {
+ if (uio->uio_offset == filesize && n) {
/*
* Get the buffer (in its pre-append state to maintain
* B_CACHE if it was previously set). Resize the
@@ -564,17 +580,16 @@ again:
* adjust the file's size as appropriate.
*/
bcount = on + n;
- if ((off_t)lbn * biosize + bcount < fvdat->filesize) {
- if ((off_t)(lbn + 1) * biosize < fvdat->filesize)
+ if ((off_t)lbn * biosize + bcount < filesize) {
+ if ((off_t)(lbn + 1) * biosize < filesize)
bcount = biosize;
else
- bcount = fvdat->filesize -
- (off_t)lbn *biosize;
+ bcount = filesize - (off_t)lbn *biosize;
}
SDT_PROBE6(fusefs, , io, write_biobackend_start,
lbn, on, n, uio, bcount, false);
bp = getblk(vp, lbn, bcount, PCATCH, 0, 0);
- if (bp && uio->uio_offset + n > fvdat->filesize) {
+ if (bp && uio->uio_offset + n > filesize) {
err = fuse_vnode_setsize(vp, cred,
uio->uio_offset + n);
if (err) {
@@ -719,11 +734,11 @@ int
fuse_io_strategy(struct vnode *vp, struct buf *bp)
{
struct fuse_filehandle *fufh;
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
struct ucred *cred;
struct uio *uiop;
struct uio uio;
struct iovec io;
+ off_t filesize;
int error = 0;
int fflag;
/* We don't know the true pid when we're dealing with the cache */
@@ -807,9 +822,16 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp)
/*
* Setup for actual write
*/
- if ((off_t)bp->b_blkno * biosize + bp->b_dirtyend >
- fvdat->filesize)
- bp->b_dirtyend = fvdat->filesize -
+ error = fuse_vnode_size(vp, &filesize, cred, curthread);
+ if (error) {
+ bp->b_ioflags |= BIO_ERROR;
+ bp->b_error = error;
+ bufdone(bp);
+ return (error);
+ }
+
+ if ((off_t)bp->b_blkno * biosize + bp->b_dirtyend > filesize)
+ bp->b_dirtyend = filesize -
(off_t)bp->b_blkno * biosize;
if (bp->b_dirtyend > bp->b_dirtyoff) {
@@ -820,7 +842,8 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp)
io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
uiop->uio_rw = UIO_WRITE;
- error = fuse_write_directbackend(vp, uiop, cred, fufh, 0);
+ error = fuse_write_directbackend(vp, uiop, cred, fufh,
+ filesize, 0);
if (error == EINTR || error == ETIMEDOUT
|| (!error && (bp->b_flags & B_NEEDCOMMIT))) {
Modified: projects/fuse2/sys/fs/fuse/fuse_node.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_node.c Wed May 15 00:15:40 2019 (r347602)
+++ projects/fuse2/sys/fs/fuse/fuse_node.c Wed May 15 00:38:52 2019 (r347603)
@@ -143,7 +143,6 @@ fuse_vnode_init(struct vnode *vp, struct fuse_vnode_da
fvdat->nid = nodeid;
LIST_INIT(&fvdat->handles);
vattr_null(&fvdat->cached_attrs);
- fvdat->filesize = FUSE_FILESIZE_UNINITIALIZED;
if (nodeid == FUSE_ROOT_ID) {
vp->v_vflag |= VV_ROOT;
}
@@ -363,7 +362,8 @@ fuse_vnode_savesize(struct vnode *vp, struct ucred *cr
fsai->valid = 0;
/* Truncate to a new value. */
- fsai->size = fvdat->filesize;
+ MPASS((fvdat->flag & FN_SIZECHANGE) != 0);
+ fsai->size = fvdat->cached_attrs.va_size;
fsai->valid |= FATTR_SIZE;
fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
@@ -379,25 +379,11 @@ fuse_vnode_savesize(struct vnode *vp, struct ucred *cr
return err;
}
+/*
+ * Adjust the vnode's size to a new value, such as that provided by
+ * FUSE_GETATTR.
+ */
int
-fuse_vnode_refreshsize(struct vnode *vp, struct ucred *cred)
-{
-
- struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct vattr va;
- int err;
-
- if ((fvdat->flag & FN_SIZECHANGE) != 0 ||
- fuse_data_cache_mode == FUSE_CACHE_UC ||
- fvdat->filesize != FUSE_FILESIZE_UNINITIALIZED)
- return 0;
-
- err = fuse_internal_getattr(vp, &va, cred, curthread);
- SDT_PROBE2(fusefs, , node, trace, 1, "refreshed file size");
- return err;
-}
-
-int
fuse_vnode_setsize(struct vnode *vp, struct ucred *cred, off_t newsize)
{
struct fuse_vnode_data *fvdat = VTOFUD(vp);
@@ -410,8 +396,8 @@ fuse_vnode_setsize(struct vnode *vp, struct ucred *cre
ASSERT_VOP_ELOCKED(vp, "fuse_vnode_setsize");
iosize = fuse_iosize(vp);
- oldsize = fvdat->filesize;
- fvdat->filesize = newsize;
+ oldsize = fvdat->cached_attrs.va_size;
+ fvdat->cached_attrs.va_size = newsize;
if ((attrs = VTOVA(vp)) != NULL)
attrs->va_size = newsize;
fvdat->flag |= FN_SIZECHANGE;
@@ -445,4 +431,22 @@ out:
brelse(bp);
vnode_pager_setsize(vp, newsize);
return err;
+}
+
+/* Get the current, possibly dirty, size of the file */
+int
+fuse_vnode_size(struct vnode *vp, off_t *filesize, struct ucred *cred,
+ struct thread *td)
+{
+ struct fuse_vnode_data *fvdat = VTOFUD(vp);
+ int error = 0;
+
+ if (!(fvdat->flag & FN_SIZECHANGE) &&
+ (VTOVA(vp) == NULL || fvdat->cached_attrs.va_size == VNOVAL))
+ error = fuse_internal_do_getattr(vp, NULL, cred, td);
+
+ if (!error)
+ *filesize = fvdat->cached_attrs.va_size;
+
+ return error;
}
Modified: projects/fuse2/sys/fs/fuse/fuse_node.h
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_node.h Wed May 15 00:15:40 2019 (r347602)
+++ projects/fuse2/sys/fs/fuse/fuse_node.h Wed May 15 00:38:52 2019 (r347603)
@@ -68,11 +68,14 @@
#define FN_REVOKED 0x00000020
#define FN_FLUSHINPROG 0x00000040
#define FN_FLUSHWANT 0x00000080
+/*
+ * Indicates that the file's size is dirty; the kernel has changed it but not
+ * yet send the change to the daemon. When this bit is set, the
+ * cache_attrs.va_size field does not time out
+ */
#define FN_SIZECHANGE 0x00000100
#define FN_DIRECTIO 0x00000200
-#define FUSE_FILESIZE_UNINITIALIZED -1
-
struct fuse_vnode_data {
/** self **/
uint64_t nid;
@@ -91,12 +94,6 @@ struct fuse_vnode_data {
/* The monotonic time after which the attr cache is invalid */
struct bintime attr_cache_timeout;
struct vattr cached_attrs;
- /*
- * File size according to the kernel, not the daemon.
- * May differ from cached_attrs.st_size due to write caching. Unlike
- * cached_attrs.st_size, filesize never expires.
- */
- off_t filesize;
uint64_t nlookup;
enum vtype vtype;
};
@@ -138,6 +135,9 @@ fuse_vnode_setparent(struct vnode *vp, struct vnode *d
}
}
+int fuse_vnode_size(struct vnode *vp, off_t *filesize, struct ucred *cred,
+ struct thread *td);
+
void fuse_vnode_destroy(struct vnode *vp);
int fuse_vnode_get(struct mount *mp, struct fuse_entry_out *feo,
@@ -146,8 +146,6 @@ int fuse_vnode_get(struct mount *mp, struct fuse_entry
void fuse_vnode_open(struct vnode *vp, int32_t fuse_open_flags,
struct thread *td);
-
-int fuse_vnode_refreshsize(struct vnode *vp, struct ucred *cred);
int fuse_vnode_savesize(struct vnode *vp, struct ucred *cred, pid_t pid);
Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_vnops.c Wed May 15 00:15:40 2019 (r347602)
+++ projects/fuse2/sys/fs/fuse/fuse_vnops.c Wed May 15 00:38:52 2019 (r347603)
@@ -1052,7 +1052,7 @@ fuse_vnop_lookup(struct vop_lookup_args *ap)
*/
fvdat = VTOFUD(vp);
if (vnode_isreg(vp) &&
- filesize != fvdat->filesize) {
+ filesize != fvdat->cached_attrs.va_size) {
/*
* The FN_SIZECHANGE flag reflects a dirty
* append. If userspace lets us know our cache
@@ -1704,18 +1704,7 @@ fuse_vnop_strategy(struct vop_strategy_args *ap)
bufdone(bp);
return 0;
}
- if (bp->b_iocmd == BIO_WRITE) {
- int err;
- err = fuse_vnode_refreshsize(vp, NOCRED);
- if (err) {
- bp->b_ioflags |= BIO_ERROR;
- bp->b_error = err;
- bufdone(bp);
- return 0;
- }
- }
-
/*
* VOP_STRATEGY always returns zero and signals error via bp->b_ioflags.
* fuse_io_strategy sets bp's error fields
@@ -1788,14 +1777,10 @@ fuse_vnop_write(struct vop_write_args *ap)
int ioflag = ap->a_ioflag;
struct ucred *cred = ap->a_cred;
pid_t pid = curthread->td_proc->p_pid;
- int err;
if (fuse_isdeadfs(vp)) {
return ENXIO;
}
- err = fuse_vnode_refreshsize(vp, cred);
- if (err)
- return err;
if (VTOFUD(vp)->flag & FN_DIRECTIO) {
ioflag |= IO_DIRECT;
More information about the svn-src-projects
mailing list