summaryrefslogtreecommitdiffstats
path: root/fs_mgr/fs_mgr_dm_linear.cpp
diff options
context:
space:
mode:
authorDavid Anderson <dvander@google.com>2018-05-01 17:09:17 -0700
committerDavid Anderson <dvander@google.com>2018-05-14 12:43:42 -0700
commit62e5b20b505e45671545cf871f701daa61cb1b2d (patch)
treeaf457e60dd47215b9e43781836420758faa54672 /fs_mgr/fs_mgr_dm_linear.cpp
parentc8dd6b74e66ee02132e9d2094675974f5285666a (diff)
downloadsystem_core-62e5b20b505e45671545cf871f701daa61cb1b2d.tar.gz
system_core-62e5b20b505e45671545cf871f701daa61cb1b2d.tar.bz2
system_core-62e5b20b505e45671545cf871f701daa61cb1b2d.zip
init/fs_mgr: prototype first-stage dm-linear support
This adds an API to fs_mgr for reading dm-linear tables out of device trees and issuing device-mapper ioctls. The device tree code will be implemented separately. The dm-linear structures in fs_mgr are organized assuming we may want to pull them from sources other than DT (for example, text files, binary blobs, or something hardcoded for testing). File systems which are mounted from these logical partitions have specific fstab requirements. The block device must be a partition name, and if Verified Boot is used, that name must match the vbmeta partition name. Second, the entry must have the "logical" fs_mgr flag. Example fstab entry: vendor /vendor ext4 ro wait,logical Example fstab entry in device tree: vendor { compatible = "android,fstab"; dev = "vendor"; type = "ext4"; mnt_flags = "ro"; fs_mgr_flags = "wait,slotselect,avb,logical"; }; Bug: 78914864 Test: N/A Change-Id: I4d8878ea8858f26310119616cadc3ee0dd08566c
Diffstat (limited to 'fs_mgr/fs_mgr_dm_linear.cpp')
-rw-r--r--fs_mgr/fs_mgr_dm_linear.cpp141
1 files changed, 141 insertions, 0 deletions
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
new file mode 100644
index 000000000..b2f3a6887
--- /dev/null
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "fs_mgr_dm_linear.h"
+
+#include <inttypes.h>
+#include <linux/dm-ioctl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sstream>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+
+#include "fs_mgr_priv.h"
+#include "fs_mgr_priv_dm_ioctl.h"
+
+namespace android {
+namespace fs_mgr {
+
+std::string LogicalPartitionExtent::Serialize() const {
+ // Note: we need to include an explicit null-terminator.
+ std::string argv =
+ android::base::StringPrintf("%s %" PRIu64, block_device_.c_str(), first_sector_);
+ argv.push_back(0);
+
+ // The kernel expects each target to be aligned.
+ size_t spec_bytes = sizeof(struct dm_target_spec) + argv.size();
+ size_t padding = ((spec_bytes + 7) & ~7) - spec_bytes;
+ for (size_t i = 0; i < padding; i++) {
+ argv.push_back(0);
+ }
+
+ struct dm_target_spec spec;
+ spec.sector_start = logical_sector_;
+ spec.length = num_sectors_;
+ spec.status = 0;
+ strcpy(spec.target_type, "linear");
+ spec.next = sizeof(struct dm_target_spec) + argv.size();
+
+ return std::string((char*)&spec, sizeof(spec)) + argv;
+}
+
+static bool LoadDmTable(int dm_fd, const LogicalPartition& partition) {
+ // Combine all dm_target_spec buffers together.
+ std::string target_string;
+ for (const auto& extent : partition.extents) {
+ target_string += extent.Serialize();
+ }
+
+ // Allocate the ioctl buffer.
+ size_t buffer_size = sizeof(struct dm_ioctl) + target_string.size();
+ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(buffer_size);
+
+ // Initialize the ioctl buffer header, then copy our target specs in.
+ struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
+ fs_mgr_dm_ioctl_init(io, buffer_size, partition.name);
+ io->target_count = partition.extents.size();
+ if (partition.attributes & kPartitionReadonly) {
+ io->flags |= DM_READONLY_FLAG;
+ }
+ memcpy(io + 1, target_string.c_str(), target_string.size());
+
+ if (ioctl(dm_fd, DM_TABLE_LOAD, io)) {
+ PERROR << "Failed ioctl() on DM_TABLE_LOAD, partition " << partition.name;
+ return false;
+ }
+ return true;
+}
+
+static bool LoadTablesAndActivate(int dm_fd, const LogicalPartition& partition) {
+ if (!LoadDmTable(dm_fd, partition)) {
+ return false;
+ }
+
+ struct dm_ioctl io;
+ return fs_mgr_dm_resume_table(&io, partition.name, dm_fd);
+}
+
+static bool CreateDmDeviceForPartition(int dm_fd, const LogicalPartition& partition) {
+ struct dm_ioctl io;
+ if (!fs_mgr_dm_create_device(&io, partition.name, dm_fd)) {
+ return false;
+ }
+ if (!LoadTablesAndActivate(dm_fd, partition)) {
+ // Remove the device rather than leave it in an inactive state.
+ fs_mgr_dm_destroy_device(&io, partition.name, dm_fd);
+ return false;
+ }
+
+ LINFO << "Created device-mapper device: " << partition.name;
+ return true;
+}
+
+bool CreateLogicalPartitions(const LogicalPartitionTable& table) {
+ android::base::unique_fd dm_fd(open("/dev/device-mapper", O_RDWR));
+ if (dm_fd < 0) {
+ PLOG(ERROR) << "failed to open /dev/device-mapper";
+ return false;
+ }
+ for (const auto& partition : table.partitions) {
+ if (!CreateDmDeviceForPartition(dm_fd, partition)) {
+ LOG(ERROR) << "could not create dm-linear device for partition: " << partition.name;
+ return false;
+ }
+ }
+ return true;
+}
+
+std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree() {
+ return nullptr;
+}
+
+} // namespace fs_mgr
+} // namespace android