Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 May 2019 00:38:53 +0000 (UTC)
From:      Alan Somers <asomers@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r347603 - projects/fuse2/sys/fs/fuse
Message-ID:  <201905150038.x4F0crjD002086@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201905150038.x4F0crjD002086>