Author: asomers
Date: Mon Mar  9 01:57:21 2020
New Revision: 358798
URL: https://svnweb.freebsd.org/changeset/base/358798

Log:
  fusefs: fix fsync for files with multiple open handles
  
  We were reusing a structure for multiple operations, but failing to
  reinitialize one member.  The result is that a server that cares about FUSE
  file handle IDs would see one correct FUSE_FSYNC operation, and one with the
  FHID unset.
  
  PR:           244431
  Reported by:  Agata <chog...@gmail.com>
  MFC after:    2 weeks

Modified:
  head/sys/fs/fuse/fuse_internal.c
  head/tests/sys/fs/fusefs/fsync.cc

Modified: head/sys/fs/fuse/fuse_internal.c
==============================================================================
--- head/sys/fs/fuse/fuse_internal.c    Mon Mar  9 00:14:09 2020        
(r358797)
+++ head/sys/fs/fuse/fuse_internal.c    Mon Mar  9 01:57:21 2020        
(r358798)
@@ -345,6 +345,7 @@ fuse_internal_fsync(struct vnode *vp,
         * which file handle the caller is really referring to.
         */
        LIST_FOREACH(fufh, &fvdat->handles, next) {
+               fdi.iosize = sizeof(*ffsi);
                if (ffsi == NULL)
                        fdisp_make_vp(&fdi, op, vp, td, NULL);
                else

Modified: head/tests/sys/fs/fusefs/fsync.cc
==============================================================================
--- head/tests/sys/fs/fusefs/fsync.cc   Mon Mar  9 00:14:09 2020        
(r358797)
+++ head/tests/sys/fs/fusefs/fsync.cc   Mon Mar  9 01:57:21 2020        
(r358798)
@@ -52,7 +52,7 @@ using namespace testing;
 
 class Fsync: public FuseTest {
 public:
-void expect_fsync(uint64_t ino, uint32_t flags, int error)
+void expect_fsync(uint64_t ino, uint32_t flags, int error, int times = 1)
 {
        EXPECT_CALL(*m_mock, process(
                ResultOf([=](auto in) {
@@ -67,12 +67,13 @@ void expect_fsync(uint64_t ino, uint32_t flags, int er
                                in.body.fsync.fsync_flags == flags);
                }, Eq(true)),
                _)
-       ).WillOnce(Invoke(ReturnErrno(error)));
+       ).Times(times)
+       .WillRepeatedly(Invoke(ReturnErrno(error)));
 }
 
-void expect_lookup(const char *relpath, uint64_t ino)
+void expect_lookup(const char *relpath, uint64_t ino, int times = 1)
 {
-       FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 0, 1);
+       FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 0, times);
 }
 
 void expect_write(uint64_t ino, uint64_t size, const void *contents)
@@ -257,4 +258,30 @@ TEST_F(Fsync, fsync)
        ASSERT_EQ(0, fsync(fd)) << strerror(errno);
 
        leak(fd);
+}
+
+/* If multiple FUSE file handles are active, we must fsync them all */
+TEST_F(Fsync, two_handles)
+{
+       const char FULLPATH[] = "mountpoint/some_file.txt";
+       const char RELPATH[] = "some_file.txt";
+       const char *CONTENTS = "abcdefgh";
+       ssize_t bufsize = strlen(CONTENTS);
+       uint64_t ino = 42;
+       int fd1, fd2;
+
+       expect_lookup(RELPATH, ino, 2);
+       expect_open(ino, 0, 2);
+       expect_write(ino, bufsize, CONTENTS);
+       expect_fsync(ino, 0, 0, 2);
+
+       fd1 = open(FULLPATH, O_WRONLY);
+       ASSERT_LE(0, fd1) << strerror(errno);
+       fd2 = open(FULLPATH, O_RDONLY);
+       ASSERT_LE(0, fd2) << strerror(errno);
+       ASSERT_EQ(bufsize, write(fd1, CONTENTS, bufsize)) << strerror(errno);
+       ASSERT_EQ(0, fsync(fd1)) << strerror(errno);
+
+       leak(fd1);
+       leak(fd2);
 }
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to