summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlessio Balsini <balsini@google.com>2020-07-13 12:01:13 +0100
committeralk3pInjection <webmaster@raspii.tech>2021-10-12 21:01:08 +0800
commitee88d415f26a67d645b3bf9932c779659bf37d20 (patch)
tree808af56935d9ac3071ac576d599fcf2057c8dffa
parent7f3c7ead47af45d8e04a406164dfd57a7524ebcd (diff)
Enable fuse passthrough mode in FuseDaemon
This patch enables the FUSE passthrough feature in the MediaProvider. FUSE passthrough is activated only if "persist.sys.fuse.passthrough" is set to true. No further special conditions of the file are required for the passthrough feature to be enabled. FUSE passthrough is a feature that allows creating at OPEN/CREATE time a direct channel from the process accessing the FUSE file system to the file that lies in the lower file system. All the following read/write operations targeting a file that was opened with FUSE passthrough mode on target the lower file system directly, without the overhead of traversing the FUSE daemon. go/fuse-passthrough Bug: 168023149 Test: atest ScopedStorageTest Signed-off-by: Alessio Balsini <balsini@google.com> Change-Id: I3a4be233d0c8b1566b4eab72cf3be30b8d30353f Signed-off-by: alk3pInjection <webmaster@raspii.tech>
-rw-r--r--jni/FuseDaemon.cpp50
1 files changed, 48 insertions, 2 deletions
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
index ecb7092e..9dc8387c 100644
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -241,7 +241,8 @@ struct fuse {
tracker(mediaprovider::fuse::NodeTracker(&lock)),
root(node::CreateRoot(_path, &lock, &tracker)),
mp(0),
- zero_addr(0) {}
+ zero_addr(0),
+ passthrough(false) {}
inline bool IsRoot(const node* node) const { return node == root; }
@@ -295,6 +296,7 @@ struct fuse {
FAdviser fadviser;
std::atomic_bool* active;
+ bool passthrough;
};
static inline string get_name(node* n) {
@@ -469,15 +471,26 @@ namespace fuse {
*/
static void pf_init(void* userdata, struct fuse_conn_info* conn) {
+ struct fuse* fuse = reinterpret_cast<struct fuse*>(userdata);
+
// We don't want a getattr request with every read request
conn->want &= ~FUSE_CAP_AUTO_INVAL_DATA & ~FUSE_CAP_READDIRPLUS_AUTO;
unsigned mask = (FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE | FUSE_CAP_SPLICE_READ |
FUSE_CAP_ASYNC_READ | FUSE_CAP_ATOMIC_O_TRUNC | FUSE_CAP_WRITEBACK_CACHE |
FUSE_CAP_EXPORT_SUPPORT | FUSE_CAP_FLOCK_LOCKS);
+
+ if (fuse->passthrough) {
+ if (conn->capable & FUSE_CAP_PASSTHROUGH) {
+ mask |= FUSE_CAP_PASSTHROUGH;
+ } else {
+ LOG(WARNING) << "Passthrough feature not supported by the kernel";
+ fuse->passthrough = false;
+ }
+ }
+
conn->want |= conn->capable & mask;
conn->max_read = MAX_READ_SIZE;
- struct fuse* fuse = reinterpret_cast<struct fuse*>(userdata);
fuse->active->store(true, std::memory_order_release);
}
@@ -978,6 +991,17 @@ static handle* create_handle_for_node(struct fuse* fuse, const string& path, int
return h;
}
+bool do_passthrough_enable(fuse_req_t req, struct fuse_file_info* fi, unsigned int fd) {
+ int passthrough_fh = fuse_passthrough_enable(req, fd);
+
+ if (passthrough_fh <= 0) {
+ return false;
+ }
+
+ fi->passthrough_fh = passthrough_fh;
+ return true;
+}
+
static void pf_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
ATRACE_CALL();
struct fuse* fuse = get_fuse(req);
@@ -1042,6 +1066,16 @@ static void pf_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
fi->fh = ptr_to_id(h);
fi->keep_cache = 1;
fi->direct_io = !h->cached;
+
+ // TODO(b/173190192) ensuring that h->cached must be enabled in order to
+ // user FUSE passthrough is a conservative rule and might be dropped as
+ // soon as demonstrated its correctness.
+ if (fuse->passthrough && h->cached) {
+ if (!do_passthrough_enable(req, fi, fd)) {
+ LOG(WARNING) << "Passthrough OPEN failed for " << path;
+ }
+ }
+
fuse_reply_open(req, fi);
}
@@ -1604,6 +1638,16 @@ static void pf_create(fuse_req_t req,
fi->fh = ptr_to_id(h);
fi->keep_cache = 1;
fi->direct_io = !h->cached;
+
+ // TODO(b/173190192) ensuring that h->cached must be enabled in order to
+ // user FUSE passthrough is a conservative rule and might be dropped as
+ // soon as demonstrated its correctness.
+ if (fuse->passthrough && h->cached) {
+ if (!do_passthrough_enable(req, fi, fd)) {
+ LOG(WARNING) << "Passthrough CREATE failed for " << child_path;
+ }
+ }
+
fuse_reply_create(req, &e, fi);
}
/*
@@ -1806,6 +1850,8 @@ void FuseDaemon::Start(android::base::unique_fd fd, const std::string& path) {
fuse_set_log_func(fuse_logger);
}
+ fuse->passthrough = android::base::GetBoolProperty("persist.sys.fuse.passthrough", false);
+
struct fuse_session
* se = fuse_session_new(&args, &ops, sizeof(ops), &fuse_default);
if (!se) {