diff options
author | Zim <zezeozue@google.com> | 2019-12-13 18:49:36 +0000 |
---|---|---|
committer | Zim <zezeozue@google.com> | 2019-12-23 11:50:15 +0000 |
commit | 280e555bec52be96497c9372a76bd3551be6d361 (patch) | |
tree | eeb3091a3b65524e92ee66e1c84d74b8b8dc4ffc /jni/com_android_providers_media_FuseDaemon.cpp | |
parent | 8a588e7e5c66475fe2be069158f31985bd7bdb97 (diff) | |
download | MediaProvider-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.cpp | 31 |
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) { |