git: 616eaa66aa49 - main - fusefs: add a test for the subtype= option

From: Alan Somers <asomers_at_FreeBSD.org>
Date: Fri, 29 Apr 2022 14:01:22 UTC
The branch main has been updated by asomers:

URL: https://cgit.FreeBSD.org/src/commit/?id=616eaa66aa4955f182eb0117e17e07da76fcf696

commit 616eaa66aa4955f182eb0117e17e07da76fcf696
Author:     Alan Somers <asomers@FreeBSD.org>
AuthorDate: 2022-04-29 13:59:29 +0000
Commit:     Alan Somers <asomers@FreeBSD.org>
CommitDate: 2022-04-29 13:59:29 +0000

    fusefs: add a test for the subtype= option
    
    At mount time server can set, for example, "subtype=xfs", so that
    mount(8) will later show the mountpoint's file system as "fusefs.xfs".
    fusefs has had this feature ever since the original GSoC commit in 2012,
    but there's never been a test for it.
    
    MFC after:      2 weeks
---
 tests/sys/fs/fusefs/mockfs.cc |  7 ++++++-
 tests/sys/fs/fusefs/mockfs.hh |  2 +-
 tests/sys/fs/fusefs/mount.cc  | 34 ++++++++++++++++++++++++++++++++--
 tests/sys/fs/fusefs/utils.cc  |  2 +-
 tests/sys/fs/fusefs/utils.hh  |  2 ++
 5 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/tests/sys/fs/fusefs/mockfs.cc b/tests/sys/fs/fusefs/mockfs.cc
index ddfb5527ef13..4eebbc2200b0 100644
--- a/tests/sys/fs/fusefs/mockfs.cc
+++ b/tests/sys/fs/fusefs/mockfs.cc
@@ -409,7 +409,8 @@ void MockFS::debug_response(const mockfs_buf_out &out) {
 MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions,
 	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)
+	bool noclusterr, unsigned time_gran, bool nointr, bool noatime,
+	const char *subtype)
 {
 	struct sigaction sa;
 	struct iovec *iov = NULL;
@@ -500,6 +501,10 @@ MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions,
 		build_iovec(&iov, &iovlen, "intr",
 			__DECONST(void*, &trueval), sizeof(bool));
 	}
+	if (*subtype) {
+		build_iovec(&iov, &iovlen, "subtype=",
+			__DECONST(void*, subtype), -1);
+	}
 	if (nmount(iov, iovlen, 0))
 		throw(std::system_error(errno, std::system_category(),
 			"Couldn't mount filesystem"));
diff --git a/tests/sys/fs/fusefs/mockfs.hh b/tests/sys/fs/fusefs/mockfs.hh
index d471491ea455..3c8a78e85072 100644
--- a/tests/sys/fs/fusefs/mockfs.hh
+++ b/tests/sys/fs/fusefs/mockfs.hh
@@ -361,7 +361,7 @@ class MockFS {
 		enum poll_method pm, uint32_t flags,
 		uint32_t kernel_minor_version, uint32_t max_write, bool async,
 		bool no_clusterr, unsigned time_gran, bool nointr,
-		bool noatime);
+		bool noatime, const char *subtype);
 
 	virtual ~MockFS();
 
diff --git a/tests/sys/fs/fusefs/mount.cc b/tests/sys/fs/fusefs/mount.cc
index 217fd1d554e8..d736377536cb 100644
--- a/tests/sys/fs/fusefs/mount.cc
+++ b/tests/sys/fs/fusefs/mount.cc
@@ -43,8 +43,28 @@ extern "C" {
 
 using namespace testing;
 
-class UpdateOk: public FuseTest, public WithParamInterface<const char*> {};
-class UpdateErr: public FuseTest, public WithParamInterface<const char*> {};
+class Mount: public FuseTest {
+public:
+void expect_statfs() {
+	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);
+	})));
+}
+};
+class Subtype: public Mount {
+	void SetUp() {
+		m_subtype = "myfs";
+		Mount::SetUp();
+	}
+};
+
+class UpdateOk: public Mount, public WithParamInterface<const char*> {};
+class UpdateErr: public Mount, public WithParamInterface<const char*> {};
 
 int mntflag_from_string(const char *s)
 {
@@ -64,6 +84,16 @@ int mntflag_from_string(const char *s)
 		return 0;
 }
 
+TEST_F(Subtype, subtype)
+{
+	struct statfs statbuf;
+
+	expect_statfs();
+
+	ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno);
+	ASSERT_EQ(0, strcmp("fusefs.myfs", statbuf.f_fstypename));
+}
+
 /* Some mount options can be changed by mount -u */
 TEST_P(UpdateOk, update)
 {
diff --git a/tests/sys/fs/fusefs/utils.cc b/tests/sys/fs/fusefs/utils.cc
index 65738f4b19a4..0d42f418c369 100644
--- a/tests/sys/fs/fusefs/utils.cc
+++ b/tests/sys/fs/fusefs/utils.cc
@@ -161,7 +161,7 @@ void FuseTest::SetUp() {
 			m_default_permissions, m_push_symlinks_in, m_ro,
 			m_pm, m_init_flags, m_kernel_minor_version,
 			m_maxwrite, m_async, m_noclusterr, m_time_gran,
-			m_nointr, m_noatime);
+			m_nointr, m_noatime, m_subtype);
 		/* 
 		 * FUSE_ACCESS is called almost universally.  Expecting it in
 		 * each test case would be super-annoying.  Instead, set a
diff --git a/tests/sys/fs/fusefs/utils.hh b/tests/sys/fs/fusefs/utils.hh
index 1cd7bad97998..7d30f2b233ab 100644
--- a/tests/sys/fs/fusefs/utils.hh
+++ b/tests/sys/fs/fusefs/utils.hh
@@ -74,6 +74,7 @@ class FuseTest : public ::testing::Test {
 	MockFS *m_mock = NULL;
 	const static uint64_t FH = 0xdeadbeef1a7ebabe;
 	const char *reclaim_mib = "debug.try_reclaim_vnode";
+	const char *m_subtype;
 
 	public:
 	int m_maxbcachebuf;
@@ -94,6 +95,7 @@ class FuseTest : public ::testing::Test {
 		m_noclusterr(false),
 		m_nointr(false),
 		m_time_gran(1),
+		m_subtype(""),
 		m_maxbcachebuf(0),
 		m_maxphys(0)
 	{}