aboutsummaryrefslogtreecommitdiff
path: root/tests/sys/fs/fusefs/utils.hh
diff options
context:
space:
mode:
authorAlan Somers <asomers@FreeBSD.org>2019-09-15 04:14:31 +0000
committerAlan Somers <asomers@FreeBSD.org>2019-09-15 04:14:31 +0000
commit00228becc8ebad2862e404ad3565af17d780814d (patch)
tree4788caf8875462758660b49560b0b7fd7d62db93 /tests/sys/fs/fusefs/utils.hh
parent23601245ba59be11e52227838b997ae61841f2ba (diff)
downloadsrc-00228becc8ebad2862e404ad3565af17d780814d.tar.gz
src-00228becc8ebad2862e404ad3565af17d780814d.zip
MFC the new fusefs driver
MFC r350665, r350990, r350992, r351039, r351042, r351061, r351066, r351113, r351560, r351961, r351963, r352021, r352025, r352230 r350665: fusefs: merge from projects/fuse2 This commit imports the new fusefs driver. It raises the protocol level from 7.8 to 7.23, fixes many bugs, adds a test suite for the driver, and adds many new features. New features include: * Optional kernel-side permissions checks (-o default_permissions) * Implement VOP_MKNOD, VOP_BMAP, and VOP_ADVLOCK * Allow interrupting FUSE operations * Support named pipes and unix-domain sockets in fusefs file systems * Forward UTIME_NOW during utimensat(2) to the daemon * kqueue support for /dev/fuse * Allow updating mounts with "mount -u" * Allow exporting fusefs file systems over NFS * Server-initiated invalidation of the name cache or data cache * Respect RLIMIT_FSIZE * Try to support servers as old as protocol 7.4 Performance enhancements include: * Implement FUSE's FOPEN_KEEP_CACHE and FUSE_ASYNC_READ flags * Cache file attributes * Cache lookup entries, both positive and negative * Server-selectable cache modes: writethrough, writeback, or uncached * Write clustering * Readahead * Use counter(9) for statistical reporting PR: 199934 216391 233783 234581 235773 235774 235775 PR: 236226 236231 236236 236291 236329 236381 236405 PR: 236327 236466 236472 236473 236474 236530 236557 PR: 236560 236844 237052 237181 237588 238565 Reviewed by: bcr (man pages) Reviewed by: cem, ngie, rpokala, glebius, kib, bde, emaste (post-commit review on project branch) Relnotes: yes Sponsored by: The FreeBSD Foundation Pull Request: https://reviews.freebsd.org/D21110 r350990: fusefs: add SVN Keywords to the test files Reported by: SVN pre-commit hooks MFC-With: r350665 Sponsored by: The FreeBSD Foundation r350992: fusefs: skip some tests when unsafe aio is disabled MFC-With: r350665 Sponsored by: The FreeBSD Foundation r351039: fusefs: fix intermittency in the default_permissions.Unlink.ok test The test needs to expect a FUSE_FORGET operation. Most of the time the test would pass anyway, because by chance FUSE_FORGET would arrive after the unmount. MFC-With: 350665 Sponsored by: The FreeBSD Foundation r351042: fusefs: Fix the size of fuse_getattr_in In FUSE protocol 7.9, the size of the FUSE_GETATTR request has increased. However, the fusefs driver is currently not sending the additional fields. In our implementation, the additional fields are always zero, so I there haven't been any test failures until now. But fusefs-lkl requires the request's length to be correct. Fix this bug, and also enhance the test suite to catch similar bugs. PR: 239830 MFC-With: 350665 Sponsored by: The FreeBSD Foundation r351061: fusefs: fix the 32-bit build after 351042 Reported by: jhb MFC-With: 351042 Sponsored by: The FreeBSD Foundation r351066: fusefs: fix conditional from r351061 The entirety of r351061 was a copy/paste error. I'm sorry I've been comitting so hastily. Reported by: rpokala Reviewed by: rpokala MFC-With: 351061 Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D21265 r351113: fusefs: don't send the namespace during listextattr The FUSE_LISTXATTR operation always returns the full list of a file's extended attributes, in all namespaces. There's no way to filter the list server-side. However, currently FreeBSD's fusefs driver sends a namespace string with the FUSE_LISTXATTR request. That behavior was probably copied from fuse_vnop_getextattr, which has an attribute name argument. It's been there ever since extended attribute support was added in r324620. This commit removes it. Reviewed by: cem Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D21280 r351560: fusefs: Fix some bugs regarding the size of the LISTXATTR list * A small error in r338152 let to the returned size always being exactly eight bytes too large. * The FUSE_LISTXATTR operation works like Linux's listxattr(2): if the caller does not provide enough space, then the server should return ERANGE rather than return a truncated list. That's true even though in FUSE's case the kernel doesn't provide space to the client at all; it simply requests a maximum size for the list. We previously weren't handling the case where the server returns ERANGE even though the kernel requested as much size as the server had told us it needs; that can happen due to a race. * We also need to ensure that a pathological server that always returns ERANGE no matter what size we request in FUSE_LISTXATTR won't cause an infinite loop in the kernel. As of this commit, it will instead cause an infinite loop that exits and enters the kernel on each iteration, allowing signals to be processed. Reviewed by: cem Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D21287 r351961: Coverity fixes in fusefs(5) CID 1404532 fixes a signed vs unsigned comparison error in fuse_vnop_bmap. It could potentially have resulted in VOP_BMAP reporting too many consecutive blocks. CID 1404364 is much worse. It was an array access by an untrusted, user-provided variable. It could potentially have resulted in a malicious file system crashing the kernel or worse. Reported by: Coverity Reviewed by: emaste Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D21466 r351963: fusefs: coverity cleanup in the tests Address the following defects reported by Coverity: * Structurally dead code (CID 1404366): set m_quit before FAIL, not after * Unchecked return value of sysctlbyname (CID 1404321) * Unchecked return value of stat(2) (CID 1404471) * Unchecked return value of open(2) (CID 1404402, 1404529) * Unchecked return value of dup(2) (CID 1404478) * Buffer overflows. These are all false positives caused by the fact that Coverity thinks I'm using a buffer to store strings, when in fact I'm really just using it to store a byte array that happens to be initialized with a string. I'm changing the type from char to uint8_t in the hopes that it will placate Coverity. (CID 1404338, 1404350, 1404367, 1404376, 1404379, 1404381, 1404388, 1404403, 1404425, 1404433, 1404434, 1404474, 1404480, 1404484, 1404503, 1404505) * False positive file descriptor leak. I'm going to try to fix this with Coverity modeling, but I'll also change an EXPECT to ASSERT so we don't perform meaningless assertions after the failure. (CID 1404320, 1404324, 1404440, 1404445). * Unannotated file descriptor leak. This will be followed up by a Coverity modeling change. (CID 1404326, 1404334, 1404336, 1404357, 1404361, 1404372, 1404391, 1404395, 1404409, 1404430, 1404448, 1404451, 1404455, 1404457, 1404458, 1404460) * Uninitialized variables in C++ constructors (CID 1404327, 1404346). In the case of m_maxphys, this actually led to part of the FUSE_INIT's response being set to stack garbage during the WriteCluster::clustering test. * Uninitialized sun_len field in struct sockaddr_un (CID 1404330, 1404371, 1404429). Reported by: Coverity Reviewed by: emaste Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D21457 r352021: fusefs: suppress some Coverity resource leak CIDs in the tests The fusefs tests deliberately leak file descriptors. To do otherwise would add extra complications to the tests' mock FUSE server. This annotation should hopefully convince Coverity to shut up about the leaks. Reviewed by: uqs Sponsored by: The FreeBSD Foundation r352025: mount_fusefs: fix a segfault on memory allocation failure Reported by: Coverity Coverity CID: 1354188 Sponsored by: The FreeBSD Foundation r352230: fusefs: Fix iosize for FUSE_WRITE in 7.8 compat mode When communicating with a FUSE server that implements version 7.8 (or older) of the FUSE protocol, the FUSE_WRITE request structure is 16 bytes shorter than normal. The protocol version check wasn't applied universally, leading to an extra 16 bytes being sent to such servers. The extra bytes were allocated and bzero()d, so there was no information disclosure. Reviewed by: emaste MFC-With: r350665 Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D21557
Notes
Notes: svn path=/stable/12/; revision=352351
Diffstat (limited to 'tests/sys/fs/fusefs/utils.hh')
-rw-r--r--tests/sys/fs/fusefs/utils.hh243
1 files changed, 243 insertions, 0 deletions
diff --git a/tests/sys/fs/fusefs/utils.hh b/tests/sys/fs/fusefs/utils.hh
new file mode 100644
index 000000000000..518f294fbab3
--- /dev/null
+++ b/tests/sys/fs/fusefs/utils.hh
@@ -0,0 +1,243 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 The FreeBSD Foundation
+ *
+ * This software was developed by BFF Storage Systems, LLC under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+struct _sem;
+typedef struct _sem sem_t;
+struct _dirdesc;
+typedef struct _dirdesc DIR;
+
+/* Nanoseconds to sleep, for tests that must */
+#define NAP_NS (100'000'000)
+
+void get_unprivileged_id(uid_t *uid, gid_t *gid);
+inline void nap()
+{
+ usleep(NAP_NS / 1000);
+}
+
+bool is_unsafe_aio_enabled(void);
+
+extern const uint32_t libfuse_max_write;
+extern const uint32_t default_max_write;
+class FuseTest : public ::testing::Test {
+ protected:
+ uint32_t m_maxreadahead;
+ uint32_t m_maxwrite;
+ uint32_t m_init_flags;
+ bool m_allow_other;
+ bool m_default_permissions;
+ uint32_t m_kernel_minor_version;
+ enum poll_method m_pm;
+ bool m_push_symlinks_in;
+ bool m_ro;
+ bool m_async;
+ bool m_noclusterr;
+ bool m_nointr;
+ unsigned m_time_gran;
+ MockFS *m_mock = NULL;
+ const static uint64_t FH = 0xdeadbeef1a7ebabe;
+
+ public:
+ int m_maxbcachebuf;
+ int m_maxphys;
+
+ FuseTest():
+ m_maxreadahead(0),
+ m_maxwrite(default_max_write),
+ m_init_flags(0),
+ m_allow_other(false),
+ m_default_permissions(false),
+ m_kernel_minor_version(FUSE_KERNEL_MINOR_VERSION),
+ m_pm(BLOCKING),
+ m_push_symlinks_in(false),
+ m_ro(false),
+ m_async(false),
+ m_noclusterr(false),
+ m_nointr(false),
+ m_time_gran(1),
+ m_maxbcachebuf(0),
+ m_maxphys(0)
+ {}
+
+ virtual void SetUp();
+
+ virtual void TearDown() {
+ if (m_mock)
+ delete m_mock;
+ }
+
+ /*
+ * 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);
+
+ /* Expect FUSE_DESTROY and shutdown the daemon */
+ void expect_destroy(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_FORGET will be called for the given
+ * inode. There will be no response. If sem is provided, it will be
+ * posted after the operation is received by the daemon.
+ */
+ void expect_forget(uint64_t ino, uint64_t nlookup, sem_t *sem = NULL);
+
+ /*
+ * Create an expectation that FUSE_GETATTR will be called for the given
+ * inode any number of times. It will respond with a few basic
+ * attributes, like the given size and the mode S_IFREG | 0644
+ */
+ void expect_getattr(uint64_t ino, uint64_t size);
+
+ /*
+ * Create an expectation that FUSE_LOOKUP will be called for the given
+ * path exactly times times and cache validity period. It will respond
+ * with inode ino, mode mode, filesize size.
+ */
+ void expect_lookup(const char *relpath, uint64_t ino, mode_t mode,
+ uint64_t size, int times, uint64_t attr_valid = UINT64_MAX,
+ uid_t uid = 0, gid_t gid = 0);
+
+ /* The protocol 7.8 version of expect_lookup */
+ void expect_lookup_7_8(const char *relpath, uint64_t ino, mode_t mode,
+ uint64_t size, int times, uint64_t attr_valid = UINT64_MAX,
+ uid_t uid = 0, gid_t gid = 0);
+
+ /*
+ * Create an expectation that FUSE_OPEN will be called for the given
+ * inode exactly times times. It will return with open_flags flags and
+ * file handle FH.
+ */
+ void expect_open(uint64_t ino, uint32_t flags, int times);
+
+ /*
+ * Create an expectation that FUSE_OPENDIR will be called exactly once
+ * for inode ino.
+ */
+ void expect_opendir(uint64_t ino);
+
+ /*
+ * Create an expectation that FUSE_READ will be called exactly once for
+ * the given inode, at offset offset and with size isize. It will
+ * return the first osize bytes from contents
+ *
+ * Protocol 7.8 tests can use this same expectation method because
+ * nothing currently validates the size of the fuse_read_in struct.
+ */
+ void expect_read(uint64_t ino, uint64_t offset, uint64_t isize,
+ uint64_t osize, const void *contents, int flags = -1);
+
+ /*
+ * Create an expectation that FUSE_READIR will be called any number of
+ * times on the given ino with the given offset, returning (by copy)
+ * the provided entries
+ */
+ void expect_readdir(uint64_t ino, uint64_t off,
+ std::vector<struct dirent> &ents);
+
+ /*
+ * Create an expectation that FUSE_RELEASE will be called exactly once
+ * for the given inode and filehandle, returning success
+ */
+ void expect_release(uint64_t ino, uint64_t fh);
+
+ /*
+ * Create an expectation that FUSE_RELEASEDIR will be called exactly
+ * once for the given inode
+ */
+ void expect_releasedir(uint64_t ino, ProcessMockerT r);
+
+ /*
+ * Create an expectation that FUSE_UNLINK will be called exactly once
+ * for the given path, returning an errno
+ */
+ void expect_unlink(uint64_t parent, const char *path, int error);
+
+ /*
+ * Create an expectation that FUSE_WRITE will be called exactly once
+ * 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_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, const void *contents);
+
+ /*
+ * Helper that runs code in a child process.
+ *
+ * First, parent_func runs in the parent process.
+ * Then, child_func runs in the child process, dropping privileges if
+ * desired.
+ * Finally, fusetest_fork returns.
+ *
+ * # Returns
+ *
+ * fusetest_fork may SKIP the test, which the caller should detect with
+ * the IsSkipped() method. If not, then the child's exit status will
+ * be returned in status.
+ */
+ void fork(bool drop_privs, int *status,
+ std::function<void()> parent_func,
+ std::function<int()> child_func);
+
+ /*
+ * Deliberately leak a file descriptor.
+ *
+ * Closing a file descriptor on fusefs would cause the server to
+ * receive FUSE_CLOSE and possibly FUSE_INACTIVE. Handling those
+ * operations would needlessly complicate most tests. So most tests
+ * deliberately leak the file descriptors instead. This method serves
+ * to document the leakage, and provide a single point of suppression
+ * for static analyzers.
+ */
+ /* coverity[+close: arg-0] */
+ static void leak(int fd __unused) {}
+
+ /*
+ * Deliberately leak a DIR* pointer
+ *
+ * See comments for FuseTest::leak
+ */
+ static void leakdir(DIR* dirp __unused) {}
+};