aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/fuse_lowlevel.c43
-rw-r--r--lib/fuse_versionscript2
2 files changed, 45 insertions, 0 deletions
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index c08c99c..1f3a5fa 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
@@ -400,6 +401,10 @@ static void fill_open(struct fuse_open_out *arg,
const struct fuse_file_info *f)
{
arg->fh = f->fh;
+ if (f->backing_id > 0) {
+ arg->backing_id = f->backing_id;
+ arg->open_flags |= FOPEN_PASSTHROUGH;
+ }
if (f->direct_io)
arg->open_flags |= FOPEN_DIRECT_IO;
if (f->keep_cache)
@@ -466,6 +471,31 @@ int fuse_reply_readlink(fuse_req_t req, const char *linkname)
return send_reply_ok(req, linkname, strlen(linkname));
}
+int fuse_passthrough_open(fuse_req_t req, int fd)
+{
+ struct fuse_backing_map map = { .fd = fd };
+ int ret;
+
+ ret = ioctl(req->se->fd, FUSE_DEV_IOC_BACKING_OPEN, &map);
+ if (ret <= 0) {
+ fuse_log(FUSE_LOG_ERR, "fuse: passthrough_open: %s\n", strerror(errno));
+ return 0;
+ }
+
+ return ret;
+}
+
+int fuse_passthrough_close(fuse_req_t req, int backing_id)
+{
+ int ret;
+
+ ret = ioctl(req->se->fd, FUSE_DEV_IOC_BACKING_CLOSE, &backing_id);
+ if (ret < 0)
+ fuse_log(FUSE_LOG_ERR, "fuse: passthrough_close: %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;
@@ -2027,6 +2057,8 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
se->conn.capable |= FUSE_CAP_DIRECT_IO_ALLOW_MMAP;
if (arg->minor >= 38 || (inargflags & FUSE_HAS_EXPIRE_ONLY))
se->conn.capable |= FUSE_CAP_EXPIRE_ONLY;
+ if (inargflags & FUSE_PASSTHROUGH)
+ se->conn.capable |= FUSE_CAP_PASSTHROUGH;
} else {
se->conn.max_readahead = 0;
}
@@ -2161,6 +2193,14 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
outargflags |= FUSE_SETXATTR_EXT;
if (se->conn.want & FUSE_CAP_DIRECT_IO_ALLOW_MMAP)
outargflags |= FUSE_DIRECT_IO_ALLOW_MMAP;
+ if (se->conn.want & FUSE_CAP_PASSTHROUGH) {
+ outargflags |= FUSE_PASSTHROUGH;
+ /*
+ * outarg.max_stack_depth includes the fuse stack layer,
+ * so it is one more than max_backing_stack_depth.
+ */
+ outarg.max_stack_depth = se->conn.max_backing_stack_depth + 1;
+ }
if (inargflags & FUSE_INIT_EXT) {
outargflags |= FUSE_INIT_EXT;
@@ -2199,6 +2239,9 @@ 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)
+ fuse_log(FUSE_LOG_DEBUG, " max_stack_depth=%u\n",
+ outarg.max_stack_depth);
}
if (arg->minor < 5)
outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index 22782bc..d0b98f6 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -194,6 +194,8 @@ FUSE_3.17 {
_fuse_new_30;
_fuse_new_317;
fuse_main_real_317;
+ fuse_passthrough_open;
+ fuse_passthrough_close;
} FUSE_3.12;
# Local Variables: