diff options
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 | 10 | ||||
-rw-r--r-- | lib/helper.c | 15 | ||||
-rw-r--r-- | lib/util.c | 8 | ||||
-rw-r--r-- | lib/util.h | 3 |
7 files changed, 112 insertions, 49 deletions
@@ -2611,15 +2611,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 bf5e2ca..718fa14 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -85,6 +85,13 @@ struct fuse_session { /* true if reading requests from /dev/fuse are handled internally */ bool buf_reallocable; + + /* + * 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 { @@ -227,34 +234,3 @@ 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; -} diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index cb046aa..1276a0f 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -1994,6 +1994,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"))) @@ -2154,12 +2225,8 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 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); @@ -2168,8 +2235,7 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) * 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 6c5fc83..a2653fc 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -202,6 +202,16 @@ FUSE_3.17 { fuse_log_close_syslog; } FUSE_3.12; +FUSE_3.17.3 { + global: + 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: # indent-tabs-mode: t # End: diff --git a/lib/helper.c b/lib/helper.c index 59dd488..aceff9f 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -423,10 +423,17 @@ void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts, if(opts->set_max_readahead) conn->max_readahead = opts->max_readahead; -#define LL_ENABLE(cond,cap) \ - if (cond) conn->want_ext |= (cap) -#define LL_DISABLE(cond,cap) \ - if (cond) conn->want_ext &= ~(cap) +#define LL_ENABLE(cond, cap) \ + do { \ + if (cond) \ + fuse_set_feature_flag(conn, cap); \ + } while (0) + +#define LL_DISABLE(cond, cap) \ + do { \ + if (cond) \ + fuse_unset_feature_flag(conn, cap); \ + } while (0) LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ); LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ); @@ -1,7 +1,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) { @@ -25,3 +32,4 @@ int libfuse_strtol(const char *str, long *res) *res = val; return 0; } + @@ -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); /** |