From dcee5c1d213c3f034126ec806966f4e029b81140 Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Fri, 12 Jun 2020 12:59:45 +0100 Subject: [PATCH] Configure read ahead for fuse mounts For fuse read ahead can be configured by writing a value to the /sys/class/bdi/{MAJOR}:{MINOR}/read_ahead_kb file. There are several different ways of getting {MAJOR}:{MINOR} values of the filesystem: * Look at st_dev of stat("/mnt/user/0/emulated"). * Parse /proc/self/mountinfo. Stat'ing approach is used since it's easier to implement. Bug: 157982297 Test: atest vold_tests Test: adb shell cat /proc/self/mountinfo to get MAJOR:MINOR Test: adb shell cat /sys/class/bdi/{MAJOR}:{MINOR}/read_ahead_kb Test: created public volume, checked it's read_ahead_kb is also 256 Change-Id: Id0c149c4af1ceabf3afc33b4100563a512b38316 --- Utils.cpp | 32 ++++++++++++++++++++++++++++++++ Utils.h | 4 ++++ model/EmulatedVolume.cpp | 2 ++ model/PublicVolume.cpp | 2 ++ 4 files changed, 40 insertions(+) diff --git a/Utils.cpp b/Utils.cpp index e3a419f..af0027f 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -63,6 +63,7 @@ using android::base::EndsWith; using android::base::ReadFileToString; using android::base::StartsWith; using android::base::StringPrintf; +using android::base::unique_fd; namespace android { namespace vold { @@ -92,6 +93,10 @@ static const char* kMediaProviderAppCtx = "u:r:mediaprovider_app:"; // other between multiple threads. static std::mutex kSecurityLock; +std::string GetFuseMountPathForUser(userid_t user_id, const std::string& relative_upper_path) { + return StringPrintf("/mnt/user/%d/%s", user_id, relative_upper_path.c_str()); +} + status_t CreateDeviceNode(const std::string& path, dev_t dev) { std::lock_guard lock(kSecurityLock); const char* cpath = path.c_str(); @@ -1355,6 +1360,33 @@ status_t EnsureDirExists(const std::string& path, mode_t mode, uid_t uid, gid_t return OK; } +// Configures read ahead property of the fuse filesystem with the mount point |fuse_mount| by +// writing |read_ahead_kb| to the /sys/class/bdi/MAJOR:MINOR/read_ahead_kb. +void ConfigureReadAheadForFuse(const std::string& fuse_mount, size_t read_ahead_kb) { + LOG(INFO) << "Configuring read_ahead of " << fuse_mount << " fuse filesystem to " + << read_ahead_kb << "kb"; + // First figure out MAJOR:MINOR of fuse_mount. Simplest way is to stat the path. + struct stat info; + if (stat(fuse_mount.c_str(), &info) != 0) { + PLOG(ERROR) << "Failed to stat " << fuse_mount; + return; + } + unsigned int maj = major(info.st_dev); + unsigned int min = minor(info.st_dev); + LOG(INFO) << fuse_mount << " has major:minor " << maj << ":" << min; + // We found major:minor of our filesystem, time to configure read ahead! + std::string read_ahead_file = StringPrintf("/sys/class/bdi/%u:%u/read_ahead_kb", maj, min); + unique_fd fd(TEMP_FAILURE_RETRY(open(read_ahead_file.c_str(), O_WRONLY | O_CLOEXEC))); + if (fd.get() == -1) { + PLOG(ERROR) << "Failed to open " << read_ahead_file; + return; + } + LOG(INFO) << "Writing " << read_ahead_kb << " to " << read_ahead_file; + if (!WriteStringToFd(std::to_string(read_ahead_kb), fd)) { + PLOG(ERROR) << "Failed to write to " << read_ahead_file; + } +} + status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, const std::string& relative_upper_path, android::base::unique_fd* fuse_fd) { std::string pre_fuse_path(StringPrintf("/mnt/user/%d", user_id)); diff --git a/Utils.h b/Utils.h index c4926e7..a1d34b8 100644 --- a/Utils.h +++ b/Utils.h @@ -47,6 +47,8 @@ extern security_context_t sFsckUntrustedContext; // TODO remove this with better solution, b/64143519 extern bool sSleepOnUnmount; +std::string GetFuseMountPathForUser(userid_t user_id, const std::string& relative_upper_path); + status_t CreateDeviceNode(const std::string& path, dev_t dev); status_t DestroyDeviceNode(const std::string& path); @@ -174,6 +176,8 @@ bool FsyncDirectory(const std::string& dirname); bool writeStringToFile(const std::string& payload, const std::string& filename); +void ConfigureReadAheadForFuse(const std::string& fuse_mount, size_t read_ahead_kb); + status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, const std::string& relative_upper_path, android::base::unique_fd* fuse_fd); diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index bb5aa86..26d9582 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -402,6 +402,8 @@ status_t EmulatedVolume::doMount() { return res; } + ConfigureReadAheadForFuse(GetFuseMountPathForUser(user_id, label), 256u); + // All mounts where successful, disable scope guards sdcardfs_guard.Disable(); fuse_guard.Disable(); diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 6195482..64b5dfa 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -250,6 +250,8 @@ status_t PublicVolume::doMount() { return -EIO; } } + + ConfigureReadAheadForFuse(GetFuseMountPathForUser(user_id, stableName), 256u); } return OK;