git: f0f596bd955e - main - fusefs: ignore FUSE_NO_OPEN(DIR)_SUPPORT flags

From: Alan Somers <asomers_at_FreeBSD.org>
Date: Fri, 20 Dec 2024 00:10:39 UTC
The branch main has been updated by asomers:

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

commit f0f596bd955e5b48c55db502e79fc652ac8970d3
Author:     CismonX <admin@cismon.net>
AuthorDate: 2024-11-02 20:19:15 +0000
Commit:     Alan Somers <asomers@FreeBSD.org>
CommitDate: 2024-12-20 00:09:49 +0000

    fusefs: ignore FUSE_NO_OPEN(DIR)_SUPPORT flags
    
    The FUSE_NO_OPEN_SUPPORT and FUSE_NO_OPENDIR_SUPPORT flags
    are only meant to indicate kernel features, and should be ignored
    if they appear in the FUSE_INIT reply flags.
    
    Also fix the corresponding test cases.
    
    MFC after:      2 weeks
    Reviewed by:    Alan Somers <asomers@FreeBSD.org>
    Signed-off-by:  CismonX <admin@cismon.net>
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/1509
---
 sys/fs/fuse/fuse_file.c        |  9 +++------
 sys/fs/fuse/fuse_internal.c    |  4 ----
 sys/fs/fuse/fuse_ipc.h         |  2 --
 sys/fs/fuse/fuse_vnops.c       | 17 ++++++++---------
 tests/sys/fs/fusefs/open.cc    | 38 ++------------------------------------
 tests/sys/fs/fusefs/opendir.cc | 27 ++-------------------------
 6 files changed, 15 insertions(+), 82 deletions(-)

