aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBernd Schubert <bernd@bsbernd.com>2024-12-28 15:10:03 +0100
committerBernd Schubert <bernd@bsbernd.com>2024-12-30 23:04:11 +0100
commit24f5b129c4e1b03ebbd05ac0c7673f306facea1a (patch)
treee16f5b02a829457efab3f98ebbe54271e581a7f6
parent3d90402f9084edb90ddb00d6ccd8c2183e6df140 (diff)
downloadlibfuse-24f5b129c4e1b03ebbd05ac0c7673f306facea1a.tar.gz
Add 64-bit conn::{capable,want}_ext fields
The previous fields are left for ABI compatibility, although it is not beautiful to add that complexity when we have to increase the so-version as we had ABI breakage anyway. example/printcap is simplified to use an array, as every line would have needed to be modified anyway. Missing 'FUSE_CAP_PASSTHROUGH' was added. Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
-rw-r--r--example/passthrough_ll.c22
-rw-r--r--example/printcap.c113
-rw-r--r--include/fuse_common.h40
-rw-r--r--lib/cuse_lowlevel.c6
-rw-r--r--lib/fuse.c3
-rw-r--r--lib/fuse_lowlevel.c172
-rw-r--r--test/test_write_cache.c2
7 files changed, 216 insertions, 142 deletions
diff --git a/example/passthrough_ll.c b/example/passthrough_ll.c
index 309d8dd..5f1fde9 100644
--- a/example/passthrough_ll.c
+++ b/example/passthrough_ll.c
@@ -168,18 +168,20 @@ static bool lo_debug(fuse_req_t req)
static void lo_init(void *userdata,
struct fuse_conn_info *conn)
{
- struct lo_data *lo = (struct lo_data*) userdata;
-
- if (lo->writeback &&
- conn->capable & FUSE_CAP_WRITEBACK_CACHE) {
- if (lo->debug)
- fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
- conn->want |= FUSE_CAP_WRITEBACK_CACHE;
+ struct lo_data *lo = (struct lo_data *)userdata;
+ bool has_flag;
+
+ if (lo->writeback) {
+ has_flag = fuse_set_feature_flag(conn, FUSE_CAP_WRITEBACK_CACHE);
+ if (lo->debug && has_flag)
+ fuse_log(FUSE_LOG_DEBUG,
+ "lo_init: activating writeback\n");
}
if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
- if (lo->debug)
- fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
- conn->want |= FUSE_CAP_FLOCK_LOCKS;
+ has_flag = fuse_set_feature_flag(conn, FUSE_CAP_FLOCK_LOCKS);
+ if (lo->debug && has_flag)
+ fuse_log(FUSE_LOG_DEBUG,
+ "lo_init: activating flock locks\n");
}
/* Disable the receiving and processing of FUSE_INTERRUPT requests */
diff --git a/example/printcap.c b/example/printcap.c
index 01b4d3f..82a7598 100644
--- a/example/printcap.c
+++ b/example/printcap.c
@@ -29,68 +29,63 @@
struct fuse_session *se;
-static void pc_init(void *userdata,
- struct fuse_conn_info *conn)
+// Define a structure to hold capability information
+struct cap_info {
+ uint64_t flag;
+ const char *name;
+};
+
+// Define an array of all capabilities
+static const struct cap_info capabilities[] = {
+ {FUSE_CAP_ASYNC_READ, "FUSE_CAP_ASYNC_READ"},
+ {FUSE_CAP_POSIX_LOCKS, "FUSE_CAP_POSIX_LOCKS"},
+ {FUSE_CAP_ATOMIC_O_TRUNC, "FUSE_CAP_ATOMIC_O_TRUNC"},
+ {FUSE_CAP_EXPORT_SUPPORT, "FUSE_CAP_EXPORT_SUPPORT"},
+ {FUSE_CAP_DONT_MASK, "FUSE_CAP_DONT_MASK"},
+ {FUSE_CAP_SPLICE_MOVE, "FUSE_CAP_SPLICE_MOVE"},
+ {FUSE_CAP_SPLICE_READ, "FUSE_CAP_SPLICE_READ"},
+ {FUSE_CAP_SPLICE_WRITE, "FUSE_CAP_SPLICE_WRITE"},
+ {FUSE_CAP_FLOCK_LOCKS, "FUSE_CAP_FLOCK_LOCKS"},
+ {FUSE_CAP_IOCTL_DIR, "FUSE_CAP_IOCTL_DIR"},
+ {FUSE_CAP_AUTO_INVAL_DATA, "FUSE_CAP_AUTO_INVAL_DATA"},
+ {FUSE_CAP_READDIRPLUS, "FUSE_CAP_READDIRPLUS"},
+ {FUSE_CAP_READDIRPLUS_AUTO, "FUSE_CAP_READDIRPLUS_AUTO"},
+ {FUSE_CAP_ASYNC_DIO, "FUSE_CAP_ASYNC_DIO"},
+ {FUSE_CAP_WRITEBACK_CACHE, "FUSE_CAP_WRITEBACK_CACHE"},
+ {FUSE_CAP_NO_OPEN_SUPPORT, "FUSE_CAP_NO_OPEN_SUPPORT"},
+ {FUSE_CAP_PARALLEL_DIROPS, "FUSE_CAP_PARALLEL_DIROPS"},
+ {FUSE_CAP_POSIX_ACL, "FUSE_CAP_POSIX_ACL"},
+ {FUSE_CAP_CACHE_SYMLINKS, "FUSE_CAP_CACHE_SYMLINKS"},
+ {FUSE_CAP_NO_OPENDIR_SUPPORT, "FUSE_CAP_NO_OPENDIR_SUPPORT"},
+ {FUSE_CAP_EXPLICIT_INVAL_DATA, "FUSE_CAP_EXPLICIT_INVAL_DATA"},
+ {FUSE_CAP_EXPIRE_ONLY, "FUSE_CAP_EXPIRE_ONLY"},
+ {FUSE_CAP_SETXATTR_EXT, "FUSE_CAP_SETXATTR_EXT"},
+ {FUSE_CAP_HANDLE_KILLPRIV, "FUSE_CAP_HANDLE_KILLPRIV"},
+ {FUSE_CAP_HANDLE_KILLPRIV_V2, "FUSE_CAP_HANDLE_KILLPRIV_V2"},
+ {FUSE_CAP_DIRECT_IO_ALLOW_MMAP, "FUSE_CAP_DIRECT_IO_ALLOW_MMAP"},
+ {FUSE_CAP_NO_EXPORT_SUPPORT, "FUSE_CAP_NO_EXPORT_SUPPORT"},
+ {FUSE_CAP_PASSTHROUGH, "FUSE_CAP_PASSTHROUGH"},
+ // Add any new capabilities here
+ {0, NULL} // Sentinel to mark the end of the array
+};
+
+static void print_capabilities(struct fuse_conn_info *conn)
+{
+ printf("Capabilities:\n");
+ for (const struct cap_info *cap = capabilities; cap->name != NULL; cap++) {
+ if (fuse_get_feature_flag(conn, cap->flag)) {
+ printf("\t%s\n", cap->name);
+ }
+ }
+}
+
+static void pc_init(void *userdata, struct fuse_conn_info *conn)
{
(void) userdata;
-
+
printf("Protocol version: %d.%d\n", conn->proto_major,
conn->proto_minor);
- printf("Capabilities:\n");
- if(conn->capable & FUSE_CAP_ASYNC_READ)
- printf("\tFUSE_CAP_ASYNC_READ\n");
- if(conn->capable & FUSE_CAP_POSIX_LOCKS)
- printf("\tFUSE_CAP_POSIX_LOCKS\n");
- if(conn->capable & FUSE_CAP_ATOMIC_O_TRUNC)
- printf("\tFUSE_CAP_ATOMIC_O_TRUNC\n");
- if(conn->capable & FUSE_CAP_EXPORT_SUPPORT)
- printf("\tFUSE_CAP_EXPORT_SUPPORT\n");
- if(conn->capable & FUSE_CAP_DONT_MASK)
- printf("\tFUSE_CAP_DONT_MASK\n");
- if(conn->capable & FUSE_CAP_SPLICE_MOVE)
- printf("\tFUSE_CAP_SPLICE_MOVE\n");
- if(conn->capable & FUSE_CAP_SPLICE_READ)
- printf("\tFUSE_CAP_SPLICE_READ\n");
- if(conn->capable & FUSE_CAP_SPLICE_WRITE)
- printf("\tFUSE_CAP_SPLICE_WRITE\n");
- if(conn->capable & FUSE_CAP_FLOCK_LOCKS)
- printf("\tFUSE_CAP_FLOCK_LOCKS\n");
- if(conn->capable & FUSE_CAP_IOCTL_DIR)
- printf("\tFUSE_CAP_IOCTL_DIR\n");
- if(conn->capable & FUSE_CAP_AUTO_INVAL_DATA)
- printf("\tFUSE_CAP_AUTO_INVAL_DATA\n");
- if(conn->capable & FUSE_CAP_READDIRPLUS)
- printf("\tFUSE_CAP_READDIRPLUS\n");
- if(conn->capable & FUSE_CAP_READDIRPLUS_AUTO)
- printf("\tFUSE_CAP_READDIRPLUS_AUTO\n");
- if(conn->capable & FUSE_CAP_ASYNC_DIO)
- printf("\tFUSE_CAP_ASYNC_DIO\n");
- if(conn->capable & FUSE_CAP_WRITEBACK_CACHE)
- printf("\tFUSE_CAP_WRITEBACK_CACHE\n");
- if(conn->capable & FUSE_CAP_NO_OPEN_SUPPORT)
- printf("\tFUSE_CAP_NO_OPEN_SUPPORT\n");
- if(conn->capable & FUSE_CAP_PARALLEL_DIROPS)
- printf("\tFUSE_CAP_PARALLEL_DIROPS\n");
- if(conn->capable & FUSE_CAP_POSIX_ACL)
- printf("\tFUSE_CAP_POSIX_ACL\n");
- if(conn->capable & FUSE_CAP_CACHE_SYMLINKS)
- printf("\tFUSE_CAP_CACHE_SYMLINKS\n");
- if(conn->capable & FUSE_CAP_NO_OPENDIR_SUPPORT)
- printf("\tFUSE_CAP_NO_OPENDIR_SUPPORT\n");
- if(conn->capable & FUSE_CAP_EXPLICIT_INVAL_DATA)
- printf("\tFUSE_CAP_EXPLICIT_INVAL_DATA\n");
- if(conn->capable & FUSE_CAP_EXPIRE_ONLY)
- printf("\tFUSE_CAP_EXPIRE_ONLY\n");
- if(conn->capable & FUSE_CAP_SETXATTR_EXT)
- printf("\tFUSE_CAP_SETXATTR_EXT\n");
- if(conn->capable & FUSE_CAP_HANDLE_KILLPRIV)
- printf("\tFUSE_CAP_HANDLE_KILLPRIV\n");
- if(conn->capable & FUSE_CAP_HANDLE_KILLPRIV_V2)
- printf("\tFUSE_CAP_HANDLE_KILLPRIV_V2\n");
- if(conn->capable & FUSE_CAP_DIRECT_IO_ALLOW_MMAP)
- printf("\tFUSE_CAP_DIRECT_IO_ALLOW_MMAP\n");
- if (conn->capable & FUSE_CAP_NO_EXPORT_SUPPORT)
- printf("\tFUSE_CAP_NO_EXPORT_SUPPORT\n");
+ print_capabilities(conn);
fuse_session_exit(se);
}
@@ -110,7 +105,7 @@ int main(int argc, char **argv)
perror("mkdtemp");
return 1;
}
-
+
printf("FUSE library version %s\n", fuse_pkgversion());
fuse_lowlevel_version();
diff --git a/include/fuse_common.h b/include/fuse_common.h
index 2c866c4..fbf16ba 100644
--- a/include/fuse_common.h
+++ b/include/fuse_common.h
@@ -540,6 +540,10 @@ struct fuse_loop_config_v1 {
* Some of the elements are read-write, these can be changed to
* indicate the value requested by the filesystem. The requested
* value must usually be smaller than the indicated value.
+ *
+ * Note: The `capable` and `want` fields are limited to 32 bits for
+ * ABI compatibility. For full 64-bit capability support, use the
+ * `capable_ext` and `want_ext` fields instead.
*/
struct fuse_conn_info {
/**
@@ -578,6 +582,8 @@ struct fuse_conn_info {
/**
* Capability flags that the kernel supports (read-only)
+ *
+ * Deprecated left over for ABI compatibility, use capable_ext
*/
uint32_t capable;
@@ -586,6 +592,10 @@ struct fuse_conn_info {
*
* libfuse attempts to initialize this field with
* reasonable default values before calling the init() handler.
+ *
+ * Deprecated left over for ABI compatibility.
+ * Use want_ext with the helper functions
+ * fuse_set_feature_flag() / fuse_unset_feature_flag()
*/
uint32_t want;
@@ -680,9 +690,25 @@ struct fuse_conn_info {
uint32_t padding : 31;
/**
+ * Extended capability flags that the kernel supports (read-only)
+ * This field provides full 64-bit capability support.
+ */
+ uint64_t capable_ext;
+
+ /**
+ * Extended capability flags that the filesystem wants to enable.
+ * This field provides full 64-bit capability support.
+ *
+ * Don't set this field directly, but use the helper functions
+ * fuse_set_feature_flag() / fuse_unset_feature_flag()
+ *
+ */
+ uint64_t want_ext;
+
+ /**
* For future use.
*/
- uint32_t reserved[20];
+ uint32_t reserved[16];
};
fuse_static_assert(sizeof(struct fuse_conn_info) == 128,
"Size of struct fuse_conn_info must be 128 bytes");
@@ -1076,8 +1102,8 @@ void fuse_loop_cfg_convert(struct fuse_loop_config *config,
static inline bool fuse_set_feature_flag(struct fuse_conn_info *conn,
uint64_t flag)
{
- if (conn->capable & flag) {
- conn->want |= flag;
+ if (conn->capable_ext & flag) {
+ conn->want_ext |= flag;
return true;
}
return false;
@@ -1086,7 +1112,13 @@ static inline bool fuse_set_feature_flag(struct fuse_conn_info *conn,
static inline void fuse_unset_feature_flag(struct fuse_conn_info *conn,
uint64_t flag)
{
- conn->want &= ~flag;
+ conn->want_ext &= ~flag;
+}
+
+static inline bool fuse_get_feature_flag(struct fuse_conn_info *conn,
+ uint64_t flag)
+{
+ return conn->capable_ext & flag ? true : false;
}
/* ----------------------------------------------------------- *
diff --git a/lib/cuse_lowlevel.c b/lib/cuse_lowlevel.c
index cd68787..5387f84 100644
--- a/lib/cuse_lowlevel.c
+++ b/lib/cuse_lowlevel.c
@@ -208,8 +208,10 @@ void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
}
se->conn.proto_major = arg->major;
se->conn.proto_minor = arg->minor;
- se->conn.capable = 0;
- se->conn.want = 0;
+
+ /* XXX This is not right.*/
+ se->conn.capable_ext = 0;
+ se->conn.want_ext = 0;
if (arg->major < 7) {
fuse_log(FUSE_LOG_ERR, "cuse: unsupported protocol version: %u.%u\n",
diff --git a/lib/fuse.c b/lib/fuse.c
index b327bab..a1537af 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -2619,8 +2619,7 @@ static void fuse_lib_init(void *data, struct fuse_conn_info *conn)
struct fuse *f = (struct fuse *) data;
fuse_create_context(f);
- if(conn->capable & FUSE_CAP_EXPORT_SUPPORT)
- conn->want |= FUSE_CAP_EXPORT_SUPPORT;
+ fuse_set_feature_flag(conn, FUSE_CAP_EXPORT_SUPPORT);
fuse_fs_init(f->fs, conn, &f->conf);
if (f->conf.intr) {
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index a0d8647..d84c678 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -728,7 +728,7 @@ static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
goto fallback;
if (se->conn.proto_minor < 14 ||
- !(se->conn.want & FUSE_CAP_SPLICE_WRITE))
+ !(se->conn.want_ext & FUSE_CAP_SPLICE_WRITE))
goto fallback;
llp = fuse_ll_get_pipe(se);
@@ -869,7 +869,7 @@ static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
splice_flags = 0;
if ((flags & FUSE_BUF_SPLICE_MOVE) &&
- (se->conn.want & FUSE_CAP_SPLICE_MOVE))
+ (se->conn.want_ext & FUSE_CAP_SPLICE_MOVE))
splice_flags |= SPLICE_F_MOVE;
if (se->io != NULL && se->io->splice_send != NULL) {
@@ -1410,7 +1410,7 @@ static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
if (req->se->op.open)
req->se->op.open(req, nodeid, &fi);
- else if (req->se->conn.want & FUSE_CAP_NO_OPEN_SUPPORT)
+ else if (req->se->conn.want_ext & FUSE_CAP_NO_OPEN_SUPPORT)
fuse_reply_err(req, ENOSYS);
else
fuse_reply_open(req, &fi);
@@ -1568,7 +1568,7 @@ static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
if (req->se->op.opendir)
req->se->op.opendir(req, nodeid, &fi);
- else if (req->se->conn.want & FUSE_CAP_NO_OPENDIR_SUPPORT)
+ else if (req->se->conn.want_ext & FUSE_CAP_NO_OPENDIR_SUPPORT)
fuse_reply_err(req, ENOSYS);
else
fuse_reply_open(req, &fi);
@@ -1651,7 +1651,7 @@ static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
struct fuse_session *se = req->se;
- unsigned int xattr_ext = !!(se->conn.want & FUSE_CAP_SETXATTR_EXT);
+ unsigned int xattr_ext = !!(se->conn.want_ext & FUSE_CAP_SETXATTR_EXT);
struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
char *name = xattr_ext ? PARAM(arg) :
(char *)arg + FUSE_COMPAT_SETXATTR_IN_SIZE;
@@ -1882,7 +1882,7 @@ static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
struct fuse_file_info fi;
if (flags & FUSE_IOCTL_DIR &&
- !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
+ !(req->se->conn.want_ext & FUSE_CAP_IOCTL_DIR)) {
fuse_reply_err(req, ENOTTY);
return;
}
@@ -1997,6 +1997,27 @@ static bool want_flags_valid(uint64_t capable, uint64_t want)
return true;
}
+/**
+ * Get the wanted capability flags, converting from old format if necessary
+ * Also applies the first 32 bits of capable_ext to capable
+ *
+ */
+static inline int convert_to_conn_want_ext(struct fuse_conn_info *conn,
+ uint64_t want_ext_default)
+{
+ /* Convert want to want_ext if necessary */
+ if (conn->want != 0) {
+ if (conn->want_ext != want_ext_default) {
+ fuse_log(FUSE_LOG_ERR,
+ "fuse: both 'want' and 'want_ext' are set\n");
+ return -EINVAL;
+ }
+ conn->want_ext |= conn->want;
+ }
+
+ return 0;
+}
+
/* Prevent bogus data races (bogus since "init" is called before
* multi-threading becomes relevant */
static __attribute__((no_sanitize("thread")))
@@ -2021,8 +2042,8 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
}
se->conn.proto_major = arg->major;
se->conn.proto_minor = arg->minor;
- se->conn.capable = 0;
- se->conn.want = 0;
+ se->conn.capable_ext = 0;
+ se->conn.want_ext = 0;
memset(&outarg, 0, sizeof(outarg));
outarg.major = FUSE_KERNEL_VERSION;
@@ -2048,45 +2069,45 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
if (inargflags & FUSE_INIT_EXT)
inargflags = inargflags | (uint64_t) arg->flags2 << 32;
if (inargflags & FUSE_ASYNC_READ)
- se->conn.capable |= FUSE_CAP_ASYNC_READ;
+ se->conn.capable_ext |= FUSE_CAP_ASYNC_READ;
if (inargflags & FUSE_POSIX_LOCKS)
- se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
+ se->conn.capable_ext |= FUSE_CAP_POSIX_LOCKS;
if (inargflags & FUSE_ATOMIC_O_TRUNC)
- se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
+ se->conn.capable_ext |= FUSE_CAP_ATOMIC_O_TRUNC;
if (inargflags & FUSE_EXPORT_SUPPORT)
- se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
+ se->conn.capable_ext |= FUSE_CAP_EXPORT_SUPPORT;
if (inargflags & FUSE_DONT_MASK)
- se->conn.capable |= FUSE_CAP_DONT_MASK;
+ se->conn.capable_ext |= FUSE_CAP_DONT_MASK;
if (inargflags & FUSE_FLOCK_LOCKS)
- se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
+ se->conn.capable_ext |= FUSE_CAP_FLOCK_LOCKS;
if (inargflags & FUSE_AUTO_INVAL_DATA)
- se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
+ se->conn.capable_ext |= FUSE_CAP_AUTO_INVAL_DATA;
if (inargflags & FUSE_DO_READDIRPLUS)
- se->conn.capable |= FUSE_CAP_READDIRPLUS;
+ se->conn.capable_ext |= FUSE_CAP_READDIRPLUS;
if (inargflags & FUSE_READDIRPLUS_AUTO)
- se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
+ se->conn.capable_ext |= FUSE_CAP_READDIRPLUS_AUTO;
if (inargflags & FUSE_ASYNC_DIO)
- se->conn.capable |= FUSE_CAP_ASYNC_DIO;
+ se->conn.capable_ext |= FUSE_CAP_ASYNC_DIO;
if (inargflags & FUSE_WRITEBACK_CACHE)
- se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
+ se->conn.capable_ext |= FUSE_CAP_WRITEBACK_CACHE;
if (inargflags & FUSE_NO_OPEN_SUPPORT)
- se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
+ se->conn.capable_ext |= FUSE_CAP_NO_OPEN_SUPPORT;
if (inargflags & FUSE_PARALLEL_DIROPS)
- se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
+ se->conn.capable_ext |= FUSE_CAP_PARALLEL_DIROPS;
if (inargflags & FUSE_POSIX_ACL)
- se->conn.capable |= FUSE_CAP_POSIX_ACL;
+ se->conn.capable_ext |= FUSE_CAP_POSIX_ACL;
if (inargflags & FUSE_HANDLE_KILLPRIV)
- se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
+ se->conn.capable_ext |= FUSE_CAP_HANDLE_KILLPRIV;
if (inargflags & FUSE_HANDLE_KILLPRIV_V2)
- se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV_V2;
+ se->conn.capable_ext |= FUSE_CAP_HANDLE_KILLPRIV_V2;
if (inargflags & FUSE_CACHE_SYMLINKS)
- se->conn.capable |= FUSE_CAP_CACHE_SYMLINKS;
+ se->conn.capable_ext |= FUSE_CAP_CACHE_SYMLINKS;
if (inargflags & FUSE_NO_OPENDIR_SUPPORT)
- se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
+ se->conn.capable_ext |= FUSE_CAP_NO_OPENDIR_SUPPORT;
if (inargflags & FUSE_EXPLICIT_INVAL_DATA)
- se->conn.capable |= FUSE_CAP_EXPLICIT_INVAL_DATA;
+ se->conn.capable_ext |= FUSE_CAP_EXPLICIT_INVAL_DATA;
if (inargflags & FUSE_SETXATTR_EXT)
- se->conn.capable |= FUSE_CAP_SETXATTR_EXT;
+ se->conn.capable_ext |= FUSE_CAP_SETXATTR_EXT;
if (!(inargflags & FUSE_MAX_PAGES)) {
size_t max_bufsize =
FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
@@ -2097,13 +2118,13 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
buf_reallocable = false;
}
if (inargflags & FUSE_DIRECT_IO_ALLOW_MMAP)
- se->conn.capable |= FUSE_CAP_DIRECT_IO_ALLOW_MMAP;
+ se->conn.capable_ext |= FUSE_CAP_DIRECT_IO_ALLOW_MMAP;
if (arg->minor >= 38 || (inargflags & FUSE_HAS_EXPIRE_ONLY))
- se->conn.capable |= FUSE_CAP_EXPIRE_ONLY;
+ se->conn.capable_ext |= FUSE_CAP_EXPIRE_ONLY;
if (inargflags & FUSE_PASSTHROUGH)
- se->conn.capable |= FUSE_CAP_PASSTHROUGH;
+ se->conn.capable_ext |= FUSE_CAP_PASSTHROUGH;
if (inargflags & FUSE_NO_EXPORT_SUPPORT)
- se->conn.capable |= FUSE_CAP_NO_EXPORT_SUPPORT;
+ se->conn.capable_ext |= FUSE_CAP_NO_EXPORT_SUPPORT;
} else {
se->conn.max_readahead = 0;
}
@@ -2112,16 +2133,17 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
#ifdef HAVE_SPLICE
#ifdef HAVE_VMSPLICE
if ((se->io == NULL) || (se->io->splice_send != NULL)) {
- se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
+ se->conn.capable_ext |= FUSE_CAP_SPLICE_WRITE |
+ FUSE_CAP_SPLICE_MOVE;
}
#endif
if ((se->io == NULL) || (se->io->splice_receive != NULL)) {
- se->conn.capable |= FUSE_CAP_SPLICE_READ;
+ se->conn.capable_ext |= FUSE_CAP_SPLICE_READ;
}
#endif
}
if (se->conn.proto_minor >= 18)
- se->conn.capable |= FUSE_CAP_IOCTL_DIR;
+ se->conn.capable_ext |= FUSE_CAP_IOCTL_DIR;
/* Default settings for modern filesystems.
*
@@ -2130,9 +2152,10 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
* we can finally enable them by default (as long as they're
* supported by the kernel).
*/
-#define LL_SET_DEFAULT(cond, cap) \
- if ((cond) && (se->conn.capable & (cap))) \
- se->conn.want |= (cap)
+#define LL_SET_DEFAULT(cond, cap) \
+ if ((cond)) \
+ fuse_set_feature_flag(&se->conn, cap)
+
LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
@@ -2154,10 +2177,31 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
se->conn.time_gran = 1;
se->got_init = 1;
- if (se->op.init)
+ if (se->op.init) {
+ uint32_t want_ext_default = se->conn.want_ext;
+ int rc;
+
+ // Apply the first 32 bits of capable_ext to capable
+ se->conn.capable =
+ (uint32_t)(se->conn.capable_ext & 0xFFFFFFFF);
+
se->op.init(se->userdata, &se->conn);
- if (!want_flags_valid(se->conn.capable, se->conn.want)) {
+ /*
+ * se->conn.want is 32-bit value and deprecated in favour of
+ * se->conn.want_ext
+ * Userspace might still use conn.want - we need to convert it
+ */
+ rc = convert_to_conn_want_ext(&se->conn, want_ext_default);
+ if (rc != 0) {
+ fuse_reply_err(req, EPROTO);
+ se->error = -EPROTO;
+ fuse_session_exit(se);
+ return;
+ }
+ }
+
+ if (!want_flags_valid(se->conn.capable_ext, se->conn.want_ext)) {
fuse_reply_err(req, EPROTO);
se->error = -EPROTO;
fuse_session_exit(se);
@@ -2196,45 +2240,45 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
by the max_write option */
outargflags |= FUSE_BIG_WRITES;
- if (se->conn.want & FUSE_CAP_ASYNC_READ)
+ if (se->conn.want_ext & FUSE_CAP_ASYNC_READ)
outargflags |= FUSE_ASYNC_READ;
- if (se->conn.want & FUSE_CAP_POSIX_LOCKS)
+ if (se->conn.want_ext & FUSE_CAP_POSIX_LOCKS)
outargflags |= FUSE_POSIX_LOCKS;
- if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
+ if (se->conn.want_ext & FUSE_CAP_ATOMIC_O_TRUNC)
outargflags |= FUSE_ATOMIC_O_TRUNC;
- if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT)
+ if (se->conn.want_ext & FUSE_CAP_EXPORT_SUPPORT)
outargflags |= FUSE_EXPORT_SUPPORT;
- if (se->conn.want & FUSE_CAP_DONT_MASK)
+ if (se->conn.want_ext & FUSE_CAP_DONT_MASK)
outargflags |= FUSE_DONT_MASK;
- if (se->conn.want & FUSE_CAP_FLOCK_LOCKS)
+ if (se->conn.want_ext & FUSE_CAP_FLOCK_LOCKS)
outargflags |= FUSE_FLOCK_LOCKS;
- if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA)
+ if (se->conn.want_ext & FUSE_CAP_AUTO_INVAL_DATA)
outargflags |= FUSE_AUTO_INVAL_DATA;
- if (se->conn.want & FUSE_CAP_READDIRPLUS)
+ if (se->conn.want_ext & FUSE_CAP_READDIRPLUS)
outargflags |= FUSE_DO_READDIRPLUS;
- if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO)
+ if (se->conn.want_ext & FUSE_CAP_READDIRPLUS_AUTO)
outargflags |= FUSE_READDIRPLUS_AUTO;
- if (se->conn.want & FUSE_CAP_ASYNC_DIO)
+ if (se->conn.want_ext & FUSE_CAP_ASYNC_DIO)
outargflags |= FUSE_ASYNC_DIO;
- if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE)
+ if (se->conn.want_ext & FUSE_CAP_WRITEBACK_CACHE)
outargflags |= FUSE_WRITEBACK_CACHE;
- if (se->conn.want & FUSE_CAP_PARALLEL_DIROPS)
+ if (se->conn.want_ext & FUSE_CAP_PARALLEL_DIROPS)
outargflags |= FUSE_PARALLEL_DIROPS;
- if (se->conn.want & FUSE_CAP_POSIX_ACL)
+ if (se->conn.want_ext & FUSE_CAP_POSIX_ACL)
outargflags |= FUSE_POSIX_ACL;
- if (se->conn.want & FUSE_CAP_HANDLE_KILLPRIV)
+ if (se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV)
outargflags |= FUSE_HANDLE_KILLPRIV;
- if (se->conn.want & FUSE_CAP_HANDLE_KILLPRIV_V2)
+ if (se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2)
outargflags |= FUSE_HANDLE_KILLPRIV_V2;
- if (se->conn.want & FUSE_CAP_CACHE_SYMLINKS)
+ if (se->conn.want_ext & FUSE_CAP_CACHE_SYMLINKS)
outargflags |= FUSE_CACHE_SYMLINKS;
- if (se->conn.want & FUSE_CAP_EXPLICIT_INVAL_DATA)
+ if (se->conn.want_ext & FUSE_CAP_EXPLICIT_INVAL_DATA)
outargflags |= FUSE_EXPLICIT_INVAL_DATA;
- if (se->conn.want & FUSE_CAP_SETXATTR_EXT)
+ if (se->conn.want_ext & FUSE_CAP_SETXATTR_EXT)
outargflags |= FUSE_SETXATTR_EXT;
- if (se->conn.want & FUSE_CAP_DIRECT_IO_ALLOW_MMAP)
+ if (se->conn.want_ext & FUSE_CAP_DIRECT_IO_ALLOW_MMAP)
outargflags |= FUSE_DIRECT_IO_ALLOW_MMAP;
- if (se->conn.want & FUSE_CAP_PASSTHROUGH) {
+ if (se->conn.want_ext & FUSE_CAP_PASSTHROUGH) {
outargflags |= FUSE_PASSTHROUGH;
/*
* outarg.max_stack_depth includes the fuse stack layer,
@@ -2242,7 +2286,7 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
*/
outarg.max_stack_depth = se->conn.max_backing_stack_depth + 1;
}
- if (se->conn.want & FUSE_CAP_NO_EXPORT_SUPPORT)
+ if (se->conn.want_ext & FUSE_CAP_NO_EXPORT_SUPPORT)
outargflags |= FUSE_NO_EXPORT_SUPPORT;
if (inargflags & FUSE_INIT_EXT) {
@@ -2282,7 +2326,7 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
outarg.congestion_threshold);
fuse_log(FUSE_LOG_DEBUG, " time_gran=%u\n",
outarg.time_gran);
- if (se->conn.want & FUSE_CAP_PASSTHROUGH)
+ if (se->conn.want_ext & FUSE_CAP_PASSTHROUGH)
fuse_log(FUSE_LOG_DEBUG, " max_stack_depth=%u\n",
outarg.max_stack_depth);
}
@@ -2467,7 +2511,7 @@ int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent
if (!se)
return -EINVAL;
- if (!(se->conn.capable & FUSE_CAP_EXPIRE_ONLY))
+ if (!(se->conn.capable_ext & FUSE_CAP_EXPIRE_ONLY))
return -ENOSYS;
return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_EXPIRE_ONLY);
@@ -3006,7 +3050,7 @@ static int _fuse_session_receive_buf(struct fuse_session *se,
struct fuse_buf tmpbuf;
if (se->conn.proto_minor < 14 ||
- !(se->conn.want & FUSE_CAP_SPLICE_READ))
+ !(se->conn.want_ext & FUSE_CAP_SPLICE_READ))
goto fallback;
llp = fuse_ll_get_pipe(se);
diff --git a/test/test_write_cache.c b/test/test_write_cache.c
index cc827c7..d3c7af0 100644
--- a/test/test_write_cache.c
+++ b/test/test_write_cache.c
@@ -65,7 +65,7 @@ static void tfs_init (void *userdata, struct fuse_conn_info *conn)
(void) userdata;
if(options.writeback) {
- assert(conn->capable & FUSE_CAP_WRITEBACK_CACHE);
+ assert(fuse_get_feature_flag(conn, FUSE_CAP_WRITEBACK_CACHE));
conn->want |= FUSE_CAP_WRITEBACK_CACHE;
}
}