svn commit: r345852 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs

Alan Somers asomers at FreeBSD.org
Wed Apr 3 19:59:49 UTC 2019


Author: asomers
Date: Wed Apr  3 19:59:45 2019
New Revision: 345852
URL: https://svnweb.freebsd.org/changeset/base/345852

Log:
  fusefs: send FUSE_FLUSH during VOP_CLOSE
  
  The FUSE protocol says that FUSE_FLUSH should be send every time a file
  descriptor is closed.  That's not quite possible in FreeBSD because multiple
  file descriptors can share a single struct file, and closef doesn't call
  fo_close until the last close.  However, we can still send FUSE_FLUSH on
  every VOP_CLOSE, which is probably good enough.
  
  There are two purposes for FUSE_FLUSH.  One is to allow file systems to
  return EIO if they have an error when writing data that's cached
  server-side.  The other is to release POSIX file locks (which fusefs(5) does
  not yet support).
  
  PR:		236405, 236327
  Sponsored by:	The FreeBSD Foundation

Modified:
  projects/fuse2/sys/fs/fuse/fuse_file.c
  projects/fuse2/sys/fs/fuse/fuse_file.h
  projects/fuse2/sys/fs/fuse/fuse_io.c
  projects/fuse2/sys/fs/fuse/fuse_node.c
  projects/fuse2/sys/fs/fuse/fuse_vnops.c
  projects/fuse2/tests/sys/fs/fusefs/allow_other.cc
  projects/fuse2/tests/sys/fs/fusefs/flush.cc
  projects/fuse2/tests/sys/fs/fusefs/fsync.cc
  projects/fuse2/tests/sys/fs/fusefs/mockfs.cc
  projects/fuse2/tests/sys/fs/fusefs/open.cc
  projects/fuse2/tests/sys/fs/fusefs/release.cc
  projects/fuse2/tests/sys/fs/fusefs/utils.cc
  projects/fuse2/tests/sys/fs/fusefs/utils.hh
  projects/fuse2/tests/sys/fs/fusefs/write.cc

Modified: projects/fuse2/sys/fs/fuse/fuse_file.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_file.c	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/sys/fs/fuse/fuse_file.c	Wed Apr  3 19:59:45 2019	(r345852)
@@ -273,12 +273,14 @@ fuse_filehandle_validrw(struct vnode *vp, int mode,
 }
 
 int
