summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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) {