summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jni/FuseDaemon.cpp27
-rw-r--r--jni/FuseDaemon.h5
-rw-r--r--jni/com_android_providers_media_FuseDaemon.cpp22
-rw-r--r--jni/node-inl.h5
-rw-r--r--src/com/android/providers/media/MediaProvider.java15
-rw-r--r--src/com/android/providers/media/fuse/FuseDaemon.java8
6 files changed, 74 insertions, 8 deletions
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
index 282a08834..d8c2f46be 100644
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -299,6 +299,7 @@ struct fuse {
std::recursive_mutex lock;
const string path;
node* const root;
+ struct fuse_session* se;
/*
* Used to make JNI calls to MediaProvider.
@@ -1540,6 +1541,31 @@ bool FuseDaemon::ShouldOpenWithFuse(int fd, bool for_read, const std::string& pa
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;
+
+ {
+ std::lock_guard<std::recursive_mutex> guard(fuse->lock);
+ const node* node = node::LookupAbsolutePath(fuse->root, path);
+ if (node) {
+ name = node->GetName();
+ parent = fuse->ToInode(node->GetParent());
+ }
+ }
+
+ 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;
+ }
+ } else {
+ TRACE << "FUSE daemon is inactive. Cannot invalidate dentry for " << path;
+ }
+}
+
FuseDaemon::FuseDaemon(JNIEnv* env, jobject mediaProvider) : mp(env, mediaProvider),
active(false), fuse(nullptr) {}
@@ -1594,6 +1620,7 @@ void FuseDaemon::Start(const int fd, const std::string& path) {
PLOG(ERROR) << "Failed to create session ";
return;
}
+ fuse_default.se = se;
se->fd = fd;
se->mountpoint = strdup(path.c_str());
diff --git a/jni/FuseDaemon.h b/jni/FuseDaemon.h
index 12338636e..1d25636bf 100644
--- a/jni/FuseDaemon.h
+++ b/jni/FuseDaemon.h
@@ -42,6 +42,11 @@ class FuseDaemon final {
*/
bool ShouldOpenWithFuse(int fd, bool for_read, const std::string& path);
+ /**
+ * Invalidate FUSE VFS dentry cache entry for path
+ */
+ void InvalidateFuseDentryCache(const std::string& path);
+
private:
FuseDaemon(const FuseDaemon&) = delete;
void operator=(const FuseDaemon&) = delete;
diff --git a/jni/com_android_providers_media_FuseDaemon.cpp b/jni/com_android_providers_media_FuseDaemon.cpp
index caf00b27b..87861cae6 100644
--- a/jni/com_android_providers_media_FuseDaemon.cpp
+++ b/jni/com_android_providers_media_FuseDaemon.cpp
@@ -73,6 +73,22 @@ jboolean com_android_providers_media_FuseDaemon_should_open_with_fuse(JNIEnv* en
return JNI_FALSE;
}
+void com_android_providers_media_FuseDaemon_invalidate_fuse_dentry_cache(JNIEnv* env, jobject self,
+ jlong java_daemon,
+ jstring java_path) {
+ fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
+ if (daemon) {
+ ScopedUtfChars utf_chars_path(env, java_path);
+ if (!utf_chars_path.c_str()) {
+ // TODO(b/145741152): Throw exception
+ return;
+ }
+
+ daemon->InvalidateFuseDentryCache(utf_chars_path.c_str());
+ }
+ // TODO(b/145741152): Throw exception
+}
+
const JNINativeMethod methods[] = {
{"native_new", "(Lcom/android/providers/media/MediaProvider;)J",
reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_new)},
@@ -81,8 +97,10 @@ const JNINativeMethod methods[] = {
{"native_delete", "(J)V",
reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_delete)},
{"native_should_open_with_fuse", "(JLjava/lang/String;ZI)Z",
- reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_should_open_with_fuse)}};
-
+ reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_should_open_with_fuse)},
+ {"native_invalidate_fuse_dentry_cache", "(JLjava/lang/String;)V",
+ reinterpret_cast<void*>(
+ com_android_providers_media_FuseDaemon_invalidate_fuse_dentry_cache)}};
} // namespace
void register_android_providers_media_FuseDaemon(JNIEnv* env) {
diff --git a/jni/node-inl.h b/jni/node-inl.h
index 76d1ba91b..e21ae5448 100644
--- a/jni/node-inl.h
+++ b/jni/node-inl.h
@@ -160,6 +160,11 @@ class node {
return name_;
}
+ node* GetParent() const {
+ std::lock_guard<std::recursive_mutex> guard(*lock_);
+ return parent_;
+ }
+
inline void AddHandle(handle* h) {
std::lock_guard<std::recursive_mutex> guard(*lock_);
handles_.emplace_back(std::unique_ptr<handle>(h));
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 57ac2862d..c109caea4 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -4758,6 +4758,14 @@ public class MediaProvider extends ContentProvider {
return new File(filePath);
}
+ private FuseDaemon getFuseDaemonForFile(File file) {
+ StorageVolume volume = mStorageManager.getStorageVolume(file);
+ if (volume == null) {
+ return null;
+ }
+ return ExternalStorageServiceImpl.getFuseDaemon(volume.getId());
+ }
+
/**
* Replacement for {@link #openFileHelper(Uri, String)} which enforces any
* permissions applicable to the path before returning.
@@ -4865,12 +4873,7 @@ public class MediaProvider extends ContentProvider {
redactionInfo.freeOffsets);
}
} else {
- FuseDaemon daemon = null;
-
- StorageVolume volume = mStorageManager.getStorageVolume(file);
- if (volume != null) {
- daemon = ExternalStorageServiceImpl.getFuseDaemon(volume.getId());
- }
+ FuseDaemon daemon = getFuseDaemonForFile(file);
ParcelFileDescriptor lowerFsFd = ParcelFileDescriptor.open(file, modeBits);
boolean forRead = (modeBits & ParcelFileDescriptor.MODE_READ_ONLY) != 0;
boolean shouldOpenWithFuse = daemon != null
diff --git a/src/com/android/providers/media/fuse/FuseDaemon.java b/src/com/android/providers/media/fuse/FuseDaemon.java
index 19ebc03cf..3ce21601e 100644
--- a/src/com/android/providers/media/fuse/FuseDaemon.java
+++ b/src/com/android/providers/media/fuse/FuseDaemon.java
@@ -99,9 +99,17 @@ public final class FuseDaemon extends Thread {
return native_should_open_with_fuse(mPtr, path, readLock, fd);
}
+ /**
+ * Invalidates FUSE VFS dentry cache for {@code path}
+ */
+ public void invalidateFuseDentryCache(String path) {
+ native_invalidate_fuse_dentry_cache(mPtr, path);
+ }
+
private native long native_new(MediaProvider mediaProvider);
private native void native_start(long daemon, int deviceFd, String path);
private native void native_delete(long daemon);
private native boolean native_should_open_with_fuse(long daemon, String path, boolean readLock,
int fd);
+ private native void native_invalidate_fuse_dentry_cache(long daemon, String path);
}