diff options
author | David Anderson <dvander@google.com> | 2018-11-19 15:27:23 -0800 |
---|---|---|
committer | David Anderson <dvander@google.com> | 2018-11-21 17:36:28 +0000 |
commit | c15618a2c6d4e542addf1c1ad0033e01888364f7 (patch) | |
tree | 4623382c58e42045c88e151071867496fa0b9c6c /fs_mgr/liblp | |
parent | eb1213f1707bb6911fd4116d51e17f331abfaa90 (diff) | |
download | system_core-c15618a2c6d4e542addf1c1ad0033e01888364f7.tar.gz system_core-c15618a2c6d4e542addf1c1ad0033e01888364f7.tar.bz2 system_core-c15618a2c6d4e542addf1c1ad0033e01888364f7.zip |
liblp: Modify NewForUpdate to accomodate two super partitions.
This method was designed for a single-super model, and now needs to
change to accomodate two super partitions (system_a and system_b, for
retrofitting).
NewForUpdate is supposed to transition metadata from one block device
to the next for updates. For normal devices this is a no-op, since
metadata only exists on one partition (super). For retrofit devices,
metadata exists on system_a and system_b. This has two implications.
First, any references to the source slot must be rewritten. For example
"vendor_b" must become "vendor_a". However this is not true of partition
names. Partitions/extents are cleared in the updated metadata since they
no longer have any meaning (the block device list has been
rewritten). We also clear groups since they are re-added during OTA.
The reason we have to do this rewriting is that slot suffixes are
automatically applied in ReadMetadata. We do not have access to the
original unsuffixed metadata that was written by the initial OTA.
This was a conscious design decision, since it localizes retrofitting
idiosyncracies to just a few places (ReadMetadata, NewForUpdate, and
fastbootd), minimizing the number of external callers that have to
understand auto-slot-suffixing.
It would be arguably cleaner if retrofit metadata was always serialized
*without* slot suffixes, thereby making NewForUpdate a no-op. However
this would necessitate changes to the API elsewhere. The functions that
read partition names would have to take a slot suffix, and this would
further complicate MetadataBuilder and fastbootd. Another solution would
be to augment LpMetadata to retain unsuffixed information, but this is
probably not worthwhile given that retrofitting is intended to be
surgical, and will have a shorter lifespan than the non-retrofit case.
Bug: 116802789
Test: liblp_test gtest
Change-Id: I33596d92b38c47bc70bc0aa37ed04f6f0b9d4b6f
Diffstat (limited to 'fs_mgr/liblp')
-rw-r--r-- | fs_mgr/liblp/builder.cpp | 39 | ||||
-rw-r--r-- | fs_mgr/liblp/io_test.cpp | 9 | ||||
-rw-r--r-- | fs_mgr/liblp/reader.cpp | 3 | ||||
-rw-r--r-- | fs_mgr/liblp/utility.cpp | 8 | ||||
-rw-r--r-- | fs_mgr/liblp/utility.h | 1 |
5 files changed, 40 insertions, 20 deletions
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp index b51afc17b..7035f42e5 100644 --- a/fs_mgr/liblp/builder.cpp +++ b/fs_mgr/liblp/builder.cpp @@ -158,39 +158,48 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::NewForUpdate(const IPartitionO return nullptr; } - // Get the list of devices we already have. - std::set<std::string> block_devices; - for (const auto& block_device : metadata->block_devices) { - block_devices.emplace(GetBlockDevicePartitionName(block_device)); + // On non-retrofit devices there is only one location for metadata: the + // super partition. update_engine will remove and resize partitions as + // needed. On the other hand, for retrofit devices, we'll need to + // translate block device and group names to update their slot suffixes. + auto super_device = GetMetadataSuperBlockDevice(*metadata.get()); + if (GetBlockDevicePartitionName(*super_device) == "super") { + return New(*metadata.get(), &opener); } - auto new_block_devices = metadata->block_devices; + // Clear partitions and extents, since they have no meaning on the target + // slot. We also clear groups since they are re-added during OTA. + metadata->partitions.clear(); + metadata->extents.clear(); + metadata->groups.clear(); - // Add missing block devices. std::string source_slot_suffix = SlotSuffixForSlotNumber(source_slot_number); std::string target_slot_suffix = SlotSuffixForSlotNumber(target_slot_number); - for (const auto& block_device : metadata->block_devices) { - std::string partition_name = GetBlockDevicePartitionName(block_device); + + // Translate block devices. + auto source_block_devices = std::move(metadata->block_devices); + for (const auto& source_block_device : source_block_devices) { + std::string partition_name = GetBlockDevicePartitionName(source_block_device); std::string slot_suffix = GetPartitionSlotSuffix(partition_name); if (slot_suffix.empty() || slot_suffix != source_slot_suffix) { - continue; + // This should never happen. It means that the source metadata + // refers to a target or unknown block device. + LERROR << "Invalid block device for slot " << source_slot_suffix << ": " + << partition_name; + return nullptr; } std::string new_name = partition_name.substr(0, partition_name.size() - slot_suffix.size()) + target_slot_suffix; - if (block_devices.find(new_name) != block_devices.end()) { - continue; - } - auto new_device = block_device; + auto new_device = source_block_device; if (!UpdateBlockDevicePartitionName(&new_device, new_name)) { LERROR << "Partition name too long: " << new_name; return nullptr; } - new_block_devices.emplace_back(new_device); + metadata->block_devices.emplace_back(new_device); } - metadata->block_devices = new_block_devices; return New(*metadata.get(), &opener); } diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp index b539d776a..9f3314d34 100644 --- a/fs_mgr/liblp/io_test.cpp +++ b/fs_mgr/liblp/io_test.cpp @@ -665,6 +665,7 @@ TEST(liblp, UpdateRetrofit) { unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder(); ASSERT_NE(builder, nullptr); ASSERT_TRUE(AddDefaultPartitions(builder.get())); + ASSERT_TRUE(builder->AddGroup("example", 0)); builder->SetAutoSlotSuffixing(); auto fd = CreateFakeDisk(); @@ -682,9 +683,11 @@ TEST(liblp, UpdateRetrofit) { ASSERT_NE(builder, nullptr); auto updated = builder->Export(); ASSERT_NE(updated, nullptr); - ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(2)); - EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super_a"); - EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[1]), "super_b"); + ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1)); + EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super_b"); + ASSERT_TRUE(updated->groups.empty()); + ASSERT_TRUE(updated->partitions.empty()); + ASSERT_TRUE(updated->extents.empty()); } TEST(liblp, UpdateNonRetrofit) { diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp index 305e6c79d..24c6b2c31 100644 --- a/fs_mgr/liblp/reader.cpp +++ b/fs_mgr/liblp/reader.cpp @@ -380,11 +380,10 @@ bool AdjustMetadataForSlot(LpMetadata* metadata, uint32_t slot_number) { continue; } std::string group_name = GetPartitionGroupName(group) + slot_suffix; - if (group_name.size() > sizeof(group.name)) { + if (!UpdatePartitionGroupName(&group, group_name)) { LERROR << __PRETTY_FUNCTION__ << " group name too long: " << group_name; return false; } - strncpy(group.name, group_name.c_str(), sizeof(group.name)); group.flags &= ~LP_GROUP_SLOT_SUFFIXED; } return true; diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp index 4f20b6bf8..60ddbdd12 100644 --- a/fs_mgr/liblp/utility.cpp +++ b/fs_mgr/liblp/utility.cpp @@ -145,5 +145,13 @@ bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::st return true; } +bool UpdatePartitionGroupName(LpMetadataPartitionGroup* group, const std::string& name) { + if (name.size() > sizeof(group->name)) { + return false; + } + strncpy(group->name, name.c_str(), sizeof(group->name)); + return true; +} + } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h index 55ecb5a59..8b70919d6 100644 --- a/fs_mgr/liblp/utility.h +++ b/fs_mgr/liblp/utility.h @@ -86,6 +86,7 @@ constexpr uint64_t AlignTo(uint64_t base, uint32_t alignment, uint32_t alignment // Update names from C++ strings. bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::string& name); +bool UpdatePartitionGroupName(LpMetadataPartitionGroup* group, const std::string& name); } // namespace fs_mgr } // namespace android |