aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/fuse.c9
-rw-r--r--lib/fuse_i.h38
-rw-r--r--lib/fuse_lowlevel.c78
-rw-r--r--lib/fuse_versionscript10
-rw-r--r--lib/helper.c15
-rw-r--r--lib/util.c8
-rw-r--r--lib/util.h3
7 files changed, 112 insertions, 49 deletions
diff --git a/lib/fuse.c b/lib/fuse.c
index 4964de2..8591454 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -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);
diff --git a/lib/util.c b/lib/util.c
index a529d38..956c3d2 100644
--- a/lib/util.c
+++ b/lib/util.c
@@ -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;
}
+
diff --git a/lib/util.h b/lib/util.h
index ed03ad4..f24401a 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -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);
/**