diff options
-rw-r--r-- | jni/FuseDaemon.cpp | 27 | ||||
-rw-r--r-- | jni/FuseDaemon.h | 5 | ||||
-rw-r--r-- | jni/com_android_providers_media_FuseDaemon.cpp | 22 | ||||
-rw-r--r-- | jni/node-inl.h | 5 | ||||
-rw-r--r-- | src/com/android/providers/media/MediaProvider.java | 15 | ||||
-rw-r--r-- | src/com/android/providers/media/fuse/FuseDaemon.java | 8 |
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); } |