diff options
-rw-r--r-- | TEST_MAPPING | 3 | ||||
-rw-r--r-- | jni/FuseDaemon.cpp | 117 | ||||
-rw-r--r-- | jni/node-inl.h | 11 | ||||
-rw-r--r-- | jni/node.cpp | 33 |
4 files changed, 80 insertions, 84 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING index 06b2f3875..7af0ca8eb 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -22,6 +22,9 @@ }, { "name": "FuseDaemonHostTest" + }, + { + "name": "fuse_node_test" } ] } diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp index 3bd9ea4d6..f960a9a7d 100644 --- a/jni/FuseDaemon.cpp +++ b/jni/FuseDaemon.cpp @@ -74,10 +74,8 @@ using std::string; using std::vector; // logging macros to avoid duplication. -#define TRACE LOG(DEBUG) -#define TRACE_VERBOSE LOG(VERBOSE) -#define TRACE_FUSE(__fuse) TRACE << "[" << __fuse->path << "] " -#define TRACE_FUSE_VERBOSE(__fuse) TRACE_VERBOSE << "[" << __fuse->path << "] " +#define TRACE_NODE(__node) \ + LOG(DEBUG) << __FUNCTION__ << " : " << #__node << " = [" << safe_name(__node) << "] " #define ATRACE_NAME(name) ScopedTrace ___tracer(name) #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__) @@ -319,8 +317,8 @@ struct fuse { std::unordered_set<const node*> inode_tracker_; }; -static inline const char* safe_name(node* n) { - return n ? n->GetName().c_str() : "?"; +static inline string safe_name(node* n) { + return n ? n->BuildSafePath() : "?"; } static inline __u64 ptr_to_id(void* ptr) { @@ -336,7 +334,6 @@ static inline __u64 ptr_to_id(void* ptr) { */ static int set_file_lock(int fd, bool for_read, const std::string& path) { std::string lock_str = (for_read ? "read" : "write"); - TRACE_VERBOSE << "Setting " << lock_str << " lock for path " << path; struct flock fl{}; fl.l_type = for_read ? F_RDLCK : F_WRLCK; @@ -344,10 +341,9 @@ static int set_file_lock(int fd, bool for_read, const std::string& path) { int res = fcntl(fd, F_OFD_SETLK, &fl); if (res) { - PLOG(ERROR) << "Failed to set " << lock_str << " lock on path " << path; + PLOG(WARNING) << "Failed to set lock: " << lock_str; return res; } - TRACE_VERBOSE << "Successfully set " << lock_str << " lock on path " << path; return res; } @@ -361,20 +357,17 @@ static int set_file_lock(int fd, bool for_read, const std::string& path) { * Returns true if fd may have a lock, false otherwise */ static bool is_file_locked(int fd, const std::string& path) { - TRACE_VERBOSE << "Checking if file is locked " << path; - struct flock fl{}; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; int res = fcntl(fd, F_OFD_GETLK, &fl); if (res) { - PLOG(ERROR) << "Failed to check lock for file " << path; + PLOG(WARNING) << "Failed to check lock"; // Assume worst return true; } bool locked = fl.l_type != F_UNLCK; - TRACE_VERBOSE << "File " << path << " is " << (locked ? "locked" : "unlocked"); return locked; } @@ -424,6 +417,7 @@ static node* make_node_entry(fuse_req_t req, node* parent, const string& name, c fuse->NodeCreated(node); } + TRACE_NODE(node); // This FS is not being exported via NFS so just a fixed generation number // for now. If we do need this, we need to increment the generation ID each // time the fuse daemon restarts because that's what it takes for us to @@ -474,12 +468,10 @@ static node* do_lookup(fuse_req_t req, fuse_ino_t parent, const char* name, const struct fuse_ctx* ctx = fuse_req_ctx(req); node* parent_node = fuse->FromInode(parent); string parent_path = parent_node->BuildPath(); - - TRACE_FUSE_VERBOSE(fuse) << "LOOKUP " << name << " @ " << parent << " (" - << safe_name(parent_node) << ")"; - string child_path = parent_path + "/" + name; + TRACE_NODE(parent_node); + std::smatch match; std::regex_search(child_path, match, storage_emulated_regex); if (match.size() == 2 && std::to_string(getuid() / PER_USER_RANGE) != match[1].str()) { @@ -505,7 +497,7 @@ static void pf_lookup(fuse_req_t req, fuse_ino_t parent, const char* name) { static void do_forget(struct fuse* fuse, fuse_ino_t ino, uint64_t nlookup) { node* node = fuse->FromInode(ino); - TRACE_FUSE(fuse) << "FORGET #" << nlookup << " @ " << ino << " (" << safe_name(node) << ")"; + TRACE_NODE(node); if (node) { // This is a narrowing conversion from an unsigned 64bit to a 32bit value. For // some reason we only keep 32 bit refcounts but the kernel issues @@ -545,7 +537,7 @@ static void pf_getattr(fuse_req_t req, const struct fuse_ctx* ctx = fuse_req_ctx(req); node* node = fuse->FromInode(ino); string path = node->BuildPath(); - TRACE_FUSE(fuse) << "GETATTR @ " << ino << " (" << safe_name(node) << ")"; + TRACE_NODE(node); if (!node) fuse_reply_err(req, ENOENT); @@ -570,7 +562,7 @@ static void pf_setattr(fuse_req_t req, string path = node->BuildPath(); struct timespec times[2]; - TRACE_FUSE(fuse) << "SETATTR valid=" << to_set << " @ " << ino << "(" << safe_name(node) << ")"; + TRACE_NODE(node); if (!node) { fuse_reply_err(req, ENOENT); @@ -611,8 +603,8 @@ static void pf_setattr(fuse_req_t req, // times[1].tv_nsec = attr->st_mtime.tv_nsec; } } - TRACE_FUSE(fuse) << "Calling utimensat on " << path << " with atime " << times[0].tv_sec - << " mtime=" << times[1].tv_sec; + + TRACE_NODE(node); if (utimensat(-1, path.c_str(), times, 0) < 0) { fuse_reply_err(req, errno); return; @@ -646,8 +638,7 @@ static void pf_mknod(fuse_req_t req, node* parent_node = fuse->FromInode(parent); string parent_path = parent_node->BuildPath(); - TRACE_FUSE(fuse) << "MKNOD " << name << " 0" << std::oct << mode << " @ " << parent << " (" - << safe_name(parent_node) << ")"; + TRACE_NODE(parent_node); if (!parent_node) { fuse_reply_err(req, ENOENT); @@ -681,8 +672,7 @@ static void pf_mkdir(fuse_req_t req, node* parent_node = fuse->FromInode(parent); const string parent_path = parent_node->BuildPath(); - TRACE_FUSE(fuse) << "MKDIR " << name << " 0" << std::oct << mode << " @ " << parent << " (" - << safe_name(parent_node) << ")"; + TRACE_NODE(parent_node); const string child_path = parent_path + "/" + name; @@ -715,7 +705,7 @@ static void pf_unlink(fuse_req_t req, fuse_ino_t parent, const char* name) { node* parent_node = fuse->FromInode(parent); const string parent_path = parent_node->BuildPath(); - TRACE_FUSE(fuse) << "UNLINK " << name << " @ " << parent << "(" << safe_name(parent_node) << ")"; + TRACE_NODE(parent_node); const string child_path = parent_path + "/" + name; @@ -726,6 +716,7 @@ static void pf_unlink(fuse_req_t req, fuse_ino_t parent, const char* name) { } node* child_node = parent_node->LookupChildByName(name, false /* acquire */); + TRACE_NODE(child_node); if (child_node) { child_node->SetDeleted(); } @@ -740,7 +731,7 @@ static void pf_rmdir(fuse_req_t req, fuse_ino_t parent, const char* name) { node* parent_node = fuse->FromInode(parent); const string parent_path = parent_node->BuildPath(); - TRACE_FUSE(fuse) << "RMDIR " << name << " @ " << parent << "(" << safe_name(parent_node) << ")"; + TRACE_NODE(parent_node); const string child_path = parent_path + "/" + name; @@ -756,6 +747,7 @@ static void pf_rmdir(fuse_req_t req, fuse_ino_t parent, const char* name) { } node* child_node = parent_node->LookupChildByName(name, false /* acquire */); + TRACE_NODE(child_node); if (child_node) { child_node->SetDeleted(); } @@ -776,7 +768,6 @@ static int do_rename(fuse_req_t req, fuse_ino_t parent, const char* name, fuse_i const struct fuse_ctx* ctx = fuse_req_ctx(req); if (flags != 0) { - LOG(ERROR) << "One or more rename flags not supported"; return EINVAL; } @@ -792,11 +783,11 @@ static int do_rename(fuse_req_t req, fuse_ino_t parent, const char* name, fuse_i return 0; } - TRACE_FUSE(fuse) << "RENAME " << name << " -> " << new_name << " @ " << parent << " (" - << safe_name(old_parent_node) << ") -> " << new_parent << " (" - << safe_name(new_parent_node) << ")"; + TRACE_NODE(old_parent_node); + TRACE_NODE(new_parent_node); node* child_node = old_parent_node->LookupChildByName(name, true /* acquire */); + TRACE_NODE(child_node) << "old_child"; const string old_child_path = child_node->BuildPath(); const string new_child_path = new_parent_path + "/" + new_name; @@ -808,6 +799,7 @@ static int do_rename(fuse_req_t req, fuse_ino_t parent, const char* name, fuse_i if (res == 0) { child_node->Rename(new_name, new_parent_node); } + TRACE_NODE(child_node) << "new_child"; child_node->Release(1); return res; @@ -834,8 +826,7 @@ static void pf_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) { node* node = fuse->FromInode(ino); const string path = node->BuildPath(); - TRACE_FUSE(fuse) << "OPEN 0" << std::oct << fi->flags << " @ " << ino << " (" << safe_name(node) - << ")"; + TRACE_NODE(node) << (is_requesting_write(fi->flags) ? "write" : "read"); if (!node) { fuse_reply_err(req, ENOENT); @@ -847,7 +838,6 @@ static void pf_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) { fi->direct_io = true; } - TRACE_FUSE(fuse) << "OPEN " << path; int status = fuse->mp->IsOpenAllowed(path, ctx->uid, is_requesting_write(fi->flags)); if (status) { fuse_reply_err(req, status); @@ -896,14 +886,7 @@ static void pf_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) { // b. Reading from a FUSE fd with caching enabled may not see the latest writes using the // lower fs fd because those writes did not go through the FUSE layer and reads from FUSE // after that write may be served from cache - if (ri->isRedactionNeeded()) { - TRACE_FUSE(fuse) << "Using direct io for " << path << " because redaction is needed."; - } else { - TRACE_FUSE(fuse) << "Using direct io for " << path << " because the file is locked."; - } fi->direct_io = true; - } else { - TRACE_FUSE(fuse) << "Using cache for " << path; } handle* h = new handle(path, fd, ri.release(), /*owner_uid*/ -1, !fi->direct_io); @@ -1097,7 +1080,7 @@ static void pf_flush(fuse_req_t req, struct fuse_file_info* fi) { ATRACE_CALL(); struct fuse* fuse = get_fuse(req); - TRACE_FUSE(fuse) << "FLUSH is a noop"; + TRACE_NODE(nullptr) << "noop"; fuse_reply_err(req, 0); } @@ -1109,8 +1092,7 @@ static void pf_release(fuse_req_t req, node* node = fuse->FromInode(ino); handle* h = reinterpret_cast<handle*>(fi->fh); - TRACE_FUSE(fuse) << "RELEASE " - << "0" << std::oct << fi->flags << " " << h << "(" << h->fd << ")"; + TRACE_NODE(node); fuse->fadviser.Close(h->fd); if (node) { @@ -1162,7 +1144,7 @@ static void pf_opendir(fuse_req_t req, node* node = fuse->FromInode(ino); const string path = node->BuildPath(); - TRACE_FUSE(fuse) << "OPENDIR @ " << ino << " (" << safe_name(node) << ")" << path; + TRACE_NODE(node); if (!node) { fuse_reply_err(req, ENOENT); @@ -1209,7 +1191,7 @@ static void do_readdir_common(fuse_req_t req, node* node = fuse->FromInode(ino); const string path = node->BuildPath(); - TRACE_FUSE(fuse) << "READDIR @" << ino << " " << path << " at offset " << off; + TRACE_NODE(node); // Get all directory entries from MediaProvider on first readdir() call of // directory handle. h->next_off = 0 indicates that current readdir() call // is first readdir() call for the directory handle, Avoid multiple JNI calls @@ -1296,7 +1278,7 @@ static void pf_releasedir(fuse_req_t req, node* node = fuse->FromInode(ino); dirhandle* h = reinterpret_cast<dirhandle*>(fi->fh); - TRACE_FUSE(fuse) << "RELEASEDIR " << h; + TRACE_NODE(node); if (node) { node->DestroyDirHandle(h); } @@ -1344,7 +1326,7 @@ static void pf_access(fuse_req_t req, fuse_ino_t ino, int mask) { node* node = fuse->FromInode(ino); const string path = node->BuildPath(); - TRACE_FUSE_VERBOSE(fuse) << "ACCESS " << path; + TRACE_NODE(node); int res = access(path.c_str(), F_OK); fuse_reply_err(req, res ? errno : 0); @@ -1361,14 +1343,12 @@ static void pf_create(fuse_req_t req, node* parent_node = fuse->FromInode(parent); const string parent_path = parent_node->BuildPath(); - TRACE_FUSE(fuse) << "CREATE " << name << " 0" << std::oct << fi->flags << " @ " << parent - << " (" << safe_name(parent_node) << ")"; + TRACE_NODE(parent_node); const string child_path = parent_path + "/" + name; int mp_return_code = fuse->mp->InsertFile(child_path.c_str(), ctx->uid); if (mp_return_code) { - PLOG(DEBUG) << "Could not create file: " << child_path; fuse_reply_err(req, mp_return_code); return; } @@ -1403,6 +1383,7 @@ static void pf_create(fuse_req_t req, int error_code = 0; struct fuse_entry_param e; node* node = make_node_entry(req, parent_node, name, child_path, &e, &error_code); + TRACE_NODE(node); if (node) { node->AddHandle(h); fuse_reply_create(req, &e, fi); @@ -1464,21 +1445,17 @@ static void pf_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, */ static struct fuse_lowlevel_ops ops{ - .init = pf_init, - .destroy = pf_destroy, - .lookup = pf_lookup, .forget = pf_forget, .getattr = pf_getattr, - .setattr = pf_setattr, - .canonical_path = pf_canonical_path, - .mknod = pf_mknod, .mkdir = pf_mkdir, .unlink = pf_unlink, - .rmdir = pf_rmdir, + .init = pf_init, .destroy = pf_destroy, .lookup = pf_lookup, .forget = pf_forget, + .getattr = pf_getattr, .setattr = pf_setattr, .canonical_path = pf_canonical_path, + .mknod = pf_mknod, .mkdir = pf_mkdir, .unlink = pf_unlink, .rmdir = pf_rmdir, /*.symlink = pf_symlink,*/ .rename = pf_rename, /*.link = pf_link,*/ .open = pf_open, .read = pf_read, /*.write = pf_write,*/ - .flush = pf_flush, .release = pf_release, .fsync = pf_fsync, - .opendir = pf_opendir, .readdir = pf_readdir, .releasedir = pf_releasedir, - .fsyncdir = pf_fsyncdir, .statfs = pf_statfs, + .flush = pf_flush, + .release = pf_release, .fsync = pf_fsync, .opendir = pf_opendir, .readdir = pf_readdir, + .releasedir = pf_releasedir, .fsyncdir = pf_fsyncdir, .statfs = pf_statfs, /*.setxattr = pf_setxattr, .getxattr = pf_getxattr, .listxattr = pf_listxattr, @@ -1519,32 +1496,26 @@ static void fuse_logger(enum fuse_log_level level, const char* fmt, va_list ap) } bool FuseDaemon::ShouldOpenWithFuse(int fd, bool for_read, const std::string& path) { - TRACE_VERBOSE << "Checking if file should be opened with FUSE " << path; bool use_fuse = false; if (active.load(std::memory_order_acquire)) { const node* node = node::LookupAbsolutePath(fuse->root, path); if (node && node->HasCachedHandle()) { - TRACE << "Should open " << path << " with FUSE. Reason: cache"; use_fuse = true; } else { // If we are unable to set a lock, we should use fuse since we can't track // when all fd references (including dups) are closed. This can happen when // we try to set a write lock twice on the same file use_fuse = set_file_lock(fd, for_read, path); - TRACE << "Should open " << path << (use_fuse ? " with" : " without") - << " FUSE. Reason: lock"; } } else { - TRACE << "FUSE daemon is inactive. Should not open " << path << " with FUSE"; + LOG(WARNING) << "FUSE daemon is inactive. Cannot open file with FUSE"; } return use_fuse; } void FuseDaemon::InvalidateFuseDentryCache(const std::string& path) { - TRACE_VERBOSE << "Invalidating dentry for path " << path; - if (active.load(std::memory_order_acquire)) { string name; fuse_ino_t parent; @@ -1560,10 +1531,10 @@ void FuseDaemon::InvalidateFuseDentryCache(const std::string& path) { if (!name.empty() && fuse_lowlevel_notify_inval_entry(fuse->se, parent, name.c_str(), name.size())) { - LOG(ERROR) << "Failed to invalidate dentry for path " << path; + LOG(WARNING) << "Failed to invalidate dentry for path"; } } else { - TRACE << "FUSE daemon is inactive. Cannot invalidate dentry for " << path; + LOG(WARNING) << "FUSE daemon is inactive. Cannot invalidate dentry"; } } @@ -1579,12 +1550,12 @@ void FuseDaemon::Start(const int fd, const std::string& path) { struct stat stat; if (lstat(path.c_str(), &stat)) { - LOG(ERROR) << "ERROR: failed to stat source " << path; + PLOG(ERROR) << "ERROR: failed to stat source " << path; return; } if (!S_ISDIR(stat.st_mode)) { - LOG(ERROR) << "ERROR: source is not a directory"; + PLOG(ERROR) << "ERROR: source is not a directory"; return; } diff --git a/jni/node-inl.h b/jni/node-inl.h index 921dfe26e..2aa3b138f 100644 --- a/jni/node-inl.h +++ b/jni/node-inl.h @@ -22,6 +22,7 @@ #include <list> #include <memory> #include <mutex> +#include <sstream> #include <string> #include <vector> @@ -114,6 +115,10 @@ class node { // associated with its descendants. std::string BuildPath() const; + // Builds the full PII safe path associated with this node, including all path segments + // associated with its descendants. + std::string BuildSafePath() const; + // Looks up a direct descendant of this node by name. If |acquire| is true, // also Acquire the node before returning a reference to it. node* LookupChildByName(const std::string& name, bool acquire) const { @@ -262,9 +267,9 @@ class node { } } - // A helper function to recursively construct the absolute path of a given - // node. - static void BuildPathForNodeRecursive(node* node, std::string* path); + // A helper function to recursively construct the absolute path of a given node. + // If |safe| is true, builds a PII safe path instead + void BuildPathForNodeRecursive(bool safe, const node* node, std::stringstream* path) const; // The name of this node. Non-const because it can change during renames. std::string name_; diff --git a/jni/node.cpp b/jni/node.cpp index 8898b7b5b..618777442 100644 --- a/jni/node.cpp +++ b/jni/node.cpp @@ -41,20 +41,37 @@ namespace mediaprovider { namespace fuse { // Assumes that |node| has at least one child. -void node::BuildPathForNodeRecursive(node* node, std::string* path) { - if (node->parent_) BuildPathForNodeRecursive(node->parent_, path); +void node::BuildPathForNodeRecursive(bool safe, const node* node, std::stringstream* path) const { + if (node->parent_) { + BuildPathForNodeRecursive(safe, node->parent_, path); + } - (*path) += node->GetName() + "/"; + if (safe && node->parent_) { + (*path) << reinterpret_cast<uintptr_t>(node); + } else { + (*path) << node->GetName(); + } + + if (node != this) { + // Must not add a '/' to the last segment + (*path) << "/"; + } } std::string node::BuildPath() const { std::lock_guard<std::recursive_mutex> guard(*lock_); - std::string path; + std::stringstream path; + + BuildPathForNodeRecursive(false, this, &path); + return path.str(); +} + +std::string node::BuildSafePath() const { + std::lock_guard<std::recursive_mutex> guard(*lock_); + std::stringstream path; - path.reserve(PATH_MAX); - if (parent_) BuildPathForNodeRecursive(parent_, &path); - path += name_; - return path; + BuildPathForNodeRecursive(true, this, &path); + return path.str(); } const node* node::LookupAbsolutePath(const node* root, const std::string& absolute_path) { |