Date: Mon, 27 May 2019 21:36:28 +0000 (UTC) From: Alan Somers <asomers@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r348313 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs Message-ID: <201905272136.x4RLaSKY035361@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: asomers Date: Mon May 27 21:36:28 2019 New Revision: 348313 URL: https://svnweb.freebsd.org/changeset/base/348313 Log: fusefs: set FUSE_WRITE_CACHE when writing from cache This bit tells the server that we're not sure which uid, gid, and/or pid originated the write. I don't know of a single file system that cares, but it's part of the protocol. Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/sys/fs/fuse/fuse_io.c projects/fuse2/tests/sys/fs/fusefs/default_permissions.cc projects/fuse2/tests/sys/fs/fusefs/fsync.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_io.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_io.c Mon May 27 20:22:54 2019 (r348312) +++ projects/fuse2/sys/fs/fuse/fuse_io.c Mon May 27 21:36:28 2019 (r348313) @@ -119,7 +119,7 @@ fuse_read_biobackend(struct vnode *vp, struct uio *uio static int fuse_write_directbackend(struct vnode *vp, struct uio *uio, struct ucred *cred, struct fuse_filehandle *fufh, off_t filesize, - int ioflag); + int ioflag, bool pages); static int fuse_write_biobackend(struct vnode *vp, struct uio *uio, struct ucred *cred, struct fuse_filehandle *fufh, int ioflag, pid_t pid); @@ -245,7 +245,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, - filesize, ioflag); + filesize, ioflag, pages); } else { SDT_PROBE2(fusefs, , io, trace, 1, "buffered write of vnode"); @@ -405,7 +405,7 @@ out: static int fuse_write_directbackend(struct vnode *vp, struct uio *uio, struct ucred *cred, struct fuse_filehandle *fufh, off_t filesize, - int ioflag) + int ioflag, bool pages) { struct fuse_vnode_data *fvdat = VTOFUD(vp); struct fuse_data *data; @@ -418,9 +418,29 @@ fuse_write_directbackend(struct vnode *vp, struct uio int diff; int err = 0; bool direct_io = fufh->fuse_open_flags & FOPEN_DIRECT_IO; + uint32_t write_flags; data = fuse_get_mpdata(vp->v_mount); + /* + * Don't set FUSE_WRITE_LOCKOWNER in write_flags. It can't be set + * accurately when using POSIX AIO, libfuse doesn't use it, and I'm not + * aware of any file systems that do. It was an attempt to add + * Linux-style mandatory locking to the FUSE protocol, but mandatory + * locking is deprecated even on Linux. See Linux commit + * f33321141b273d60cbb3a8f56a5489baad82ba5e . + */ + /* + * Set FUSE_WRITE_CACHE whenever we don't know the uid, gid, and/or pid + * that originated a write. For example when writing from the + * writeback cache. I don't know of a single file system that cares, + * but the protocol says we're supposed to do this. + */ + write_flags = !pages && ( + (ioflag & IO_DIRECT) || + !fsess_opt_datacache(vnode_mount(vp)) || + fuse_data_cache_mode != FUSE_CACHE_WB) ? 0 : FUSE_WRITE_CACHE; + if (uio->uio_resid == 0) return (0); @@ -439,17 +459,8 @@ fuse_write_directbackend(struct vnode *vp, struct uio fwi->fh = fufh->fh_id; fwi->offset = uio->uio_offset; fwi->size = chunksize; + fwi->write_flags = write_flags; if (fuse_libabi_geq(data, 7, 9)) { - /* - * Don't set FUSE_WRITE_LOCKOWNER. It can't be set - * accurately when using POSIX AIO, libfuse doesn't use - * it, and I'm not aware of any file systems that do. - * It was an attempt to add Linux-style mandatory - * locking to the FUSE protocol, but mandatory locking - * is deprecated even on Linux. See Linux commit - * f33321141b273d60cbb3a8f56a5489baad82ba5e . - */ - fwi->write_flags = 0; fwi->flags = 0; /* TODO */ fwi_data = (char *)fdi.indata + sizeof(*fwi); } else { @@ -525,6 +536,7 @@ retry: fwi->fh = fufh->fh_id; fwi->offset = as_written_offset; fwi->size = diff; + fwi->write_flags = write_flags; goto retry; } } @@ -884,7 +896,7 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp) uiop->uio_rw = UIO_WRITE; error = fuse_write_directbackend(vp, uiop, cred, fufh, - filesize, 0); + filesize, 0, false); if (error == EINTR || error == ETIMEDOUT || (!error && (bp->b_flags & B_NEEDCOMMIT))) { Modified: projects/fuse2/tests/sys/fs/fusefs/default_permissions.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/default_permissions.cc Mon May 27 20:22:54 2019 (r348312) +++ projects/fuse2/tests/sys/fs/fusefs/default_permissions.cc Mon May 27 21:36:28 2019 (r348313) @@ -1229,7 +1229,7 @@ TEST_F(Write, clear_suid) expect_getattr(1, S_IFDIR | 0755, UINT64_MAX, 1); expect_lookup(RELPATH, ino, S_IFREG | oldmode, UINT64_MAX); expect_open(ino, 0, 1); - expect_write(ino, 0, sizeof(wbuf), sizeof(wbuf), 0, wbuf); + expect_write(ino, 0, sizeof(wbuf), sizeof(wbuf), 0, 0, wbuf); expect_chmod(ino, newmode, sizeof(wbuf)); fd = open(FULLPATH, O_WRONLY); @@ -1255,7 +1255,7 @@ TEST_F(Write, clear_sgid) expect_getattr(1, S_IFDIR | 0755, UINT64_MAX, 1); expect_lookup(RELPATH, ino, S_IFREG | oldmode, UINT64_MAX); expect_open(ino, 0, 1); - expect_write(ino, 0, sizeof(wbuf), sizeof(wbuf), 0, wbuf); + expect_write(ino, 0, sizeof(wbuf), sizeof(wbuf), 0, 0, wbuf); expect_chmod(ino, newmode, sizeof(wbuf)); fd = open(FULLPATH, O_WRONLY); @@ -1285,7 +1285,7 @@ TEST_F(Write, recursion_panic_while_clearing_suid) expect_getattr(1, S_IFDIR | 0755, UINT64_MAX, 1); expect_lookup(RELPATH, ino, S_IFREG | oldmode, UINT64_MAX); expect_open(ino, 0, 1); - expect_write(ino, 0, sizeof(wbuf), sizeof(wbuf), 0, wbuf); + expect_write(ino, 0, sizeof(wbuf), sizeof(wbuf), 0, 0, wbuf); /* XXX Return a smaller file size than what we just wrote! */ expect_chmod(ino, newmode, 0); Modified: projects/fuse2/tests/sys/fs/fusefs/fsync.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/fsync.cc Mon May 27 20:22:54 2019 (r348312) +++ projects/fuse2/tests/sys/fs/fusefs/fsync.cc Mon May 27 21:36:28 2019 (r348313) @@ -75,7 +75,7 @@ void expect_lookup(const char *relpath, uint64_t ino) void expect_write(uint64_t ino, uint64_t size, const void *contents) { - FuseTest::expect_write(ino, 0, size, size, 0, contents); + FuseTest::expect_write(ino, 0, size, size, 0, 0, contents); } }; Modified: projects/fuse2/tests/sys/fs/fusefs/utils.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/utils.cc Mon May 27 20:22:54 2019 (r348312) +++ projects/fuse2/tests/sys/fs/fusefs/utils.cc Mon May 27 21:36:28 2019 (r348313) @@ -377,15 +377,17 @@ void FuseTest::expect_unlink(uint64_t parent, const ch } void FuseTest::expect_write(uint64_t ino, uint64_t offset, uint64_t isize, - uint64_t osize, uint32_t flags, const void *contents) + uint64_t osize, uint32_t flags_set, uint32_t flags_unset, + const void *contents) { EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { const char *buf = (const char*)in.body.bytes + sizeof(struct fuse_write_in); bool pid_ok; + uint32_t wf = in.body.write.write_flags; - if (in.body.write.write_flags & FUSE_WRITE_CACHE) + if (wf & FUSE_WRITE_CACHE) pid_ok = true; else pid_ok = (pid_t)in.header.pid == getpid(); @@ -396,7 +398,8 @@ void FuseTest::expect_write(uint64_t ino, uint64_t off in.body.write.offset == offset && in.body.write.size == isize && pid_ok && - in.body.write.write_flags == flags && + (wf & flags_set) == flags_set && + (wf & flags_unset) == 0 && 0 == bcmp(buf, contents, isize)); }, Eq(true)), _) @@ -407,7 +410,7 @@ void FuseTest::expect_write(uint64_t ino, uint64_t off } void FuseTest::expect_write_7_8(uint64_t ino, uint64_t offset, uint64_t isize, - uint64_t osize, uint32_t flags, const void *contents) + uint64_t osize, const void *contents) { EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { @@ -420,7 +423,6 @@ void FuseTest::expect_write_7_8(uint64_t ino, uint64_t in.body.write.offset == offset && in.body.write.size == isize && pid_ok && - in.body.write.write_flags == flags && 0 == bcmp(buf, contents, isize)); }, Eq(true)), _) Modified: projects/fuse2/tests/sys/fs/fusefs/utils.hh ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/utils.hh Mon May 27 20:22:54 2019 (r348312) +++ projects/fuse2/tests/sys/fs/fusefs/utils.hh Mon May 27 21:36:28 2019 (r348313) @@ -169,15 +169,18 @@ class FuseTest : public ::testing::Test { /* * Create an expectation that FUSE_WRITE will be called exactly once - * for the given inode, at offset offset, with write_flags flags, - * size isize and buffer contents. It will return osize + * for the given inode, at offset offset, with size isize and buffer + * contents. Any flags present in flags_set must be set, and any + * present in flags_unset must not be set. Other flags are don't care. + * It will return osize. */ void expect_write(uint64_t ino, uint64_t offset, uint64_t isize, - uint64_t osize, uint32_t flags, const void *contents); + uint64_t osize, uint32_t flags_set, uint32_t flags_unset, + const void *contents); /* Protocol 7.8 version of expect_write */ void expect_write_7_8(uint64_t ino, uint64_t offset, uint64_t isize, - uint64_t osize, uint32_t flags, const void *contents); + uint64_t osize, const void *contents); /* * Helper that runs code in a child process. Modified: projects/fuse2/tests/sys/fs/fusefs/write.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/write.cc Mon May 27 20:22:54 2019 (r348312) +++ projects/fuse2/tests/sys/fs/fusefs/write.cc Mon May 27 21:36:28 2019 (r348313) @@ -65,6 +65,12 @@ void expect_release(uint64_t ino, ProcessMockerT r) ).WillRepeatedly(Invoke(r)); } +void expect_write(uint64_t ino, uint64_t offset, uint64_t isize, + uint64_t osize, const void *contents) +{ + FuseTest::expect_write(ino, offset, isize, osize, 0, 0, contents); +} + }; class Write_7_8: public FuseTest { @@ -100,7 +106,7 @@ virtual void SetUp() { /* Tests for the write-through cache mode */ class WriteThrough: public Write { - +public: virtual void SetUp() { const char *cache_mode_node = "vfs.fusefs.data_cache_mode"; int val = 0; @@ -117,11 +123,17 @@ virtual void SetUp() { "(writethrough) for this test"; } +void expect_write(uint64_t ino, uint64_t offset, uint64_t isize, + uint64_t osize, const void *contents) +{ + FuseTest::expect_write(ino, offset, isize, osize, 0, FUSE_WRITE_CACHE, + contents); +} }; /* Tests for the writeback cache mode */ class WriteBack: public Write { - +public: virtual void SetUp() { const char *node = "vfs.fusefs.data_cache_mode"; int val = 0; @@ -138,6 +150,12 @@ virtual void SetUp() { "(writeback) for this test"; } +void expect_write(uint64_t ino, uint64_t offset, uint64_t isize, + uint64_t osize, const void *contents) +{ + FuseTest::expect_write(ino, offset, isize, osize, FUSE_WRITE_CACHE, 0, + contents); +} }; /* AIO writes need to set the header's pid field correctly */ @@ -155,7 +173,7 @@ TEST_F(AioWrite, DISABLED_aio_write) expect_lookup(RELPATH, ino, 0); expect_open(ino, 0, 1); - expect_write(ino, offset, bufsize, bufsize, 0, CONTENTS); + expect_write(ino, offset, bufsize, bufsize, CONTENTS); fd = open(FULLPATH, O_WRONLY); EXPECT_LE(0, fd) << strerror(errno); @@ -196,7 +214,7 @@ TEST_F(Write, append) expect_lookup(RELPATH, ino, initial_offset); expect_open(ino, 0, 1); - expect_write(ino, initial_offset, BUFSIZE, BUFSIZE, 0, CONTENTS); + expect_write(ino, initial_offset, BUFSIZE, BUFSIZE, CONTENTS); /* Must open O_RDWR or fuse(4) implicitly sets direct_io */ fd = open(FULLPATH, O_RDWR | O_APPEND); @@ -218,7 +236,7 @@ TEST_F(Write, append_direct_io) expect_lookup(RELPATH, ino, initial_offset); expect_open(ino, FOPEN_DIRECT_IO, 1); - expect_write(ino, initial_offset, BUFSIZE, BUFSIZE, 0, CONTENTS); + expect_write(ino, initial_offset, BUFSIZE, BUFSIZE, CONTENTS); fd = open(FULLPATH, O_WRONLY | O_APPEND); EXPECT_LE(0, fd) << strerror(errno); @@ -242,7 +260,7 @@ TEST_F(Write, direct_io_evicts_cache) expect_lookup(RELPATH, ino, bufsize); expect_open(ino, 0, 1); expect_read(ino, 0, bufsize, bufsize, CONTENTS0); - expect_write(ino, 0, bufsize, bufsize, 0, CONTENTS1); + expect_write(ino, 0, bufsize, bufsize, CONTENTS1); fd = open(FULLPATH, O_RDWR); EXPECT_LE(0, fd) << strerror(errno); @@ -285,9 +303,8 @@ TEST_F(Write, indirect_io_short_write) expect_lookup(RELPATH, ino, 0); expect_open(ino, 0, 1); - expect_write(ino, 0, bufsize, bufsize0, 0, CONTENTS); - expect_write(ino, bufsize0, bufsize1, bufsize1, 0, - contents1); + expect_write(ino, 0, bufsize, bufsize0, CONTENTS); + expect_write(ino, bufsize0, bufsize1, bufsize1, contents1); fd = open(FULLPATH, O_WRONLY); EXPECT_LE(0, fd) << strerror(errno); @@ -312,7 +329,7 @@ TEST_F(Write, direct_io_short_write) expect_lookup(RELPATH, ino, 0); expect_open(ino, FOPEN_DIRECT_IO, 1); - expect_write(ino, 0, bufsize, halfbufsize, 0, CONTENTS); + expect_write(ino, 0, bufsize, halfbufsize, CONTENTS); fd = open(FULLPATH, O_WRONLY); EXPECT_LE(0, fd) << strerror(errno); @@ -342,7 +359,7 @@ TEST_F(Write, direct_io_short_write_iov) expect_lookup(RELPATH, ino, 0); expect_open(ino, FOPEN_DIRECT_IO, 1); - expect_write(ino, 0, totalsize, size0, 0, EXPECTED0); + expect_write(ino, 0, totalsize, size0, EXPECTED0); fd = open(FULLPATH, O_WRONLY); EXPECT_LE(0, fd) << strerror(errno); @@ -388,9 +405,8 @@ TEST_F(Write, mmap) /* * Writes from the pager may or may not be associated with the correct * pid, so they must set FUSE_WRITE_CACHE. - * TODO: expect FUSE_WRITE_CACHE after upgrading to protocol 7.9 */ - expect_write(ino, 0, len, len, 0, expected); + FuseTest::expect_write(ino, 0, len, len, FUSE_WRITE_CACHE, 0, expected); expect_flush(ino, 1, ReturnErrno(0)); expect_release(ino, ReturnErrno(0)); @@ -435,7 +451,7 @@ TEST_F(WriteThrough, evicts_read_cache) expect_lookup(RELPATH, ino, bufsize); expect_open(ino, 0, 1); expect_read(ino, 0, bufsize, bufsize, contents0); - expect_write(ino, 0, wrsize, wrsize, 0, contents1); + expect_write(ino, 0, wrsize, wrsize, contents1); fd = open(FULLPATH, O_RDWR); EXPECT_LE(0, fd) << strerror(errno); @@ -468,7 +484,7 @@ TEST_F(WriteThrough, pwrite) expect_lookup(RELPATH, ino, 0); expect_open(ino, 0, 1); - expect_write(ino, offset, bufsize, bufsize, 0, CONTENTS); + expect_write(ino, offset, bufsize, bufsize, CONTENTS); fd = open(FULLPATH, O_WRONLY); EXPECT_LE(0, fd) << strerror(errno); @@ -489,7 +505,7 @@ TEST_F(Write, write) expect_lookup(RELPATH, ino, 0); expect_open(ino, 0, 1); - expect_write(ino, 0, bufsize, bufsize, 0, CONTENTS); + expect_write(ino, 0, bufsize, bufsize, CONTENTS); fd = open(FULLPATH, O_WRONLY); EXPECT_LE(0, fd) << strerror(errno); @@ -518,8 +534,8 @@ TEST_F(Write, write_large) expect_lookup(RELPATH, ino, 0); expect_open(ino, 0, 1); - expect_write(ino, 0, halfbufsize, halfbufsize, 0, contents); - expect_write(ino, halfbufsize, halfbufsize, halfbufsize, 0, + expect_write(ino, 0, halfbufsize, halfbufsize, contents); + expect_write(ino, halfbufsize, halfbufsize, halfbufsize, &contents[halfbufsize / sizeof(int)]); fd = open(FULLPATH, O_WRONLY); @@ -561,7 +577,7 @@ TEST_F(Write_7_8, write) expect_lookup(RELPATH, ino, 0); expect_open(ino, 0, 1); - expect_write_7_8(ino, 0, bufsize, bufsize, 0, CONTENTS); + expect_write_7_8(ino, 0, bufsize, bufsize, CONTENTS); fd = open(FULLPATH, O_WRONLY); EXPECT_LE(0, fd) << strerror(errno); @@ -582,7 +598,7 @@ TEST_F(WriteBack, close) expect_lookup(RELPATH, ino, 0); expect_open(ino, 0, 1); - expect_write(ino, 0, bufsize, bufsize, 0, CONTENTS); + expect_write(ino, 0, bufsize, bufsize, CONTENTS); EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { return (in.header.opcode == FUSE_SETATTR); @@ -621,7 +637,7 @@ TEST_F(WriteBack, rmw) FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1); expect_open(ino, 0, 1); expect_read(ino, 0, fsize, fsize, INITIAL); - expect_write(ino, offset, bufsize, bufsize, 0, CONTENTS); + expect_write(ino, offset, bufsize, bufsize, CONTENTS); fd = open(FULLPATH, O_WRONLY); EXPECT_LE(0, fd) << strerror(errno); @@ -646,7 +662,7 @@ TEST_F(WriteBack, writeback) expect_lookup(RELPATH, ino, 0); expect_open(ino, 0, 1); - expect_write(ino, 0, bufsize, bufsize, 0, CONTENTS); + expect_write(ino, 0, bufsize, bufsize, CONTENTS); fd = open(FULLPATH, O_RDWR); EXPECT_LE(0, fd) << strerror(errno); @@ -678,7 +694,8 @@ TEST_F(WriteBack, o_direct) expect_lookup(RELPATH, ino, 0); expect_open(ino, 0, 1); - expect_write(ino, 0, bufsize, bufsize, 0, CONTENTS); + FuseTest::expect_write(ino, 0, bufsize, bufsize, 0, FUSE_WRITE_CACHE, + CONTENTS); expect_read(ino, 0, bufsize, bufsize, CONTENTS); fd = open(FULLPATH, O_RDWR | O_DIRECT); @@ -711,7 +728,7 @@ TEST_F(WriteThrough, DISABLED_writethrough) expect_lookup(RELPATH, ino, 0); expect_open(ino, 0, 1); - expect_write(ino, 0, bufsize, bufsize, 0, CONTENTS); + expect_write(ino, 0, bufsize, bufsize, CONTENTS); fd = open(FULLPATH, O_RDWR); EXPECT_LE(0, fd) << strerror(errno); @@ -738,7 +755,7 @@ TEST_F(WriteThrough, update_file_size) expect_lookup(RELPATH, ino, 0); expect_open(ino, 0, 1); - expect_write(ino, 0, bufsize, bufsize, 0, CONTENTS); + expect_write(ino, 0, bufsize, bufsize, CONTENTS); fd = open(FULLPATH, O_RDWR); EXPECT_LE(0, fd) << strerror(errno);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201905272136.x4RLaSKY035361>