mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 08:43:19 -04:00
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
This commit is contained in:
parent
618c97b87b
commit
f0f596bd95
6 changed files with 15 additions and 82 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
Loading…
Reference in a new issue