Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fusefs: ignore FUSE_NO_OPEN(DIR)_SUPPORT flags #1509

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading