From 6590df2763bf5fc7e14957e678a328ecf69a7aca Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 14 Jun 2018 15:03:53 -0700 Subject: [PATCH] init: Create logical partitions via liblp. Currently, init can create logical partitions by hardcoding them in fs_mgr or by specifying them in device-tree. This change allows init to also create logical partitions by using liblp, which stores partition tables in a physical partition. The current name for this partition is "android". Two aspects of this code will change long-term. One, the prototype code using device-tree will be deleted once fastboot supports logical partitions. Two, libdm will obsolete most of the code in fs_mgr_dm_linear.cpp. For now however we preserve how the prototype code functions and we layer liblp on top of the existing dm_linear logic. Bug: 79173901 Test: N/A Change-Id: If014a109da78fa12269bf0df0dda39028ac2d1aa --- fs_mgr/fs_mgr_dm_linear.cpp | 26 +++++++++ fs_mgr/include/fs_mgr_dm_linear.h | 1 + fs_mgr/liblp/include/liblp/metadata_format.h | 3 ++ fs_mgr/liblp/utility.cpp | 12 +++++ init/init_first_stage.cpp | 57 ++++++++++++++------ 5 files changed, 83 insertions(+), 16 deletions(-) diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp index b2f3a6887..ed42d40e1 100644 --- a/fs_mgr/fs_mgr_dm_linear.cpp +++ b/fs_mgr/fs_mgr_dm_linear.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include "fs_mgr_priv.h" #include "fs_mgr_priv_dm_ioctl.h" @@ -137,5 +138,30 @@ std::unique_ptr LoadPartitionsFromDeviceTree() { return nullptr; } +bool CreateLogicalPartitions(const std::string& block_device) { + uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix()); + auto metadata = ReadMetadata(block_device.c_str(), slot); + if (!metadata) { + LOG(ERROR) << "Could not read partition table."; + return true; + } + + LogicalPartitionTable table; + for (const auto& partition : metadata->partitions) { + LogicalPartition new_partition; + new_partition.name = GetPartitionName(partition); + new_partition.attributes = partition.attributes; + for (size_t i = 0; i < partition.num_extents; i++) { + const auto& extent = metadata->extents[partition.first_extent_index + i]; + new_partition.extents.emplace_back(new_partition.num_sectors, extent.target_data, + extent.num_sectors, block_device.c_str()); + new_partition.num_sectors += extent.num_sectors; + } + table.partitions.push_back(new_partition); + } + + return CreateLogicalPartitions(table); +} + } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h index 7f928e508..9772c4b4b 100644 --- a/fs_mgr/include/fs_mgr_dm_linear.h +++ b/fs_mgr/include/fs_mgr_dm_linear.h @@ -92,6 +92,7 @@ std::unique_ptr LoadPartitionsFromDeviceTree(); // /dev/block/dm- where |name| is the partition name. // bool CreateLogicalPartitions(const LogicalPartitionTable& table); +bool CreateLogicalPartitions(const std::string& block_device); } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h index f6262ff63..6a2c65583 100644 --- a/fs_mgr/liblp/include/liblp/metadata_format.h +++ b/fs_mgr/liblp/include/liblp/metadata_format.h @@ -256,6 +256,9 @@ struct LpMetadata { std::string GetPartitionName(const LpMetadataPartition& partition); std::string GetPartitionGuid(const LpMetadataPartition& partition); +// Helper to return a slot number for a slot suffix. +uint32_t SlotNumberForSlotSuffix(const std::string& suffix); + } // namespace fs_mgr } // namespace android #endif diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp index 958700b61..217d80256 100644 --- a/fs_mgr/liblp/utility.cpp +++ b/fs_mgr/liblp/utility.cpp @@ -88,5 +88,17 @@ std::string GetPartitionGuid(const LpMetadataPartition& partition) { return buffer; } +uint32_t SlotNumberForSlotSuffix(const std::string& suffix) { + if (suffix.empty()) { + return 0; + } + if (suffix.size() != 2 || suffix[0] != '_' || suffix[1] < 'a') { + LERROR << __PRETTY_FUNCTION__ << "slot '" << suffix + << "' does not have a recognized format."; + return 0; + } + return suffix[1] - 'a'; +} + } // namespace fs_mgr } // namespace android diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp index db60ce11e..2bc9f3ae0 100644 --- a/init/init_first_stage.cpp +++ b/init/init_first_stage.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "devices.h" #include "fs_mgr.h" @@ -75,6 +76,7 @@ class FirstStageMount { std::unique_ptr device_tree_fstab_; std::unique_ptr dm_linear_table_; + std::string lp_metadata_partition_; std::vector mount_fstab_recs_; std::set required_devices_partition_names_; std::unique_ptr device_handler_; @@ -120,13 +122,17 @@ static bool inline IsRecoveryMode() { } static inline bool IsDmLinearEnabled() { - bool enabled = false; - import_kernel_cmdline( - false, [&enabled](const std::string& key, const std::string& value, bool in_qemu) { - if (key == "androidboot.logical_partitions" && value == "1") { - enabled = true; - } - }); + static bool checked = false; + static bool enabled = false; + if (checked) { + return enabled; + } + import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) { + if (key == "androidboot.logical_partitions" && value == "1") { + enabled = true; + } + }); + checked = true; return enabled; } @@ -163,7 +169,7 @@ std::unique_ptr FirstStageMount::Create() { } bool FirstStageMount::DoFirstStageMount() { - if (!dm_linear_table_ && mount_fstab_recs_.empty()) { + if (!IsDmLinearEnabled() && mount_fstab_recs_.empty()) { // Nothing to mount. LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)"; return true; @@ -184,14 +190,18 @@ bool FirstStageMount::InitDevices() { bool FirstStageMount::GetBackingDmLinearDevices() { // Add any additional devices required for dm-linear mappings. - if (!dm_linear_table_) { + if (!IsDmLinearEnabled()) { return true; } - for (const auto& partition : dm_linear_table_->partitions) { - for (const auto& extent : partition.extents) { - const std::string& partition_name = android::base::Basename(extent.block_device()); - required_devices_partition_names_.emplace(partition_name); + required_devices_partition_names_.emplace(LP_METADATA_PARTITION_NAME); + + if (dm_linear_table_) { + for (const auto& partition : dm_linear_table_->partitions) { + for (const auto& extent : partition.extents) { + const std::string& partition_name = android::base::Basename(extent.block_device()); + required_devices_partition_names_.emplace(partition_name); + } } } return true; @@ -205,7 +215,7 @@ bool FirstStageMount::InitRequiredDevices() { return true; } - if (dm_linear_table_ || need_dm_verity_) { + if (IsDmLinearEnabled() || need_dm_verity_) { const std::string dm_path = "/devices/virtual/misc/device-mapper"; bool found = false; auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) { @@ -253,10 +263,21 @@ bool FirstStageMount::InitRequiredDevices() { } bool FirstStageMount::CreateLogicalPartitions() { - if (!dm_linear_table_) { + if (!IsDmLinearEnabled()) { return true; } - return android::fs_mgr::CreateLogicalPartitions(*dm_linear_table_.get()); + + if (lp_metadata_partition_.empty()) { + LOG(ERROR) << "Could not locate logical partition tables in partition " + << LP_METADATA_PARTITION_NAME; + return false; + } + if (dm_linear_table_) { + if (!android::fs_mgr::CreateLogicalPartitions(*dm_linear_table_.get())) { + return false; + } + } + return android::fs_mgr::CreateLogicalPartitions(lp_metadata_partition_); } ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent) { @@ -266,6 +287,10 @@ ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const auto iter = required_devices_partition_names_.find(name); if (iter != required_devices_partition_names_.end()) { LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter; + if (IsDmLinearEnabled() && name == LP_METADATA_PARTITION_NAME) { + std::vector links = device_handler_->GetBlockDeviceSymlinks(uevent); + lp_metadata_partition_ = links[0]; + } required_devices_partition_names_.erase(iter); device_handler_->HandleDeviceEvent(uevent); if (required_devices_partition_names_.empty()) {