diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-08-19 02:39:04 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-08-19 02:39:04 +0000 |
commit | 1a458e21f244d05ed05cb73336ec237365837831 (patch) | |
tree | 1ec6f709a67dfd9ec250347d96b262cf1a943861 | |
parent | 8f0981474a32d2cc790f76c04420e90032bccedf (diff) | |
parent | 3a9c1794385ae80c7835a8ec496f4a2efdf4de76 (diff) | |
download | core-android12-d1-s5-release.tar.gz |
Merge cherrypicks of [15619363, 15619364, 15619365, 15619399, 15619400, 15619401, 15619366, 15619367, 15619368, 15619369, 15619424, 15619425, 15619426, 15619427, 15619428, 15619402, 15619403, 15619404, 15619370, 15619371, 15619372, 15619373, 15618427, 15619429, 15619405, 15619406, 15619407, 15619408, 15619374, 15619375, 15619409] into sc-d1-releaseandroid-12.0.0_r7android-12.0.0_r6android-12.0.0_r5android-12.0.0_r4android-12.0.0_r15android-12.0.0_r14android-12.0.0_r13android-12.0.0_r12android12-d1-s6-releaseandroid12-d1-s5-releaseandroid12-d1-s4-releaseandroid12-d1-s3-releaseandroid12-d1-s2-releaseandroid12-d1-s1-releaseandroid12-d1-release
Change-Id: Ib1370ba9a896762549748a3e5fbd575958f68410
-rw-r--r-- | fs_mgr/Android.bp | 1 | ||||
-rw-r--r-- | fs_mgr/blockdev.cpp | 159 | ||||
-rw-r--r-- | fs_mgr/blockdev.h | 21 | ||||
-rw-r--r-- | fs_mgr/fs_mgr.cpp | 17 | ||||
-rw-r--r-- | fs_mgr/libdm/dm.cpp | 30 | ||||
-rw-r--r-- | fs_mgr/libdm/include/libdm/dm.h | 4 |
6 files changed, 208 insertions, 24 deletions
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index 5356b006d..3c83aabba 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -63,6 +63,7 @@ cc_defaults { "-D_FILE_OFFSET_BITS=64", ], srcs: [ + "blockdev.cpp", "file_wait.cpp", "fs_mgr.cpp", "fs_mgr_format.cpp", diff --git a/fs_mgr/blockdev.cpp b/fs_mgr/blockdev.cpp new file mode 100644 index 000000000..14b217ca8 --- /dev/null +++ b/fs_mgr/blockdev.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/stringprintf.h> +#include <android-base/strings.h> + +#include <dirent.h> +#include <libdm/dm.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <sys/types.h> +#include "blockdev.h" + +using android::base::Basename; +using android::base::ErrnoError; +using android::base::Error; +using android::base::Result; +using android::base::ResultError; +using android::base::StartsWith; +using android::base::StringPrintf; +using android::base::unique_fd; +using android::dm::DeviceMapper; + +// Return the parent device of a partition. Converts e.g. "sda26" into "sda". +static std::string PartitionParent(const std::string& blockdev) { + if (blockdev.find('/') != std::string::npos) { + LOG(ERROR) << __func__ << ": invalid argument " << blockdev; + return blockdev; + } + auto dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/sys/class/block"), closedir}; + if (!dir) { + return blockdev; + } + for (struct dirent* ent = readdir(dir.get()); ent; ent = readdir(dir.get())) { + if (ent->d_name[0] == '.') { + continue; + } + std::string path = StringPrintf("/sys/class/block/%s/%s", ent->d_name, blockdev.c_str()); + struct stat statbuf; + if (stat(path.c_str(), &statbuf) >= 0) { + return ent->d_name; + } + } + return blockdev; +} + +// Convert a major:minor pair into a block device name. +static std::string BlockdevName(dev_t dev) { + auto dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/dev/block"), closedir}; + if (!dir) { + return {}; + } + for (struct dirent* ent = readdir(dir.get()); ent; ent = readdir(dir.get())) { + if (ent->d_name[0] == '.') { + continue; + } + const std::string path = std::string("/dev/block/") + ent->d_name; + struct stat statbuf; + if (stat(path.c_str(), &statbuf) >= 0 && dev == statbuf.st_rdev) { + return ent->d_name; + } + } + return {}; +} + +// Trim whitespace from the end of a string. +static void rtrim(std::string& s) { + s.erase(s.find_last_not_of('\n') + 1, s.length()); +} + +// For file `file_path`, retrieve the block device backing the filesystem on +// which the file exists and return the queue depth of the block device. +static Result<uint32_t> BlockDeviceQueueDepth(const std::string& file_path) { + struct stat statbuf; + int res = stat(file_path.c_str(), &statbuf); + if (res < 0) { + return ErrnoError() << "stat(" << file_path << ")"; + } + std::string blockdev = "/dev/block/" + BlockdevName(statbuf.st_dev); + LOG(DEBUG) << __func__ << ": " << file_path << " -> " << blockdev; + if (blockdev.empty()) { + const std::string err_msg = + StringPrintf("Failed to convert %u:%u (path %s)", major(statbuf.st_dev), + minor(statbuf.st_dev), file_path.c_str()); + return ResultError(err_msg, 0); + } + auto& dm = DeviceMapper::Instance(); + for (;;) { + std::optional<std::string> child = dm.GetParentBlockDeviceByPath(blockdev); + if (!child) { + break; + } + LOG(DEBUG) << __func__ << ": " << blockdev << " -> " << *child; + blockdev = *child; + } + std::optional<std::string> maybe_blockdev = android::dm::ExtractBlockDeviceName(blockdev); + if (!maybe_blockdev) { + return ResultError("Failed to remove /dev/block/ prefix from " + blockdev, 0); + } + blockdev = PartitionParent(*maybe_blockdev); + LOG(DEBUG) << __func__ << ": " + << "Partition parent: " << blockdev; + const std::string nr_tags_path = + StringPrintf("/sys/class/block/%s/mq/0/nr_tags", blockdev.c_str()); + std::string nr_tags; + if (!android::base::ReadFileToString(nr_tags_path, &nr_tags)) { + return ResultError("Failed to read " + nr_tags_path, 0); + } + rtrim(nr_tags); + LOG(DEBUG) << __func__ << ": " << file_path << " is backed by /dev/" << blockdev + << " and that block device supports queue depth " << nr_tags; + return strtol(nr_tags.c_str(), NULL, 0); +} + +// Set 'nr_requests' of `loop_device_path` to the queue depth of the block +// device backing `file_path`. +Result<void> ConfigureQueueDepth(const std::string& loop_device_path, + const std::string& file_path) { + if (!StartsWith(loop_device_path, "/dev/")) { + return Error() << "Invalid argument " << loop_device_path; + } + + const std::string loop_device_name = Basename(loop_device_path); + + const Result<uint32_t> qd = BlockDeviceQueueDepth(file_path); + if (!qd.ok()) { + LOG(DEBUG) << __func__ << ": " + << "BlockDeviceQueueDepth() returned " << qd.error(); + return ResultError(qd.error()); + } + const std::string nr_requests = StringPrintf("%u", *qd); + const std::string sysfs_path = + StringPrintf("/sys/class/block/%s/queue/nr_requests", loop_device_name.c_str()); + unique_fd sysfs_fd(open(sysfs_path.c_str(), O_RDWR | O_CLOEXEC)); + if (sysfs_fd == -1) { + return ErrnoError() << "Failed to open " << sysfs_path; + } + + const int res = write(sysfs_fd.get(), nr_requests.data(), nr_requests.length()); + if (res < 0) { + return ErrnoError() << "Failed to write to " << sysfs_path; + } + return {}; +} diff --git a/fs_mgr/blockdev.h b/fs_mgr/blockdev.h new file mode 100644 index 000000000..2c0d68a77 --- /dev/null +++ b/fs_mgr/blockdev.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/result.h> +#include <string> + +android::base::Result<void> ConfigureQueueDepth(const std::string& loop_device_path, + const std::string& file_path); diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index af71fe6d5..21df8af8c 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -70,6 +70,7 @@ #include <log/log_properties.h> #include <logwrap/logwrap.h> +#include "blockdev.h" #include "fs_mgr_priv.h" #define KEY_LOC_PROP "ro.crypto.keyfile.userdata" @@ -2065,22 +2066,24 @@ static bool PrepareZramBackingDevice(off64_t size) { // Allocate loop device and attach it to file_path. LoopControl loop_control; - std::string device; - if (!loop_control.Attach(target_fd.get(), 5s, &device)) { + std::string loop_device; + if (!loop_control.Attach(target_fd.get(), 5s, &loop_device)) { return false; } + ConfigureQueueDepth(loop_device, "/"); + // set block size & direct IO - unique_fd device_fd(TEMP_FAILURE_RETRY(open(device.c_str(), O_RDWR | O_CLOEXEC))); - if (device_fd.get() == -1) { - PERROR << "Cannot open " << device; + unique_fd loop_fd(TEMP_FAILURE_RETRY(open(loop_device.c_str(), O_RDWR | O_CLOEXEC))); + if (loop_fd.get() == -1) { + PERROR << "Cannot open " << loop_device; return false; } - if (!LoopControl::EnableDirectIo(device_fd.get())) { + if (!LoopControl::EnableDirectIo(loop_fd.get())) { return false; } - return InstallZramDevice(device); + return InstallZramDevice(loop_device); } bool fs_mgr_swapon_all(const Fstab& fstab) { diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index c4874b8d1..e43c00b44 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -560,34 +560,30 @@ std::string DeviceMapper::GetTargetType(const struct dm_target_spec& spec) { return std::string{spec.target_type, sizeof(spec.target_type)}; } -static bool ExtractBlockDeviceName(const std::string& path, std::string* name) { +std::optional<std::string> ExtractBlockDeviceName(const std::string& path) { static constexpr std::string_view kDevBlockPrefix("/dev/block/"); if (android::base::StartsWith(path, kDevBlockPrefix)) { - *name = path.substr(kDevBlockPrefix.length()); - return true; + return path.substr(kDevBlockPrefix.length()); } - return false; + return {}; } bool DeviceMapper::IsDmBlockDevice(const std::string& path) { - std::string name; - if (!ExtractBlockDeviceName(path, &name)) { - return false; - } - return android::base::StartsWith(name, "dm-"); + std::optional<std::string> name = ExtractBlockDeviceName(path); + return name && android::base::StartsWith(*name, "dm-"); } std::optional<std::string> DeviceMapper::GetDmDeviceNameByPath(const std::string& path) { - std::string name; - if (!ExtractBlockDeviceName(path, &name)) { + std::optional<std::string> name = ExtractBlockDeviceName(path); + if (!name) { LOG(WARNING) << path << " is not a block device"; return std::nullopt; } - if (!android::base::StartsWith(name, "dm-")) { + if (!android::base::StartsWith(*name, "dm-")) { LOG(WARNING) << path << " is not a dm device"; return std::nullopt; } - std::string dm_name_file = "/sys/block/" + name + "/dm/name"; + std::string dm_name_file = "/sys/block/" + *name + "/dm/name"; std::string dm_name; if (!android::base::ReadFileToString(dm_name_file, &dm_name)) { PLOG(ERROR) << "Failed to read file " << dm_name_file; @@ -598,16 +594,16 @@ std::optional<std::string> DeviceMapper::GetDmDeviceNameByPath(const std::string } std::optional<std::string> DeviceMapper::GetParentBlockDeviceByPath(const std::string& path) { - std::string name; - if (!ExtractBlockDeviceName(path, &name)) { + std::optional<std::string> name = ExtractBlockDeviceName(path); + if (!name) { LOG(WARNING) << path << " is not a block device"; return std::nullopt; } - if (!android::base::StartsWith(name, "dm-")) { + if (!android::base::StartsWith(*name, "dm-")) { // Reached bottom of the device mapper stack. return std::nullopt; } - auto slaves_dir = "/sys/block/" + name + "/slaves"; + auto slaves_dir = "/sys/block/" + *name + "/slaves"; auto dir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(slaves_dir.c_str()), closedir); if (dir == nullptr) { PLOG(ERROR) << "Failed to open: " << slaves_dir; diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h index 70b14fa46..bdbbf9112 100644 --- a/fs_mgr/libdm/include/libdm/dm.h +++ b/fs_mgr/libdm/include/libdm/dm.h @@ -49,6 +49,10 @@ enum class DmDeviceState { INVALID, SUSPENDED, ACTIVE }; static constexpr uint64_t kSectorSize = 512; +// Returns `path` without /dev/block prefix if and only if `path` starts with +// that prefix. +std::optional<std::string> ExtractBlockDeviceName(const std::string& path); + class DeviceMapper final { public: class DmBlockDevice final { |