From nobody Sat Jan 24 16:04:11 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4dz03b4KXsz6Q0Q7 for ; Sat, 24 Jan 2026 16:04:11 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4dz03b362Lz3vPn for ; Sat, 24 Jan 2026 16:04:11 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1769270651; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=yyOv+3f9T9kmwkivQGwP6zpjQdu4hiPa5zBTA3oVbR8=; b=MmD+N9MNo2UtKd6KqfjQ/cocWsy+frvOrhNMRqIng79GiVd2jJCBJ9ZDTJbLCRaRN3tO+s ifB01L+QCdeGq4YzK7Ctg/hFxCitirVCj0Tu411mXbMqmqP2SfzWpSZ03DEr4CGo1dwXpZ FFZbYlXOWBniT33Scat/Dasw3fdtK0d1HmobB3zUbvU4AQXyGiL2OVU10NhgAMKRrYBT/W e68PKyZPT8ACxToTqvfTfsMP90llI040sDFW0gYt+8dffWfCMgmmFG2DuJykBg2BJcNeug mnrb7vZfsQ9VGCjmsWUYwSNW+A/4FMUfsFXYYLOl9S74MOCnfbOMAlAJS5N5AQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1769270651; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=yyOv+3f9T9kmwkivQGwP6zpjQdu4hiPa5zBTA3oVbR8=; b=Jz6Lwo38Lmb5n4EQ9na5gypb4KRqNaLhM0tiHWwhTnYsK4tnA3lF0vdLd5xmhKDUZhpuQa aXk6qfrlMALS2GOHakVj5+9JUrLmjlssfKcmxkCuN9kW25DDTlmvGTE27fbczbLEbJuL71 Slfqh5DluMi+nBLFJ+37iSDreEeAEzpxCOHFvLFL+UfKygXrvOJw8baHLewm2tkQ00xUou c68oJARnp9k26tKcz3MUn8t7s8M+1VhSx6hg/d/ndPM8sLc5yWIymnLmIhj6TtqEIC80xc QXGgOMCRYS7NvlN6c3aup+evUAbZviEIC3+RQhhdqvcEMb4vr1t33tDzKBYCFA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1769270651; a=rsa-sha256; cv=none; b=rgdDxjsfhQqx3SQKHxwZJRznNGedhPjG/sHFL/ME5FUkzQV8JinZy4lzMK8pLN14A3K8Na f4rquyi2hTKZcaSV7DiOYlLVo91AlPWvaazxpS0BlHV+3UG5K8CnMj8KuYzBn2DHdjyEep oGBIHcTpQUOgI/ouXBlRPKg+xXxjhhlcY+4glHXuePPobLKppsCkG23B69KEAwz5UcZTU/ sfWQd+0F8mBpK3m0+gkK/14nCnmz2ZDBUwYtMw6jAoKN9LHbEd7i5IdqddtPb2bdu9WJ5+ PaKoHMX/UqEBIbVkklGGwm+Os+z8ZhWE81DiMFfufujl5PCO8F4XU54ke9wtTA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4dz03b2j5Pz19wH for ; Sat, 24 Jan 2026 16:04:11 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 370f4 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sat, 24 Jan 2026 16:04:11 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Alan Somers Subject: git: ffb747d587bf - main - fusefs: Add tests for the new -o auto_unmount feature List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: asomers X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: ffb747d587bf09a982df67fba322b91d02f70be6 Auto-Submitted: auto-generated Date: Sat, 24 Jan 2026 16:04:11 +0000 Message-Id: <6974ed7b.370f4.686ccfdc@gitrepo.freebsd.org> The branch main has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=ffb747d587bf09a982df67fba322b91d02f70be6 commit ffb747d587bf09a982df67fba322b91d02f70be6 Author: Alan Somers AuthorDate: 2026-01-19 19:11:46 +0000 Commit: Alan Somers CommitDate: 2026-01-24 16:02:33 +0000 fusefs: Add tests for the new -o auto_unmount feature Add tests for mount_fusefs's new -o auto_unmount feature, recently added by arrowd. MFC with: 10037d0978f "fusefs: Implement support for the auto_unmount" --- tests/sys/fs/fusefs/destroy.cc | 81 ++++++++++++++++++++++++++++++++++++++++++ tests/sys/fs/fusefs/mockfs.cc | 12 ++++++- tests/sys/fs/fusefs/mockfs.hh | 5 ++- tests/sys/fs/fusefs/utils.cc | 8 ++++- tests/sys/fs/fusefs/utils.hh | 5 +++ 5 files changed, 108 insertions(+), 3 deletions(-) diff --git a/tests/sys/fs/fusefs/destroy.cc b/tests/sys/fs/fusefs/destroy.cc index 45acb1f99724..0c8e2fd22a50 100644 --- a/tests/sys/fs/fusefs/destroy.cc +++ b/tests/sys/fs/fusefs/destroy.cc @@ -29,6 +29,9 @@ */ extern "C" { +#include +#include + #include #include #include @@ -45,6 +48,30 @@ class Destroy: public FuseTest {}; /* Tests for unexpected deaths of the server */ class Death: public FuseTest{}; +/* Tests for the auto_unmount mount option*/ +class AutoUnmount: public FuseTest { +virtual void SetUp() { + m_auto_unmount = true; + FuseTest::SetUp(); +} + +protected: +/* Unmounting fusefs might be asynchronous with close, so use a retry loop */ +void assert_unmounted() { + struct statfs statbuf; + + for (int retry = 100; retry > 0; retry--) { + ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno); + if (strcmp("fusefs", statbuf.f_fstypename) != 0 && + strcmp("/dev/fuse", statbuf.f_mntfromname) != 0) + return; + nap(); + } + FAIL() << "fusefs is still mounted"; +} + +}; + static void* open_th(void* arg) { int fd; const char *path = (const char*)arg; @@ -55,6 +82,60 @@ static void* open_th(void* arg) { return 0; } +/* + * With the auto_unmount mount option, the kernel will automatically unmount + * the file system when the server dies. + */ +TEST_F(AutoUnmount, auto_unmount) +{ + /* Kill the daemon */ + m_mock->kill_daemon(); + + /* Use statfs to check that the file system is no longer mounted */ + assert_unmounted(); +} + +/* + * When -o auto_unmount is used, the kernel should _not_ unmount the file + * system when any /dev/fuse file descriptor is closed, but only for the last + * one. + */ +TEST_F(AutoUnmount, dup) +{ + struct statfs statbuf; + int fuse2; + + EXPECT_CALL(*m_mock, process( + ResultOf([](auto in) { + return (in.header.opcode == FUSE_STATFS); + }, Eq(true)), + _) + ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) { + SET_OUT_HEADER_LEN(out, statfs); + }))); + + fuse2 = dup_dev_fuse(); + + /* + * Close one of the /dev/fuse file descriptors. Close the duplicate + * first so the daemon thread doesn't freak out when it gets a bunch of + * EBADF errors. + */ + close(fuse2); + + /* Use statfs to check that the file system is still mounted */ + ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno); + EXPECT_EQ(0, strcmp("fusefs", statbuf.f_fstypename)); + EXPECT_EQ(0, strcmp("/dev/fuse", statbuf.f_mntfromname)); + + /* + * Close the original file descriptor too. Now the file system should be + * unmounted at last. + */ + m_mock->kill_daemon(); + assert_unmounted(); +} + /* * The server dies with unsent operations still on the message queue. * Check for any memory leaks like this: diff --git a/tests/sys/fs/fusefs/mockfs.cc b/tests/sys/fs/fusefs/mockfs.cc index ee47d9e0e01c..b9e4afbbea0b 100644 --- a/tests/sys/fs/fusefs/mockfs.cc +++ b/tests/sys/fs/fusefs/mockfs.cc @@ -426,7 +426,8 @@ MockFS::MockFS(int max_read, int max_readahead, bool allow_other, bool push_symlinks_in, bool ro, enum poll_method pm, uint32_t flags, uint32_t kernel_minor_version, uint32_t max_write, bool async, bool noclusterr, unsigned time_gran, bool nointr, bool noatime, - const char *fsname, const char *subtype, bool no_auto_init) + const char *fsname, const char *subtype, bool no_auto_init, + bool auto_unmount) : m_daemon_id(NULL), m_kernel_minor_version(kernel_minor_version), m_kq(pm == KQ ? kqueue() : -1), @@ -519,6 +520,10 @@ MockFS::MockFS(int max_read, int max_readahead, bool allow_other, build_iovec(&iov, &iovlen, "intr", __DECONST(void*, &trueval), sizeof(bool)); } + if (auto_unmount) { + build_iovec(&iov, &iovlen, "auto_unmount", + __DECONST(void*, &trueval), sizeof(bool)); + } if (*fsname) { build_iovec(&iov, &iovlen, "fsname=", __DECONST(void*, fsname), -1); @@ -787,6 +792,11 @@ void MockFS::init(uint32_t flags) { write(m_fuse_fd, out.get(), out->header.len); } +int MockFS::dup_dev_fuse() +{ + return (dup(m_fuse_fd)); +} + void MockFS::kill_daemon() { m_quit = true; if (m_daemon_id != NULL) diff --git a/tests/sys/fs/fusefs/mockfs.hh b/tests/sys/fs/fusefs/mockfs.hh index 00503332f820..c8f90c2f5402 100644 --- a/tests/sys/fs/fusefs/mockfs.hh +++ b/tests/sys/fs/fusefs/mockfs.hh @@ -372,10 +372,13 @@ class MockFS { uint32_t kernel_minor_version, uint32_t max_write, bool async, bool no_clusterr, unsigned time_gran, bool nointr, bool noatime, const char *fsname, const char *subtype, - bool no_auto_init); + bool no_auto_init, bool auto_unmount); virtual ~MockFS(); + /* Duplicate the /dev/fuse file descriptor, and return the duplicate */ + int dup_dev_fuse(); + /* Kill the filesystem daemon without unmounting the filesystem */ void kill_daemon(); diff --git a/tests/sys/fs/fusefs/utils.cc b/tests/sys/fs/fusefs/utils.cc index 125b7e2d6fc7..93b850a7b7e3 100644 --- a/tests/sys/fs/fusefs/utils.cc +++ b/tests/sys/fs/fusefs/utils.cc @@ -152,7 +152,7 @@ void FuseTest::SetUp() { m_pm, m_init_flags, m_kernel_minor_version, m_maxwrite, m_async, m_noclusterr, m_time_gran, m_nointr, m_noatime, m_fsname, m_subtype, - m_no_auto_init); + m_no_auto_init, m_auto_unmount); /* * FUSE_ACCESS is called almost universally. Expecting it in * each test case would be super-annoying. Instead, set a @@ -571,6 +571,12 @@ get_unprivileged_id(uid_t *uid, gid_t *gid) *gid = gr->gr_gid; } +int +FuseTest::dup_dev_fuse() +{ + return (m_mock->dup_dev_fuse()); +} + void FuseTest::fork(bool drop_privs, int *child_status, std::function parent_func, diff --git a/tests/sys/fs/fusefs/utils.hh b/tests/sys/fs/fusefs/utils.hh index 91bbba909672..ebd8d41d6961 100644 --- a/tests/sys/fs/fusefs/utils.hh +++ b/tests/sys/fs/fusefs/utils.hh @@ -70,6 +70,7 @@ class FuseTest : public ::testing::Test { bool m_noclusterr; bool m_nointr; bool m_no_auto_init; + bool m_auto_unmount; unsigned m_time_gran; MockFS *m_mock = NULL; const static uint64_t FH = 0xdeadbeef1a7ebabe; @@ -97,6 +98,7 @@ class FuseTest : public ::testing::Test { m_noclusterr(false), m_nointr(false), m_no_auto_init(false), + m_auto_unmount(false), m_time_gran(1), m_fsname(""), m_subtype(""), @@ -234,6 +236,9 @@ class FuseTest : public ::testing::Test { void expect_write_7_8(uint64_t ino, uint64_t offset, uint64_t isize, uint64_t osize, const void *contents); + /* Duplicate the /dev/fuse file descriptor, and return the duplicate */ + int dup_dev_fuse(); + /* * Helper that runs code in a child process. *