Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F161250412
D32141.id95726.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D32141.id95726.diff
View Options
Index: sys/fs/fuse/fuse_file.h
===================================================================
--- sys/fs/fuse/fuse_file.h
+++ sys/fs/fuse/fuse_file.h
@@ -211,7 +211,8 @@
void fuse_filehandle_init(struct vnode *vp, fufh_type_t fufh_type,
struct fuse_filehandle **fufhp, struct thread *td,
- struct ucred *cred, struct fuse_open_out *foo);
+ const struct ucred *cred,
+ const struct fuse_open_out *foo);
int fuse_filehandle_open(struct vnode *vp, int mode,
struct fuse_filehandle **fufhp, struct thread *td,
struct ucred *cred);
Index: sys/fs/fuse/fuse_file.c
===================================================================
--- sys/fs/fuse/fuse_file.c
+++ sys/fs/fuse/fuse_file.c
@@ -124,44 +124,68 @@
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;
- struct fuse_open_in *foi;
- struct fuse_open_out *foo;
+ const struct fuse_open_out default_foo = {
+ .fh = 0,
+ .open_flags = FOPEN_KEEP_CACHE,
+ .padding = 0
+ };
+ 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));
- fdisp_make_vp(&fdi, op, vp, td, cred);
-
- foi = fdi.indata;
- foi->flags = oflags;
-
- if ((err = fdisp_wait_answ(&fdi))) {
- SDT_PROBE2(fusefs, , file, trace, 1,
- "OUCH ... daemon didn't give fh");
- if (err == ENOENT) {
- fuse_internal_vnode_disappear(vp);
+ if (fsess_not_impl(mp, op) && dataflags & fsess_no_op_support) {
+ /* The operation implicitly succeeds */
+ foo = &default_foo;
+ } else {
+ fdisp_make_vp(&fdi, op, vp, td, cred);
+
+ foi = fdi.indata;
+ foi->flags = oflags;
+
+ err = fdisp_wait_answ(&fdi);
+ if (err == ENOSYS && dataflags & fsess_no_op_support) {
+ /* The operation implicitly succeeds */
+ foo = &default_foo;
+ fsess_set_notimpl(mp, op);
+ fsess_set_notimpl(mp, relop);
+ err = 0;
+ } else if (err) {
+ SDT_PROBE2(fusefs, , file, trace, 1,
+ "OUCH ... daemon didn't give fh");
+ if (err == ENOENT)
+ fuse_internal_vnode_disappear(vp);
+ goto out;
+ } else {
+ foo = fdi.answ;
}
- goto out;
}
- foo = fdi.answ;
fuse_filehandle_init(vp, fufh_type, fufhp, td, cred, foo);
fuse_vnode_open(vp, foo->open_flags, td);
out:
- fdisp_destroy(&fdi);
+ if (foi)
+ fdisp_destroy(&fdi);
return err;
}
@@ -169,6 +193,7 @@
fuse_filehandle_close(struct vnode *vp, struct fuse_filehandle *fufh,
struct thread *td, struct ucred *cred)
{
+ struct mount *mp = vnode_mount(vp);
struct fuse_dispatcher fdi;
struct fuse_release_in *fri;
@@ -180,6 +205,10 @@
}
if (vnode_isdir(vp))
op = FUSE_RELEASEDIR;
+
+ if (fsess_not_impl(mp, op))
+ goto out;
+
fdisp_init(&fdi, sizeof(*fri));
fdisp_make_vp(&fdi, op, vp, td, cred);
fri = fdi.indata;
@@ -327,8 +356,8 @@
void
fuse_filehandle_init(struct vnode *vp, fufh_type_t fufh_type,
- struct fuse_filehandle **fufhp, struct thread *td, struct ucred *cred,
- struct fuse_open_out *foo)
+ struct fuse_filehandle **fufhp, struct thread *td, const struct ucred *cred,
+ const struct fuse_open_out *foo)
{
struct fuse_vnode_data *fvdat = VTOFUD(vp);
struct fuse_filehandle *fufh;
Index: sys/fs/fuse/fuse_internal.c
===================================================================
--- sys/fs/fuse/fuse_internal.c
+++ sys/fs/fuse/fuse_internal.c
@@ -363,7 +363,7 @@
ffsi->fsync_flags = 0;
if (datasync)
- ffsi->fsync_flags = 1;
+ ffsi->fsync_flags = FUSE_FSYNC_FDATASYNC;
if (waitfor == MNT_WAIT) {
err = fdisp_wait_answ(&fdi);
@@ -1009,6 +1009,10 @@
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
@@ -1098,7 +1102,6 @@
* FUSE_DO_READDIRPLUS: not yet implemented
* FUSE_READDIRPLUS_AUTO: not yet implemented
* FUSE_ASYNC_DIO: not yet implemented
- * FUSE_NO_OPEN_SUPPORT: not yet implemented
* FUSE_PARALLEL_DIROPS: not yet implemented
* FUSE_HANDLE_KILLPRIV: not yet implemented
* FUSE_POSIX_ACL: not yet implemented
@@ -1107,7 +1110,8 @@
* FUSE_MAX_PAGES: not yet implemented
*/
fiii->flags = FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_EXPORT_SUPPORT
- | FUSE_BIG_WRITES | FUSE_WRITEBACK_CACHE;
+ | FUSE_BIG_WRITES | FUSE_WRITEBACK_CACHE
+ | FUSE_NO_OPEN_SUPPORT | FUSE_NO_OPENDIR_SUPPORT;
fuse_insert_callback(fdi.tick, fuse_internal_init_callback);
fuse_insert_message(fdi.tick, false);
Index: sys/fs/fuse/fuse_ipc.h
===================================================================
--- sys/fs/fuse/fuse_ipc.h
+++ sys/fs/fuse/fuse_ipc.h
@@ -229,6 +229,8 @@
/* (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 */
Index: sys/fs/fuse/fuse_kernel.h
===================================================================
--- sys/fs/fuse/fuse_kernel.h
+++ sys/fs/fuse/fuse_kernel.h
@@ -41,22 +41,61 @@
*
* Protocol changelog:
*
+ * 7.1:
+ * - add the following messages:
+ * FUSE_SETATTR, FUSE_SYMLINK, FUSE_MKNOD, FUSE_MKDIR, FUSE_UNLINK,
+ * FUSE_RMDIR, FUSE_RENAME, FUSE_LINK, FUSE_OPEN, FUSE_READ, FUSE_WRITE,
+ * FUSE_RELEASE, FUSE_FSYNC, FUSE_FLUSH, FUSE_SETXATTR, FUSE_GETXATTR,
+ * FUSE_LISTXATTR, FUSE_REMOVEXATTR, FUSE_OPENDIR, FUSE_READDIR,
+ * FUSE_RELEASEDIR
+ * - add padding to messages to accommodate 32-bit servers on 64-bit kernels
+ *
+ * 7.2:
+ * - add FOPEN_DIRECT_IO and FOPEN_KEEP_CACHE flags
+ * - add FUSE_FSYNCDIR message
+ *
+ * 7.3:
+ * - add FUSE_ACCESS message
+ * - add FUSE_CREATE message
+ * - add filehandle to fuse_setattr_in
+ *
+ * 7.4:
+ * - add frsize to fuse_kstatfs
+ * - clean up request size limit checking
+ *
+ * 7.5:
+ * - add flags and max_write to fuse_init_out
+ *
+ * 7.6:
+ * - add max_readahead to fuse_init_in and fuse_init_out
+ *
+ * 7.7:
+ * - add FUSE_INTERRUPT message
+ * - add POSIX file lock support
+ *
+ * 7.8:
+ * - add lock_owner and flags fields to fuse_release_in
+ * - add FUSE_BMAP message
+ * - add FUSE_DESTROY message
+ *
* 7.9:
* - new fuse_getattr_in input argument of GETATTR
* - add lk_flags in fuse_lk_in
* - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
* - add blksize field to fuse_attr
* - add file flags field to fuse_read_in and fuse_write_in
+ * - Add ATIME_NOW and MTIME_NOW flags to fuse_setattr_in
*
* 7.10
* - add nonseekable open flag
*
- * 7.11
+ * 7.11
* - add IOCTL message
* - add unsolicited notification support
+ * - add POLL message and NOTIFY_POLL notification
*
- * 7.12
- * - add umask flag to input argument of open, mknod and mkdir
+ * 7.12
+ * - add umask flag to input argument of create, mknod and mkdir
* - add notification messages for invalidation of inodes and
* directory entries
*
@@ -89,6 +128,7 @@
*
* 7.20
* - add FUSE_AUTO_INVAL_DATA
+ *
* 7.21
* - add FUSE_READDIRPLUS
* - send the requested events in POLL request
@@ -105,7 +145,7 @@
* - add FUSE_RENAME2 request
* - add FUSE_NO_OPEN_SUPPORT flag
*
- * 7.24
+ * 7.24
* - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support
*
* 7.25
@@ -134,11 +174,31 @@
#include <sys/types.h>
#endif
+/*
+ * Version negotiation:
+ *
+ * Both the kernel and userspace send the version they support in the
+ * INIT request and reply respectively.
+ *
+ * If the major versions match then both shall use the smallest
+ * of the two minor versions for communication.
+ *
+ * If the kernel supports a larger major version, then userspace shall
+ * reply with the major version it supports, ignore the rest of the
+ * INIT message and expect a new INIT message from the kernel with a
+ * matching major version.
+ *
+ * If the library supports a larger major version, then it shall fall
+ * back to the major protocol version sent by the kernel for
+ * communication and reply with that major version (and an arbitrary
+ * supported minor version).
+ */
+
/** Version number of this interface */
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 28
+#define FUSE_KERNEL_MINOR_VERSION 29
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -240,6 +300,7 @@
* FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED
* FUSE_MAX_PAGES: init_out.max_pages contains the max number of req pages
* FUSE_CACHE_SYMLINKS: cache READLINK responses
+ * FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir
*/
#define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1)
@@ -265,6 +326,7 @@
#define FUSE_ABORT_ERROR (1 << 21)
#define FUSE_MAX_PAGES (1 << 22)
#define FUSE_CACHE_SYMLINKS (1 << 23)
+#define FUSE_NO_OPENDIR_SUPPORT (1 << 24)
#ifdef linux
/**
@@ -331,6 +393,13 @@
*/
#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0)
+/**
+ * Fsync flags
+ *
+ * FUSE_FSYNC_FDATASYNC: Sync data only, not metadata
+ */
+#define FUSE_FSYNC_FDATASYNC (1 << 0)
+
enum fuse_opcode {
FUSE_LOOKUP = 1,
FUSE_FORGET = 2, /* no reply */
@@ -791,14 +860,14 @@
};
struct fuse_lseek_in {
- uint64_t fh;
- uint64_t offset;
- uint32_t whence;
- uint32_t padding;
+ uint64_t fh;
+ uint64_t offset;
+ uint32_t whence;
+ uint32_t padding;
};
struct fuse_lseek_out {
- uint64_t offset;
+ uint64_t offset;
};
struct fuse_copy_file_range_in {
Index: tests/sys/fs/fusefs/open.cc
===================================================================
--- tests/sys/fs/fusefs/open.cc
+++ tests/sys/fs/fusefs/open.cc
@@ -73,6 +73,13 @@
};
+class OpenNoOpenSupport: public FuseTest {
+ virtual void SetUp() {
+ m_init_flags = FUSE_NO_OPEN_SUPPORT;
+ FuseTest::SetUp();
+ }
+};
+
/*
* fusefs(5) does not support I/O on device nodes (neither does UFS). But it
* shouldn't crash
@@ -274,3 +281,62 @@
test_ok(O_RDWR, 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
+ * 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)
+{
+ 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, 2);
+ 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)));
+ expect_flush(ino, 1, ReturnErrno(ENOSYS));
+
+ fd = open(FULLPATH, O_RDONLY);
+ ASSERT_LE(0, fd) << strerror(errno);
+ close(fd);
+
+ fd = open(FULLPATH, O_RDONLY);
+ ASSERT_LE(0, fd) << strerror(errno);
+
+ leak(fd);
+}
Index: tests/sys/fs/fusefs/opendir.cc
===================================================================
--- tests/sys/fs/fusefs/opendir.cc
+++ tests/sys/fs/fusefs/opendir.cc
@@ -73,6 +73,13 @@
};
+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
@@ -172,3 +179,44 @@
errno = 0;
EXPECT_NE(nullptr, opendir(FULLPATH)) << strerror(errno);
}
+
+/*
+ * 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
+ * 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)
+{
+ 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_IFDIR | 0755, 0, 2);
+ expect_opendir(ino, O_RDONLY, ReturnErrno(ENOSYS));
+
+ fd = open(FULLPATH, O_DIRECTORY);
+ ASSERT_LE(0, fd) << strerror(errno);
+ close(fd);
+
+ fd = open(FULLPATH, O_DIRECTORY);
+ ASSERT_LE(0, fd) << strerror(errno);
+
+ leak(fd);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jul 3, 3:30 AM (4 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34610638
Default Alt Text
D32141.id95726.diff (14 KB)
Attached To
Mode
D32141: fusefs: implement FUSE_NO_OPEN_SUPPORT and FUSE_NO_OPENDIR_SUPPORT
Attached
Detach File
Event Timeline
Log In to Comment