diff options
-rw-r--r-- | jni/FuseDaemon.cpp | 50 |
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) { |