Track inodes by hand when kEnableInodeTracking is true.
This helps us build confidence that our assumptions around node lifecycles
are correct.
Test: atest FuseDaemonHostTest
Change-Id: I81d793a95db732b4b22b6e20c6c11717290359f7
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
index 523226b..3e2569a 100644
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -55,6 +55,7 @@
#include <regex>
#include <thread>
#include <unordered_map>
+#include <unordered_set>
#include <vector>
#include "MediaProviderWrapper.h"
@@ -220,6 +221,11 @@
const size_t target_ = 32 * 1024 * 1024;
};
+// Whether inode tracking is enabled or not. When enabled, we maintain a
+// separate mapping from inode numbers to "live" nodes so we can detect when
+// we receive a request to a node that has been deleted.
+static constexpr bool kEnableInodeTracking = true;
+
/* Single FUSE mount */
struct fuse {
explicit fuse(const std::string& _path)
@@ -231,12 +237,19 @@
// because fuse_lowlevel_ops documents that the root inode is always one
// (see FUSE_ROOT_ID in fuse_lowlevel.h). There are no particular requirements
// on any of the other inodes in the FS.
- inline node* FromInode(__u64 inode) const {
+ inline node* FromInode(__u64 inode) {
if (inode == FUSE_ROOT_ID) {
return root;
}
- return node::FromInode(inode);
+ node* node = node::FromInode(inode);
+
+ if (kEnableInodeTracking) {
+ std::lock_guard<std::recursive_mutex> guard(lock);
+ CHECK(inode_tracker_.find(node) != inode_tracker_.end());
+ }
+
+ return node;
}
inline __u64 ToInode(node* node) const {
@@ -247,6 +260,26 @@
return node::ToInode(node);
}
+ // Notify this FUSE instance that one of its nodes has been deleted.
+ void NodeDeleted(const node* node) {
+ if (kEnableInodeTracking) {
+ LOG(INFO) << "Node: " << node << " deleted.";
+
+ std::lock_guard<std::recursive_mutex> guard(lock);
+ inode_tracker_.erase(node);
+ }
+ }
+
+ // Notify this FUSE instance that a new nodes has been created.
+ void NodeCreated(const node* node) {
+ if (kEnableInodeTracking) {
+ LOG(INFO) << "Node: " << node << " created.";
+
+ std::lock_guard<std::recursive_mutex> guard(lock);
+ inode_tracker_.insert(node);
+ }
+ }
+
std::recursive_mutex lock;
const string path;
node* const root;
@@ -265,6 +298,8 @@
/* const */ char* zero_addr;
FAdviser fadviser;
+
+ std::unordered_set<const node*> inode_tracker_;
};
static inline const char* safe_name(node* n) {
@@ -347,6 +382,7 @@
node->Acquire();
} else {
node = ::node::Create(parent, name, &fuse->lock);
+ fuse->NodeCreated(node);
}
// Manipulate attr here if needed
@@ -452,7 +488,9 @@
// 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
// forget requests with a 64 bit counter.
- node->Release(static_cast<uint32_t>(nlookup));
+ if (node->Release(static_cast<uint32_t>(nlookup))) {
+ fuse->NodeDeleted(node);
+ }
}
}