summaryrefslogtreecommitdiff
path: root/jni/com_android_providers_media_FuseDaemon.cpp
diff options
context:
space:
mode:
authorZim <zezeozue@google.com>2019-12-13 18:49:36 +0000
committerZim <zezeozue@google.com>2019-12-23 11:50:15 +0000
commit280e555bec52be96497c9372a76bd3551be6d361 (patch)
treeeeb3091a3b65524e92ee66e1c84d74b8b8dc4ffc /jni/com_android_providers_media_FuseDaemon.cpp
parent8a588e7e5c66475fe2be069158f31985bd7bdb97 (diff)
downloadMediaProvider-280e555bec52be96497c9372a76bd3551be6d361.tar.gz
Resolve FUSE and lower FS cache inconsistencies
Rf - Read FUSE, Wf - Write FUSE Rl - Read lower fs, Wl - Write lower fs File reads in the following scenarios may not see the latest data because of different VFS caches: 1. Rf - Wl -Rf 2. Rl - Wf - Rl To fix the scenarios above we dynamically return a FUSE or lower FS fd from the MediaProvider#open or open with or without caching during FUSE_OPEN. Here are the conditions: MP open: - Return FUSE fd if file already opened with caching via FUSE or we are unable to SET_OFD_SETLK to F_RDLCK or F_WRLCK with fcntl(2). - Return lower FS fd otherwise FUSE open: - Open with caching if F_OFD_GETLK with fcntl(2) returns F_UNLCK - Open with direct_io otherwise Unfortunately, we cannot place a F_RDLCK on a file opened in write only mode and we cannot place a F_WRLCK twice. This means that if a file is opened via MP in write only mode, we can only set a F_WRLCK and subsequent opens will have to go through FUSE. Pseudo code of algorithm implemented: MP#opeFd lowerFsFd = open(lowerPath) useFuse = FuseD#shouldOpenWithFuse(lowerPath, fd) if useFuse upperFsFd = open(upperPath) return upperFsFd else return lowerFsFd FuseD#open lowerFsFd = open(path) hasLock = fcntl(get_lock, lowerFsFd) if hasLock return uncachedFileInfo else return cachedFileInfo FuseD#shouldOpenWithFuse if cached return true else res = fcntl(set_read_or_write_lock, fd) return res Test: atest FuseDaemonHostTest#testVfsCacheConsistency Test: adb logcat -v color | grep --color=never -iE "using fuse|using lower|using direct|using cache" FuseDaemon: [/storage/emulated] Using cache for /storage/emulated/0/DCIM/open_file_path_write_content_resolver.jpg MediaProvider: Using FUSE for /storage/emulated/0/DCIM/open_file_path_write_content_resolver.jpg FuseDaemon: [/storage/emulated] Using cache for /storage/emulated/0/DCIM/open_file_path_write_content_resolver.jpg MediaProvider: Using lower FS for /storage/emulated/0/DCIM/open_content_resolver_write_content_resolver.jpg FuseDaemon: [/storage/emulated] Using direct io for /storage/emulated/0/DCIM/open_content_resolver_write_content_resolver.jpg FuseDaemon: [/storage/emulated] Using cache for /storage/emulated/0/DCIM/open_file_path_write_file_path.jpg MediaProvider: Using FUSE for /storage/emulated/0/DCIM/open_file_path_write_file_path.jpg FuseDaemon: [/storage/emulated] Using cache for /storage/emulated/0/DCIM/open_file_path_write_file_path.jpg MediaProvider: Using lower FS for /storage/emulated/0/DCIM/open_content_resolver_write_file_path.jpg FuseDaemon: [/storage/emulated] Using direct io for /storage/emulated/0/DCIM/open_content_resolver_write_file_path.jpg MediaProvider: Using lower FS for /storage/emulated/0/DCIM/open_content_resolver_write_only.jpg MediaProvider: Using FUSE for /storage/emulated/0/DCIM/open_content_resolver_write_only.jpg FuseDaemon: [/storage/emulated] Using direct io for /storage/emulated/0/DCIM/open_content_resolver_write_only.jpg MediaProvider: Using lower FS for /storage/emulated/0/DCIM/open_content_resolver_dup.jpg FuseDaemon: [/storage/emulated] Using direct io for /storage/emulated/0/DCIM/open_content_resolver_dup.jpg Bug: 135341433 Change-Id: I94c8cbed32567e807259d67a6a9a4ea470158d9e
Diffstat (limited to 'jni/com_android_providers_media_FuseDaemon.cpp')
-rw-r--r--jni/com_android_providers_media_FuseDaemon.cpp31
1 files changed, 26 insertions, 5 deletions
diff --git a/jni/com_android_providers_media_FuseDaemon.cpp b/jni/com_android_providers_media_FuseDaemon.cpp
index 1633b991f..caf00b27b 100644
--- a/jni/com_android_providers_media_FuseDaemon.cpp
+++ b/jni/com_android_providers_media_FuseDaemon.cpp
@@ -30,9 +30,10 @@ namespace {
constexpr const char* CLASS_NAME = "com/android/providers/media/fuse/FuseDaemon";
static jclass gFuseDaemonClass;
-jlong com_android_providers_media_FuseDaemon_new(JNIEnv* env, jobject self, jobject mediaProvider) {
+jlong com_android_providers_media_FuseDaemon_new(JNIEnv* env, jobject self,
+ jobject media_provider) {
LOG(DEBUG) << "Creating the FUSE daemon...";
- return reinterpret_cast<jlong>(new fuse::FuseDaemon(env, mediaProvider));
+ return reinterpret_cast<jlong>(new fuse::FuseDaemon(env, media_provider));
}
void com_android_providers_media_FuseDaemon_start(JNIEnv* env, jobject self, jlong java_daemon,
@@ -44,9 +45,8 @@ void com_android_providers_media_FuseDaemon_start(JNIEnv* env, jobject self, jlo
if (!utf_chars_path.c_str()) {
return;
}
- const std::string& string_path = std::string(utf_chars_path.c_str());
- daemon->Start(fd, string_path);
+ daemon->Start(fd, utf_chars_path.c_str());
}
void com_android_providers_media_FuseDaemon_delete(JNIEnv* env, jobject self, jlong java_daemon) {
@@ -55,13 +55,34 @@ void com_android_providers_media_FuseDaemon_delete(JNIEnv* env, jobject self, jl
delete daemon;
}
+jboolean com_android_providers_media_FuseDaemon_should_open_with_fuse(JNIEnv* env, jobject self,
+ jlong java_daemon,
+ jstring java_path,
+ jboolean for_read, jint fd) {
+ 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/145741852): Throw exception
+ return JNI_FALSE;
+ }
+
+ return daemon->ShouldOpenWithFuse(fd, for_read, utf_chars_path.c_str());
+ }
+ // TODO(b/145741852): Throw exception
+ return JNI_FALSE;
+}
+
const JNINativeMethod methods[] = {
{"native_new", "(Lcom/android/providers/media/MediaProvider;)J",
reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_new)},
{"native_start", "(JILjava/lang/String;)V",
reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_start)},
{"native_delete", "(J)V",
- reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_delete)}};
+ 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)}};
+
} // namespace
void register_android_providers_media_FuseDaemon(JNIEnv* env) {