summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-08-19 02:39:04 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-08-19 02:39:04 +0000
commit1a458e21f244d05ed05cb73336ec237365837831 (patch)
tree1ec6f709a67dfd9ec250347d96b262cf1a943861
parent8f0981474a32d2cc790f76c04420e90032bccedf (diff)
parent3a9c1794385ae80c7835a8ec496f4a2efdf4de76 (diff)
downloadcore-android12-d1-s4-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.bp1
-rw-r--r--fs_mgr/blockdev.cpp159
-rw-r--r--fs_mgr/blockdev.h21
-rw-r--r--fs_mgr/fs_mgr.cpp17
-rw-r--r--fs_mgr/libdm/dm.cpp30
-rw-r--r--fs_mgr/libdm/include/libdm/dm.h4
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 {