Skip to content

Commit

Permalink
fusefs: ignore FUSE_NO_OPEN(DIR)_SUPPORT flags
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by:	CismonX <[email protected]>
Pull Request:	#1509
  • Loading branch information
CismonX authored and asomers committed Dec 20, 2024
1 parent 618c97b commit f0f596b
Show file tree
Hide file tree
Showing 6 changed files with 15 additions and 82 deletions.
9 changes: 3 additions & 6 deletions sys/fs/fuse/fuse_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -132,25 +131,22 @@ 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);

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 {
Expand All @@ -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);
Expand All @@ -174,6 +170,7 @@ fuse_filehandle_open(struct vnode *vp, int a_mode,
goto out;
} else {
foo = fdi.answ;
fsess_set_impl(mp, op);
}
}

Expand Down
4 changes: 0 additions & 4 deletions sys/fs/fuse/fuse_internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions sys/fs/fuse/fuse_ipc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
17 changes: 8 additions & 9 deletions sys/fs/fuse/fuse_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
}

Expand Down
38 changes: 2 additions & 36 deletions tests/sys/fs/fusefs/open.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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";
Expand Down
27 changes: 2 additions & 25 deletions tests/sys/fs/fusefs/opendir.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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";
Expand Down

0 comments on commit f0f596b

Please sign in to comment.