diff options
author | Bernd Schubert <bschubert@ddn.com> | 2025-05-18 00:24:07 +0200 |
---|---|---|
committer | Bernd Schubert <bernd@bsbernd.com> | 2025-05-20 18:14:44 +0200 |
commit | baadab0492a495fda98216b351976d2e5d6d0866 (patch) | |
tree | 61017d2976439c6b7453b402aad5ecd3816b72ef /lib | |
parent | eadd6a5454373c7c404463c81be652275da5e07b (diff) | |
download | libfuse-baadab0492a495fda98216b351976d2e5d6d0866.tar.gz |
conn->want conversion: Fix fuse_apply_conn_info_opts()
fuse_apply_conn_info_opts() was applying to 'want_ext',
which would cause conflicts with 'want' if the application
applied its own flags to 'conn->want'.
Solution is:
- to move fuse_{set,unset,get}_feature_flag and
convert_to_conn_want_ext() to fuse_lowlevel.c and
to define them as part of the public API, although
convert_to_conn_want_ext() should not be used - it is
currently needed to be a public function due as it needs
to be defined for the tests.
Related to https://github.com/libfuse/libfuse/issues/1171 and
https://github.com/libfuse/libfuse/pull/1172.
Closes: https://github.com/libfuse/libfuse/issues/1171
Signed-off-by: Bernd Schubert <bschubert@ddn.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/fuse.c | 9 | ||||
-rw-r--r-- | lib/fuse_i.h | 38 | ||||
-rw-r--r-- | lib/fuse_lowlevel.c | 78 | ||||
-rw-r--r-- | lib/fuse_versionscript | 6 | ||||
-rw-r--r-- | lib/helper.c | 4 | ||||
-rw-r--r-- | lib/util.c | 8 | ||||
-rw-r--r-- | lib/util.h | 3 |
7 files changed, 99 insertions, 47 deletions
@@ -2560,15 +2560,8 @@ void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn, fuse_unset_feature_flag(conn, FUSE_CAP_POSIX_LOCKS); if (!fs->op.flock) fuse_unset_feature_flag(conn, FUSE_CAP_FLOCK_LOCKS); - if (fs->op.init) { - uint64_t want_ext_default = conn->want_ext; - uint32_t want_default = fuse_lower_32_bits(conn->want_ext); - - conn->want = want_default; + if (fs->op.init) fs->user_data = fs->op.init(conn, cfg); - - convert_to_conn_want_ext(conn, want_ext_default, want_default); - } } static int fuse_init_intr_signal(int signum, int *installed); diff --git a/lib/fuse_i.h b/lib/fuse_i.h index 14d99ad..80ec803 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -106,6 +106,13 @@ struct fuse_session { /* io_uring */ struct fuse_session_uring uring; + + /* + * conn->want and conn_want_ext options set by libfuse , needed + * to correctly convert want to want_ext + */ + uint32_t conn_want; + uint64_t conn_want_ext; }; struct fuse_chan { @@ -250,36 +257,5 @@ int fuse_loop_cfg_verify(struct fuse_loop_config *config); /* room needed in buffer to accommodate header */ #define FUSE_BUFFER_HEADER_SIZE 0x1000 -/** - * Get the wanted capability flags, converting from old format if necessary - */ -static inline int convert_to_conn_want_ext(struct fuse_conn_info *conn, - uint64_t want_ext_default, - uint32_t want_default) -{ - /* - * Convert want to want_ext if necessary. - * For the high level interface this function might be called - * twice, once from the high level interface and once from the - * low level interface. Both, with different want_ext_default and - * want_default values. In order to suppress a failure for the - * second call, we check if the lower 32 bits of want_ext are - * already set to the value of want. - */ - if (conn->want != want_default && - fuse_lower_32_bits(conn->want_ext) != conn->want) { - if (conn->want_ext != want_ext_default) - return -EINVAL; - - /* high bits from want_ext, low bits from want */ - conn->want_ext = fuse_higher_32_bits(conn->want_ext) | - conn->want; - } - - /* ensure there won't be a second conversion */ - conn->want = fuse_lower_32_bits(conn->want_ext); - - return 0; -} #endif /* LIB_FUSE_I_H_*/ diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 9fb793b..c2f3ccb 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -2435,6 +2435,77 @@ static bool want_flags_valid(uint64_t capable, uint64_t want) return true; } +/** + * Get the wanted capability flags, converting from old format if necessary + */ +int fuse_convert_to_conn_want_ext(struct fuse_conn_info *conn) +{ + struct fuse_session *se = container_of(conn, struct fuse_session, conn); + + /* + * Convert want to want_ext if necessary. + * For the high level interface this function might be called + * twice, once from the high level interface and once from the + * low level interface. Both, with different want_ext_default and + * want_default values. In order to suppress a failure for the + * second call, we check if the lower 32 bits of want_ext are + * already set to the value of want. + */ + if (conn->want != se->conn_want && + fuse_lower_32_bits(conn->want_ext) != conn->want) { + if (conn->want_ext != se->conn_want_ext) { + fuse_log(FUSE_LOG_ERR, + "%s: Both conn->want_ext and conn->want are set.\n" + "want=%x, want_ext=%lx, se->want=%lx se->want_ext=%lx\n", + __func__, conn->want, conn->want_ext, + se->conn_want, se->conn_want_ext); + return -EINVAL; + } + + /* high bits from want_ext, low bits from want */ + conn->want_ext = fuse_higher_32_bits(conn->want_ext) | + conn->want; + } + + /* ensure there won't be a second conversion */ + conn->want = fuse_lower_32_bits(conn->want_ext); + + return 0; +} + +bool fuse_set_feature_flag(struct fuse_conn_info *conn, + uint64_t flag) +{ + struct fuse_session *se = container_of(conn, struct fuse_session, conn); + + if (conn->capable_ext & flag) { + conn->want_ext |= flag; + se->conn_want_ext |= flag; + conn->want |= flag; + se->conn_want |= flag; + return true; + } + return false; +} + +void fuse_unset_feature_flag(struct fuse_conn_info *conn, + uint64_t flag) +{ + struct fuse_session *se = container_of(conn, struct fuse_session, conn); + + conn->want_ext &= ~flag; + se->conn_want_ext &= ~flag; + conn->want &= ~flag; + se->conn_want &= ~flag; +} + +bool fuse_get_feature_flag(struct fuse_conn_info *conn, + uint64_t flag) +{ + return conn->capable_ext & flag ? true : false; +} + + /* Prevent bogus data races (bogus since "init" is called before * multi-threading becomes relevant */ static __attribute__((no_sanitize("thread"))) void @@ -2603,12 +2674,8 @@ _do_init(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, se->got_init = 1; if (se->op.init) { - uint64_t want_ext_default = se->conn.want_ext; - uint32_t want_default = fuse_lower_32_bits(se->conn.want_ext); - // Apply the first 32 bits of capable_ext to capable se->conn.capable = fuse_lower_32_bits(se->conn.capable_ext); - se->conn.want = want_default; se->op.init(se->userdata, &se->conn); @@ -2617,8 +2684,7 @@ _do_init(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, * se->conn.want_ext * Userspace might still use conn.want - we need to convert it */ - convert_to_conn_want_ext(&se->conn, want_ext_default, - want_default); + fuse_convert_to_conn_want_ext(&se->conn); } if (!want_flags_valid(se->conn.capable_ext, se->conn.want_ext)) { diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index 22c59e1..ab57d7c 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -205,6 +205,12 @@ FUSE_3.17 { FUSE_3.18 { global: fuse_req_is_uring; + fuse_set_feature_flag; + fuse_unset_feature_flag; + fuse_get_feature_flag; + + # Not part of public API, for internal test use only + fuse_convert_to_conn_want_ext; } FUSE_3.17; # Local Variables: diff --git a/lib/helper.c b/lib/helper.c index 5811c53..ced70a2 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -430,13 +430,13 @@ void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts, #define LL_ENABLE(cond, cap) \ do { \ if (cond) \ - conn->want_ext |= (cap); \ + fuse_set_feature_flag(conn, cap); \ } while (0) #define LL_DISABLE(cond, cap) \ do { \ if (cond) \ - conn->want_ext &= ~(cap); \ + fuse_unset_feature_flag(conn, cap); \ } while (0) LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ); @@ -10,7 +10,14 @@ #include <stdlib.h> #include <errno.h> +#ifndef FUSE_USE_VERSION +#define FUSE_USE_VERSION (FUSE_MAKE_VERSION(3, 18)) +#endif + #include "util.h" +#include "fuse_log.h" +#include "fuse_lowlevel.h" +#include <stdio.h> int libfuse_strtol(const char *str, long *res) { @@ -44,3 +51,4 @@ void fuse_set_thread_name(unsigned long tid, const char *name) (void)name; #endif } + @@ -2,12 +2,15 @@ #define FUSE_UTIL_H_ #include <stdint.h> +#include <stdbool.h> #define ROUND_UP(val, round_to) (((val) + (round_to - 1)) & ~(round_to - 1)) #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) +struct fuse_conn_info; + int libfuse_strtol(const char *str, long *res); void fuse_set_thread_name(unsigned long tid, const char *name); |