diff --git a/sys/fs/fuse/fuse_file.c b/sys/fs/fuse/fuse_file.c
index 88de12d59425..5f5819c2ccae 100644
--- a/sys/fs/fuse/fuse_file.c
+++ b/sys/fs/fuse/fuse_file.c
@@ -122,7 +122,6 @@ fuse_filehandle_open(struct vnode *vp, int a_mode,
     struct fuse_filehandle **fufhp, struct thread *td, struct ucred *cred)
 {
 	struct mount *mp = vnode_mount(vp);
-	struct fuse_data *data = fuse_get_mpdata(mp);
 	struct fuse_dispatcher fdi;
 	const struct fuse_open_out default_foo = {
 		.fh = 0,
@@ -132,12 +131,10 @@ fuse_filehandle_open(struct vnode *vp, int a_mode,
 	struct fuse_open_in *foi = NULL;
 	const struct fuse_open_out *foo;
 	fufh_type_t fufh_type;
-	int dataflags = data->dataflags;
 	int err = 0;
 	int oflags = 0;
 	int op = FUSE_OPEN;
 	int relop = FUSE_RELEASE;
-	int fsess_no_op_support = FSESS_NO_OPEN_SUPPORT;
 
 	fufh_type = fflags_2_fufh_type(a_mode);
 	oflags = fufh_type_2_fflags(fufh_type);
@@ -145,12 +142,11 @@ fuse_filehandle_open(struct vnode *vp, int a_mode,
 	if (vnode_isdir(vp)) {
 		op = FUSE_OPENDIR;
 		relop = FUSE_RELEASEDIR;
-		fsess_no_op_support = FSESS_NO_OPENDIR_SUPPORT;
 		/* vn_open_vnode already rejects FWRITE on directories */
 		MPASS(fufh_type == FUFH_RDONLY || fufh_type == FUFH_EXEC);
 	}
 	fdisp_init(&fdi, sizeof(*foi));
-	if (fsess_not_impl(mp, op) && dataflags & fsess_no_op_support) {
+	if (fsess_not_impl(mp, op)) {
 		/* The operation implicitly succeeds */
 		foo = &default_foo;
 	} else {
@@ -160,7 +156,7 @@ fuse_filehandle_open(struct vnode *vp, int a_mode,
 		foi->flags = oflags;
 
 		err = fdisp_wait_answ(&fdi);
-		if (err == ENOSYS && dataflags & fsess_no_op_support) {
+		if (err == ENOSYS) {
 			/* The operation implicitly succeeds */
 			foo = &default_foo;
 			fsess_set_notimpl(mp, op);
@@ -174,6 +170,7 @@ fuse_filehandle_open(struct vnode *vp, int a_mode,
 			goto out;
 		} else {
 			foo = fdi.answ;
+			fsess_set_impl(mp, op);
 		}
 	}
 
diff --git a/sys/fs/fuse/fuse_internal.c b/sys/fs/fuse/fuse_internal.c
index 11d7b2d3e9bb..c6354ae7150f 100644
--- a/sys/fs/fuse/fuse_internal.c
+++ b/sys/fs/fuse/fuse_internal.c
@@ -1010,10 +1010,6 @@ fuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio)
 				data->dataflags |= FSESS_POSIX_LOCKS;
 			if (fiio->flags & FUSE_EXPORT_SUPPORT)
 				data->dataflags |= FSESS_EXPORT_SUPPORT;
-			if (fiio->flags & FUSE_NO_OPEN_SUPPORT)
-				data->dataflags |= FSESS_NO_OPEN_SUPPORT;
-			if (fiio->flags & FUSE_NO_OPENDIR_SUPPORT)
-				data->dataflags |= FSESS_NO_OPENDIR_SUPPORT;
 			/* 
 			 * Don't bother to check FUSE_BIG_WRITES, because it's
 			 * redundant with max_write
diff --git a/sys/fs/fuse/fuse_ipc.h b/sys/fs/fuse/fuse_ipc.h
index 0ec556138be0..5648624f4c63 100644
--- a/sys/fs/fuse/fuse_ipc.h
+++ b/sys/fs/fuse/fuse_ipc.h
@@ -227,8 +227,6 @@ struct fuse_data {
                                          /* (and being observed by the daemon) */
 #define FSESS_PUSH_SYMLINKS_IN    0x0020 /* prefix absolute symlinks with mp */
 #define FSESS_DEFAULT_PERMISSIONS 0x0040 /* kernel does permission checking */
-#define FSESS_NO_OPEN_SUPPORT     0x0080 /* can elide FUSE_OPEN ops */
-#define FSESS_NO_OPENDIR_SUPPORT  0x0100 /* can elide FUSE_OPENDIR ops */
 #define FSESS_ASYNC_READ          0x1000 /* allow multiple reads of some file */
 #define FSESS_POSIX_LOCKS         0x2000 /* daemon supports POSIX locks */
 #define FSESS_EXPORT_SUPPORT      0x10000 /* daemon supports NFS-style lookups */
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index 30993441bd72..9c858d6c467d 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -1945,10 +1945,9 @@ fuse_vnop_readdir(struct vop_readdir_args *ap)
 	tresid = uio->uio_resid;
 	err = fuse_filehandle_get_dir(vp, &fufh, cred, pid);
 	if (err == EBADF && mp->mnt_flag & MNT_EXPORTED) {
-		KASSERT(fuse_get_mpdata(mp)->dataflags
-				& FSESS_NO_OPENDIR_SUPPORT,
-			("FUSE file systems that don't set "
-			 "FUSE_NO_OPENDIR_SUPPORT should not be exported"));
+		KASSERT(!fsess_is_impl(mp, FUSE_OPENDIR),
+			("FUSE file systems that implement "
+			 "FUSE_OPENDIR should not be exported"));
 		/* 
 		 * nfsd will do VOP_READDIR without first doing VOP_OPEN.  We
 		 * must implicitly open the directory here.
@@ -3202,21 +3201,21 @@ fuse_vnop_vptofh(struct vop_vptofh_args *ap)
 		return EOPNOTSUPP;
 	}
 	if ((mp->mnt_flag & MNT_EXPORTED) &&
-		!(data->dataflags & FSESS_NO_OPENDIR_SUPPORT))
+		fsess_is_impl(mp, FUSE_OPENDIR))
 	{
 		/*
 		 * NFS is stateless, so nfsd must reopen a directory on every
 		 * call to VOP_READDIR, passing in the d_off field from the
-		 * final dirent of the previous invocation.  But without
-		 * FUSE_NO_OPENDIR_SUPPORT, the FUSE protocol does not
+		 * final dirent of the previous invocation.  But if the server
+		 * implements FUSE_OPENDIR, the FUSE protocol does not
 		 * guarantee that d_off will be valid after a directory is
 		 * closed and reopened.  So prohibit exporting FUSE file
-		 * systems that don't set that flag.
+		 * systems that implement FUSE_OPENDIR.
 		 *
 		 * But userspace NFS servers don't have this problem.
                  */
 		SDT_PROBE2(fusefs, , vnops, trace, 1,
-			"VOP_VPTOFH without FUSE_NO_OPENDIR_SUPPORT");
+			"VOP_VPTOFH with FUSE_OPENDIR");
 		return EOPNOTSUPP;
 	}
 
diff --git a/tests/sys/fs/fusefs/open.cc b/tests/sys/fs/fusefs/open.cc
index ff736e6c3a94..1212a7047f26 100644
--- a/tests/sys/fs/fusefs/open.cc
+++ b/tests/sys/fs/fusefs/open.cc
@@ -70,14 +70,6 @@ void test_ok(int os_flags, int fuse_flags) {
 }
 };
 
-
-class OpenNoOpenSupport: public FuseTest {
-	virtual void SetUp() {
-		m_init_flags = FUSE_NO_OPEN_SUPPORT;
-		FuseTest::SetUp();
-	}
-};
-
 /* 
  * fusefs(4) does not support I/O on device nodes (neither does UFS).  But it
  * shouldn't crash
@@ -281,37 +273,11 @@ TEST_F(Open, o_rdwr)
 }
 
 /*
- * Without FUSE_NO_OPEN_SUPPORT, returning ENOSYS is an error
- */
-TEST_F(Open, enosys)
-{
-	const char FULLPATH[] = "mountpoint/some_file.txt";
-	const char RELPATH[] = "some_file.txt";
-	uint64_t ino = 42;
-	int fd;
-
-	FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
-	EXPECT_CALL(*m_mock, process(
-		ResultOf([=](auto in) {
-			return (in.header.opcode == FUSE_OPEN &&
-				in.body.open.flags == (uint32_t)O_RDONLY &&
-				in.header.nodeid == ino);
-		}, Eq(true)),
-		_)
-	).Times(1)
-	.WillOnce(Invoke(ReturnErrno(ENOSYS)));
-
-	fd = open(FULLPATH, O_RDONLY);
-	ASSERT_EQ(-1, fd) << strerror(errno);
-	EXPECT_EQ(ENOSYS, errno);
-}
-
-/*
- * If a fuse server sets FUSE_NO_OPEN_SUPPORT and returns ENOSYS to a
+ * If a fuse server returns ENOSYS to a
  * FUSE_OPEN, then it and subsequent FUSE_OPEN and FUSE_RELEASE operations will
  * also succeed automatically without being sent to the server.
  */
-TEST_F(OpenNoOpenSupport, enosys)
+TEST_F(Open, enosys)
 {
 	const char FULLPATH[] = "mountpoint/some_file.txt";
 	const char RELPATH[] = "some_file.txt";
diff --git a/tests/sys/fs/fusefs/opendir.cc b/tests/sys/fs/fusefs/opendir.cc
index dd837a8d43c1..e1fed59635fc 100644
--- a/tests/sys/fs/fusefs/opendir.cc
+++ b/tests/sys/fs/fusefs/opendir.cc
@@ -71,13 +71,6 @@ void expect_opendir(uint64_t ino, uint32_t flags, ProcessMockerT r)
 
 };
 
-class OpendirNoOpendirSupport: public Opendir {
-	virtual void SetUp() {
-		m_init_flags = FUSE_NO_OPENDIR_SUPPORT;
-		FuseTest::SetUp();
-	}
-};
-
 
 /* 
  * The fuse daemon fails the request with enoent.  This usually indicates a
@@ -179,27 +172,11 @@ TEST_F(Opendir, opendir)
 }
 
 /*
- * Without FUSE_NO_OPENDIR_SUPPORT, returning ENOSYS is an error
- */
-TEST_F(Opendir, enosys)
-{
-	const char FULLPATH[] = "mountpoint/some_file.txt";
-	const char RELPATH[] = "some_file.txt";
-	uint64_t ino = 42;
-
-	expect_lookup(RELPATH, ino);
-	expect_opendir(ino, O_RDONLY, ReturnErrno(ENOSYS));
-
-	EXPECT_EQ(-1, open(FULLPATH, O_DIRECTORY));
-	EXPECT_EQ(ENOSYS, errno);
-}
-
-/*
- * If a fuse server sets FUSE_NO_OPENDIR_SUPPORT and returns ENOSYS to a
+ * If a fuse server returns ENOSYS to a
  * FUSE_OPENDIR, then it and subsequent FUSE_OPENDIR and FUSE_RELEASEDIR
  * operations will also succeed automatically without being sent to the server.
  */
-TEST_F(OpendirNoOpendirSupport, enosys)
+TEST_F(Opendir, enosys)
 {
 	const char FULLPATH[] = "mountpoint/some_file.txt";
 	const char RELPATH[] = "some_file.txt";