aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/fuse_lowlevel.c77
-rw-r--r--lib/fuse_versionscript1
2 files changed, 78 insertions, 0 deletions
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index fc76b7c..a4a4df0 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -27,6 +27,7 @@
#include <errno.h>
#include <assert.h>
#include <sys/file.h>
+#include <sys/ioctl.h>
#ifndef F_LINUX_SPECIFIC_BASE
#define F_LINUX_SPECIFIC_BASE 1024
@@ -388,6 +389,7 @@ static void fill_open(struct fuse_open_out *arg,
const struct fuse_file_info *f)
{
arg->fh = f->fh;
+ arg->passthrough_fh = f->passthrough_fh;
if (f->direct_io)
arg->open_flags |= FOPEN_DIRECT_IO;
if (f->keep_cache)
@@ -457,6 +459,77 @@ int fuse_reply_canonical_path(fuse_req_t req, const char *path)
return send_reply_ok(req, path, strlen(path) + 1);
}
+enum {
+ FUSE_PASSTHROUGH_API_UNAVAILABLE,
+ FUSE_PASSTHROUGH_API_V0,
+ FUSE_PASSTHROUGH_API_V1,
+ FUSE_PASSTHROUGH_API_V2,
+ FUSE_PASSTHROUGH_API_STABLE,
+};
+
+/*
+ * Requests the FUSE passthrough feature to be enabled on a specific file
+ * through the passed fd.
+ * This function returns an identifier that must be used as passthrough_fh
+ * when the open/create_open request reply is sent back to /dev/fuse.
+ * As for the current FUSE passthrough implementation, passthrough_fh values
+ * are only valid if > 0, so in case the FUSE passthrough open ioctl returns
+ * a value <= 0, this must be considered an error and is returned as-is by
+ * this function.
+ */
+int fuse_passthrough_enable(fuse_req_t req, unsigned int fd) {
+ static sig_atomic_t passthrough_version = FUSE_PASSTHROUGH_API_STABLE;
+ int ret = 0; /* values <= 0 represent errors in FUSE passthrough */
+
+ /*
+ * The interface of FUSE passthrough is still unstable in the kernel,
+ * so the following solution is to search for the most updated API
+ * version and, if not found, fall back to an older one.
+ * This happens when ioctl() returns -1 and errno is set to ENOTTY,
+ * an error code that corresponds to the lack of a specific ioctl.
+ */
+ switch (passthrough_version) {
+ case FUSE_PASSTHROUGH_API_STABLE:
+ /* There is not a stable API yet */
+ passthrough_version = FUSE_PASSTHROUGH_API_V2;
+ case FUSE_PASSTHROUGH_API_V2: {
+ ret = ioctl(req->se->fd, FUSE_DEV_IOC_PASSTHROUGH_OPEN_V2, &fd);
+ if (ret == -1 && errno == ENOTTY)
+ passthrough_version = FUSE_PASSTHROUGH_API_V1;
+ else
+ break;
+ }
+ case FUSE_PASSTHROUGH_API_V1: {
+ struct fuse_passthrough_out_v0 out = {};
+ out.fd = fd;
+
+ ret = ioctl(req->se->fd, FUSE_DEV_IOC_PASSTHROUGH_OPEN_V1, &out);
+ if (ret == -1 && errno == ENOTTY)
+ passthrough_version = FUSE_PASSTHROUGH_API_V0;
+ else
+ break;
+ }
+ case FUSE_PASSTHROUGH_API_V0: {
+ struct fuse_passthrough_out_v0 out = {};
+ out.fd = fd;
+
+ ret = ioctl(req->se->fd, FUSE_DEV_IOC_PASSTHROUGH_OPEN_V0, &out);
+ if (ret == -1 && errno == ENOTTY)
+ passthrough_version = FUSE_PASSTHROUGH_API_UNAVAILABLE;
+ else
+ break;
+ }
+ default:
+ fuse_log(FUSE_LOG_ERR, "fuse: passthrough_enable no valid API\n");
+ return -ENOTTY;
+ }
+
+ if (ret <= 0)
+ fuse_log(FUSE_LOG_ERR, "fuse: passthrough_enable: %s\n", strerror(errno));
+
+ return ret;
+}
+
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
{
struct fuse_open_out arg;
@@ -1990,6 +2063,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
bufsize = max_bufsize;
}
}
+ if (arg->flags & FUSE_PASSTHROUGH)
+ se->conn.capable |= FUSE_PASSTHROUGH;
} else {
se->conn.max_readahead = 0;
}
@@ -2102,6 +2177,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
outarg.flags |= FUSE_WRITEBACK_CACHE;
if (se->conn.want & FUSE_CAP_POSIX_ACL)
outarg.flags |= FUSE_POSIX_ACL;
+ if (se->conn.want & FUSE_CAP_PASSTHROUGH)
+ outarg.flags |= FUSE_PASSTHROUGH;
outarg.max_readahead = se->conn.max_readahead;
outarg.max_write = se->conn.max_write;
if (se->conn.proto_minor >= 13) {
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index 4c075a3..b01699a 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -163,6 +163,7 @@ FUSE_3.7 {
global:
fuse_set_log_func;
fuse_log;
+ fuse_passthrough_enable;
fuse_reply_canonical_path;
} FUSE_3.3;