-fuse_filehandle_get(struct vnode *vp, fufh_type_t fufh_type,
+fuse_filehandle_get(struct vnode *vp, int fflag,
     struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
 {
 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
 	struct fuse_filehandle *fufh;
+	fufh_type_t fufh_type;
 
+	fufh_type = fflags_2_fufh_type(fflag);
 	if (cred == NULL)
 		goto fallback;
 
@@ -307,14 +309,14 @@ found:
 }
 
 int
-fuse_filehandle_getrw(struct vnode *vp, fufh_type_t fufh_type,
+fuse_filehandle_getrw(struct vnode *vp, int fflag,
     struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
 {
 	int err;
 
-	err = fuse_filehandle_get(vp, fufh_type, fufhp, cred, pid);
+	err = fuse_filehandle_get(vp, fflag, fufhp, cred, pid);
 	if (err)
-		err = fuse_filehandle_get(vp, FUFH_RDWR, fufhp, cred, pid);
+		err = fuse_filehandle_get(vp, FREAD | FWRITE, fufhp, cred, pid);
 	return err;
 }
 

Modified: projects/fuse2/sys/fs/fuse/fuse_file.h
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_file.h	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/sys/fs/fuse/fuse_file.h	Wed Apr  3 19:59:45 2019	(r345852)
@@ -150,10 +150,10 @@ struct fuse_filehandle {
 
 bool fuse_filehandle_validrw(struct vnode *vp, int mode,
 	struct ucred *cred, pid_t pid);
-int fuse_filehandle_get(struct vnode *vp, fufh_type_t fufh_type,
+int fuse_filehandle_get(struct vnode *vp, int fflag,
                         struct fuse_filehandle **fufhp, struct ucred *cred,
 			pid_t pid);
-int fuse_filehandle_getrw(struct vnode *vp, fufh_type_t fufh_type,
+int fuse_filehandle_getrw(struct vnode *vp, int fflag,
                           struct fuse_filehandle **fufhp, struct ucred *cred,
 			  pid_t pid);
 

Modified: projects/fuse2/sys/fs/fuse/fuse_io.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_io.c	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/sys/fs/fuse/fuse_io.c	Wed Apr  3 19:59:45 2019	(r345852)
@@ -127,12 +127,12 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, in
 {
 	struct fuse_filehandle *fufh;
 	int err, directio;
-	fufh_type_t fufh_type;
+	int fflag;
 
 	MPASS(vp->v_type == VREG || vp->v_type == VDIR);
 
-	fufh_type = (uio->uio_rw == UIO_READ) ? FUFH_RDONLY : FUFH_WRONLY;
-	err = fuse_filehandle_getrw(vp, fufh_type, &fufh, cred, pid);
+	fflag = (uio->uio_rw == UIO_READ) ? FREAD : FWRITE;
+	err = fuse_filehandle_getrw(vp, fflag, &fufh, cred, pid);
 	if (err) {
 		printf("FUSE: io dispatch: filehandles are closed\n");
 		return err;
@@ -643,7 +643,7 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp)
 	struct uio uio;
 	struct iovec io;
 	int error = 0;
-	fufh_type_t fufh_type;
+	int fflag;
 	/* We don't know the true pid when we're dealing with the cache */
 	pid_t pid = 0;
 
@@ -652,9 +652,9 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp)
 	MPASS(vp->v_type == VREG || vp->v_type == VDIR);
 	MPASS(bp->b_iocmd == BIO_READ || bp->b_iocmd == BIO_WRITE);
 
-	fufh_type = bp->b_iocmd == BIO_READ ? FUFH_RDONLY : FUFH_WRONLY;
+	fflag = bp->b_iocmd == BIO_READ ? FREAD : FWRITE;
 	cred = bp->b_iocmd == BIO_READ ? bp->b_rcred : bp->b_wcred;
-	error = fuse_filehandle_getrw(vp, fufh_type, &fufh, cred, pid);
+	error = fuse_filehandle_getrw(vp, fflag, &fufh, cred, pid);
 	if (bp->b_iocmd == BIO_READ && error == EBADF) {
 		/* 
 		 * This may be a read-modify-write operation on a cached file
@@ -662,8 +662,7 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp)
 		 *
 		 * TODO: eliminate this hacky check once the FUFH table is gone
 		 */
-		fufh_type = FUFH_WRONLY;
-		error = fuse_filehandle_get(vp, fufh_type, &fufh, cred, pid);
+		error = fuse_filehandle_get(vp, FWRITE, &fufh, cred, pid);
 	}
 	if (error) {
 		printf("FUSE: strategy: filehandles are closed\n");

Modified: projects/fuse2/sys/fs/fuse/fuse_node.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_node.c	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/sys/fs/fuse/fuse_node.c	Wed Apr  3 19:59:45 2019	(r345852)
@@ -378,7 +378,7 @@ fuse_vnode_savesize(struct vnode *vp, struct ucred *cr
 	fsai->size = fvdat->filesize;
 	fsai->valid |= FATTR_SIZE;
 
-	fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh, cred, pid);
+	fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
 	if (fufh) {
 		fsai->fh = fufh->fh_id;
 		fsai->valid |= FATTR_FH;

Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_vnops.c	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/sys/fs/fuse/fuse_vnops.c	Wed Apr  3 19:59:45 2019	(r345852)
@@ -221,11 +221,43 @@ static int
 fuse_filehandle_get_dir(struct vnode *vp, struct fuse_filehandle **fufhp,
 	struct ucred *cred, pid_t pid)
 {
-	if (fuse_filehandle_get(vp, FUFH_RDONLY, fufhp, cred, pid) == 0)
+	if (fuse_filehandle_get(vp, FREAD, fufhp, cred, pid) == 0)
 		return 0;
-	return fuse_filehandle_get(vp, FUFH_EXEC, fufhp, cred, pid);
+	return fuse_filehandle_get(vp, FEXEC, fufhp, cred, pid);
 }
 
+/* Send FUSE_FLUSH for this vnode */
+static int
+fuse_flush(struct vnode *vp, struct ucred *cred, pid_t pid, int fflag)
+{
+	struct fuse_flush_in *ffi;
+	struct fuse_filehandle *fufh;
+	struct fuse_dispatcher fdi;
+	struct thread *td = curthread;
+	struct mount *mp = vnode_mount(vp);
+	int err;
+
+	if (!fsess_isimpl(vnode_mount(vp), FUSE_FLUSH))
+		return 0;
+
+	err = fuse_filehandle_get(vp, fflag, &fufh, cred, pid);
+	if (err)
+		return err;
+
+	fdisp_init(&fdi, sizeof(*ffi));
+	fdisp_make_vp(&fdi, FUSE_FLUSH, vp, td, cred);
+	ffi = fdi.indata;
+	ffi->fh = fufh->fh_id;
+
+	err = fdisp_wait_answ(&fdi);
+	if (err == ENOSYS) {
+		fsess_set_notimpl(mp, FUSE_FLUSH);
+		err = 0;
+	}
+	fdisp_destroy(&fdi);
+	return err;
+}
+
 /*
     struct vnop_access_args {
 	struct vnode *a_vp;
@@ -275,7 +307,7 @@ fuse_vnop_access(struct vop_access_args *ap)
 }
 
 /*
-    struct vnop_close_args {
+    struct vop_close_args {
 	struct vnode *a_vp;
 	int  a_fflag;
 	struct ucred *a_cred;
@@ -290,6 +322,7 @@ fuse_vnop_close(struct vop_close_args *ap)
 	int fflag = ap->a_fflag;
 	struct thread *td = ap->a_td;
 	pid_t pid = td->td_proc->p_pid;
+	int err = 0;
 
 	if (fuse_isdeadfs(vp)) {
 		return 0;
@@ -297,6 +330,8 @@ fuse_vnop_close(struct vop_close_args *ap)
 	if (vnode_isdir(vp)) {
 		struct fuse_filehandle *fufh;
 
+		// XXX: what if two file descriptors have the same directory
+		// opened?  We shouldn't close the file handle too soon.
 		if (fuse_filehandle_get_dir(vp, &fufh, cred, pid) == 0)
 			fuse_filehandle_close(vp, fufh, NULL, cred);
 		return 0;
@@ -304,11 +339,12 @@ fuse_vnop_close(struct vop_close_args *ap)
 	if (fflag & IO_NDELAY) {
 		return 0;
 	}
+	err = fuse_flush(vp, cred, pid, fflag);
 	/* TODO: close the file handle, if we're sure it's no longer used */
 	if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
 		fuse_vnode_savesize(vp, cred, td->td_proc->p_pid);
 	}
-	return 0;
+	return err;
 }
 
 static void
@@ -1611,7 +1647,7 @@ fuse_vnop_setattr(struct vop_setattr_args *ap)
 		newsize = vap->va_size;
 		fsai->valid |= FATTR_SIZE;
 
-		fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh, cred, pid);
+		fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
 		if (fufh) {
 			fsai->fh = fufh->fh_id;
 			fsai->valid |= FATTR_FH;

Modified: projects/fuse2/tests/sys/fs/fusefs/allow_other.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/allow_other.cc	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/tests/sys/fs/fusefs/allow_other.cc	Wed Apr  3 19:59:45 2019	(r345852)
@@ -78,6 +78,7 @@ TEST_F(AllowOther, allowed)
 
 			expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
 			expect_open(ino, 0, 1);
+			expect_flush(ino, 1, ReturnErrno(0));
 			expect_release(ino, FH);
 			expect_getattr(ino, 0);
 		}, []() {

Modified: projects/fuse2/tests/sys/fs/fusefs/flush.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/flush.cc	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/tests/sys/fs/fusefs/flush.cc	Wed Apr  3 19:59:45 2019	(r345852)
@@ -41,7 +41,8 @@ using namespace testing;
 class Flush: public FuseTest {
 
 public:
-void expect_flush(uint64_t ino, int times, pid_t lo, ProcessMockerT r)
+void
+expect_flush(uint64_t ino, int times, pid_t lo, ProcessMockerT r)
 {
 	EXPECT_CALL(*m_mock, process(
 		ResultOf([=](auto in) {
@@ -55,9 +56,9 @@ void expect_flush(uint64_t ino, int times, pid_t lo, P
 	.WillRepeatedly(Invoke(r));
 }
 
-void expect_lookup(const char *relpath, uint64_t ino)
+void expect_lookup(const char *relpath, uint64_t ino, int times)
 {
-	FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 0, 1);
+	FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 0, times);
 }
 
 /*
@@ -82,16 +83,18 @@ class FlushWithLocks: public Flush {
 	}
 };
 
-/* If a file descriptor is duplicated, every close causes FLUSH */
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236405 */
-TEST_F(Flush, DISABLED_dup)
+/*
+ * If multiple file descriptors refer to the same file handle, closing each
+ * should send FUSE_FLUSH
+ */
+TEST_F(Flush, open_twice)
 {
 	const char FULLPATH[] = "mountpoint/some_file.txt";
 	const char RELPATH[] = "some_file.txt";
 	uint64_t ino = 42;
 	int fd, fd2;
 
-	expect_lookup(RELPATH, ino);
+	expect_lookup(RELPATH, ino, 2);
 	expect_open(ino, 0, 1);
 	expect_getattr(ino, 0);
 	expect_flush(ino, 2, 0, ReturnErrno(0));
@@ -100,10 +103,11 @@ TEST_F(Flush, DISABLED_dup)
 	fd = open(FULLPATH, O_WRONLY);
 	EXPECT_LE(0, fd) << strerror(errno);
 
-	fd2 = dup(fd);
+	fd2 = open(FULLPATH, O_WRONLY);
+	EXPECT_LE(0, fd2) << strerror(errno);
 
-	ASSERT_EQ(0, close(fd2)) << strerror(errno);
-	ASSERT_EQ(0, close(fd)) << strerror(errno);
+	EXPECT_EQ(0, close(fd2)) << strerror(errno);
+	EXPECT_EQ(0, close(fd)) << strerror(errno);
 }
 
 /*
@@ -114,15 +118,14 @@ TEST_F(Flush, DISABLED_dup)
  * all.
  */
 /* http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html */
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236405 */
-TEST_F(Flush, DISABLED_eio)
+TEST_F(Flush, eio)
 {
 	const char FULLPATH[] = "mountpoint/some_file.txt";
 	const char RELPATH[] = "some_file.txt";
 	uint64_t ino = 42;
 	int fd;
 
-	expect_lookup(RELPATH, ino);
+	expect_lookup(RELPATH, ino, 1);
 	expect_open(ino, 0, 1);
 	expect_getattr(ino, 0);
 	expect_flush(ino, 1, 0, ReturnErrno(EIO));
@@ -138,41 +141,48 @@ TEST_F(Flush, DISABLED_eio)
  * If the filesystem returns ENOSYS, it will be treated as success and
  * no more FUSE_FLUSH operations will be sent to the daemon
  */
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236405 */
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236557 */
-TEST_F(Flush, DISABLED_enosys)
+TEST_F(Flush, enosys)
 {
-	const char FULLPATH[] = "mountpoint/some_file.txt";
-	const char RELPATH[] = "some_file.txt";
-	uint64_t ino = 42;
-	int fd, fd2;
+	const char FULLPATH0[] = "mountpoint/some_file.txt";
+	const char RELPATH0[] = "some_file.txt";
+	const char FULLPATH1[] = "mountpoint/other_file.txt";
+	const char RELPATH1[] = "other_file.txt";
+	uint64_t ino0 = 42;
+	uint64_t ino1 = 43;
+	int fd0, fd1;
 
-	expect_lookup(RELPATH, ino);
-	expect_open(ino, 0, 1);
-	expect_getattr(ino, 0);
+	expect_lookup(RELPATH0, ino0, 1);
+	expect_open(ino0, 0, 1);
+	expect_getattr(ino0, 0);
 	/* On the 2nd close, FUSE_FLUSH won't be sent at all */
-	expect_flush(ino, 1, 0, ReturnErrno(ENOSYS));
+	expect_flush(ino0, 1, 0, ReturnErrno(ENOSYS));
 	expect_release();
 
-	fd = open(FULLPATH, O_WRONLY);
-	EXPECT_LE(0, fd) << strerror(errno);
+	expect_lookup(RELPATH1, ino1, 1);
+	expect_open(ino1, 0, 1);
+	expect_getattr(ino1, 0);
+	/* On the 2nd close, FUSE_FLUSH won't be sent at all */
+	expect_release();
 
-	fd2 = dup(fd);
+	fd0 = open(FULLPATH0, O_WRONLY);
+	ASSERT_LE(0, fd0) << strerror(errno);
 
-	EXPECT_EQ(0, close(fd2)) << strerror(errno);
-	EXPECT_EQ(0, close(fd)) << strerror(errno);
+	fd1 = open(FULLPATH1, O_WRONLY);
+	ASSERT_LE(0, fd1) << strerror(errno);
+
+	EXPECT_EQ(0, close(fd0)) << strerror(errno);
+	EXPECT_EQ(0, close(fd1)) << strerror(errno);
 }
 
 /* A FUSE_FLUSH should be sent on close(2) */
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236405 */
-TEST_F(Flush, DISABLED_flush)
+TEST_F(Flush, flush)
 {
 	const char FULLPATH[] = "mountpoint/some_file.txt";
 	const char RELPATH[] = "some_file.txt";
 	uint64_t ino = 42;
 	int fd;
 
-	expect_lookup(RELPATH, ino);
+	expect_lookup(RELPATH, ino, 1);
 	expect_open(ino, 0, 1);
 	expect_getattr(ino, 0);
 	expect_flush(ino, 1, 0, ReturnErrno(0));
@@ -188,7 +198,6 @@ TEST_F(Flush, DISABLED_flush)
  * When closing a file with a POSIX file lock, flush should release the lock,
  * _even_if_ it's not the process's last file descriptor for this file.
  */
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236405 */
 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=234581 */
 TEST_F(FlushWithLocks, DISABLED_unlock_on_close)
 {
@@ -199,7 +208,7 @@ TEST_F(FlushWithLocks, DISABLED_unlock_on_close)
 	struct flock fl;
 	pid_t pid = getpid();
 
-	expect_lookup(RELPATH, ino);
+	expect_lookup(RELPATH, ino, 1);
 	expect_open(ino, 0, 1);
 	expect_getattr(ino, 0);
 	EXPECT_CALL(*m_mock, process(

Modified: projects/fuse2/tests/sys/fs/fusefs/fsync.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/fsync.cc	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/tests/sys/fs/fusefs/fsync.cc	Wed Apr  3 19:59:45 2019	(r345852)
@@ -139,6 +139,7 @@ TEST_F(Fsync, close)
 		}, Eq(true)),
 		_)
 	).Times(0);
+	expect_flush(ino, 1, ReturnErrno(0));
 	expect_release(ino, FH);
 
 	fd = open(FULLPATH, O_RDWR);

Modified: projects/fuse2/tests/sys/fs/fusefs/mockfs.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/mockfs.cc	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/tests/sys/fs/fusefs/mockfs.cc	Wed Apr  3 19:59:45 2019	(r345852)
@@ -169,7 +169,8 @@ void debug_fuseop(const mockfs_buf_in *in)
 				in->body.open.flags, name);
 			break;
 		case FUSE_FLUSH:
-			printf(" lock_owner=%lu", in->body.flush.lock_owner);
+			printf(" fh=%#lx lock_owner=%lu", in->body.flush.fh,
+				in->body.flush.lock_owner);
 			break;
 		case FUSE_FORGET:
 			printf(" nlookup=%lu", in->body.forget.nlookup);

Modified: projects/fuse2/tests/sys/fs/fusefs/open.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/open.cc	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/tests/sys/fs/fusefs/open.cc	Wed Apr  3 19:59:45 2019	(r345852)
@@ -205,6 +205,7 @@ TEST_F(Open, multiple_creds)
 			SET_OUT_HEADER_LEN(out, open);
 		})));
 		expect_getattr(ino, 0);
+		expect_flush(ino, 2, ReturnErrno(0));
 		expect_release(ino, fh0);
 		expect_release(ino, fh1);
 

Modified: projects/fuse2/tests/sys/fs/fusefs/release.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/release.cc	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/tests/sys/fs/fusefs/release.cc	Wed Apr  3 19:59:45 2019	(r345852)
@@ -82,6 +82,7 @@ TEST_F(Release, dup)
 	expect_lookup(RELPATH, ino, 1);
 	expect_open(ino, 0, 1);
 	expect_getattr(ino, 0);
+	expect_flush(ino, 1, ReturnErrno(0));
 	expect_release(ino, 0, O_RDONLY, 0);
 	
 	fd = open(FULLPATH, O_RDONLY);
@@ -111,6 +112,7 @@ TEST_F(Release, eio)
 	expect_lookup(RELPATH, ino, 1);
 	expect_open(ino, 0, 1);
 	expect_getattr(ino, 0);
+	expect_flush(ino, 1, ReturnErrno(0));
 	expect_release(ino, 0, O_WRONLY, EIO);
 	
 	fd = open(FULLPATH, O_WRONLY);
@@ -133,6 +135,7 @@ TEST_F(Release, DISABLED_flags)
 	expect_lookup(RELPATH, ino, 1);
 	expect_open(ino, 0, 1);
 	expect_getattr(ino, 0);
+	expect_flush(ino, 1, ReturnErrno(0));
 	expect_release(ino, 0, O_RDWR | O_APPEND, 0);
 	
 	fd = open(FULLPATH, O_RDWR | O_APPEND);
@@ -156,6 +159,7 @@ TEST_F(Release, multiple_opens)
 	expect_lookup(RELPATH, ino, 2);
 	expect_open(ino, 0, 2);
 	expect_getattr(ino, 0);
+	expect_flush(ino, 2, ReturnErrno(0));
 	expect_release(ino, 0, O_RDONLY, 0);
 	
 	fd = open(FULLPATH, O_RDONLY);
@@ -179,6 +183,7 @@ TEST_F(Release, ok)
 	expect_lookup(RELPATH, ino, 1);
 	expect_open(ino, 0, 1);
 	expect_getattr(ino, 0);
+	expect_flush(ino, 1, ReturnErrno(0));
 	expect_release(ino, 0, O_RDONLY, 0);
 	
 	fd = open(FULLPATH, O_RDONLY);
@@ -212,6 +217,7 @@ TEST_F(ReleaseWithLocks, DISABLED_unlock_on_close)
 		SET_OUT_HEADER_LEN(out, setlk);
 		out->body.setlk.lk = in->body.setlk.lk;
 	})));
+	expect_flush(ino, 1, ReturnErrno(0));
 	expect_release(ino, (uint64_t)pid, O_RDWR, 0);
 
 	fd = open(FULLPATH, O_RDWR);

Modified: projects/fuse2/tests/sys/fs/fusefs/utils.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/utils.cc	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/tests/sys/fs/fusefs/utils.cc	Wed Apr  3 19:59:45 2019	(r345852)
@@ -114,6 +114,19 @@ FuseTest::expect_access(uint64_t ino, mode_t access_mo
 	).WillOnce(Invoke(ReturnErrno(error)));
 }
 
+void
+FuseTest::expect_flush(uint64_t ino, int times, ProcessMockerT r)
+{
+	EXPECT_CALL(*m_mock, process(
+		ResultOf([=](auto in) {
+			return (in->header.opcode == FUSE_FLUSH &&
+				in->header.nodeid == ino);
+		}, Eq(true)),
+		_)
+	).Times(times)
+	.WillRepeatedly(Invoke(r));
+}
+
 void FuseTest::expect_getattr(uint64_t ino, uint64_t size)
 {
 	/* Until the attr cache is working, we may send an additional GETATTR */

Modified: projects/fuse2/tests/sys/fs/fusefs/utils.hh
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/utils.hh	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/tests/sys/fs/fusefs/utils.hh	Wed Apr  3 19:59:45 2019	(r345852)
@@ -70,10 +70,16 @@ class FuseTest : public ::testing::Test {
 	}
 
 	/*
-	 * Create an expectation that FUSE_ACCESS will be called oncde for the
+	 * Create an expectation that FUSE_ACCESS will be called once for the
 	 * given inode with the given access_mode, returning the given errno
 	 */
 	void expect_access(uint64_t ino, mode_t access_mode, int error);
+
+	/*
+	 * Create an expectation that FUSE_FLUSH will be called times times for
+	 * the given inode
+	 */
+	void expect_flush(uint64_t ino, int times, ProcessMockerT r);
 
 	/*
 	 * Create an expectation that FUSE_GETATTR will be called for the given

Modified: projects/fuse2/tests/sys/fs/fusefs/write.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/write.cc	Wed Apr  3 19:35:07 2019	(r345851)
+++ projects/fuse2/tests/sys/fs/fusefs/write.cc	Wed Apr  3 19:59:45 2019	(r345852)
@@ -374,6 +374,7 @@ TEST_F(Write, DISABLED_mmap)
 	 * pid, so they must set FUSE_WRITE_CACHE
 	 */
 	expect_write(ino, 0, len, len, FUSE_WRITE_CACHE, expected);
+	expect_flush(ino, 1, ReturnErrno(0));
 	expect_release(ino, ReturnErrno(0));
 
 	fd = open(FULLPATH, O_RDWR);
@@ -512,6 +513,7 @@ TEST_F(WriteBack, close)
 		SET_OUT_HEADER_LEN(out, attr);
 		out->body.attr.attr.ino = ino;	// Must match nodeid
 	})));
+	expect_flush(ino, 1, ReturnErrno(0));
 	expect_release(ino, ReturnErrno(0));
 
 	fd = open(FULLPATH, O_RDWR);


More information about the svn-src-projects mailing list