summaryrefslogtreecommitdiffstats
path: root/fs_mgr/liblp
diff options
context:
space:
mode:
authorDavid Anderson <dvander@google.com>2018-11-19 15:27:23 -0800
committerDavid Anderson <dvander@google.com>2018-11-21 17:36:28 +0000
commitc15618a2c6d4e542addf1c1ad0033e01888364f7 (patch)
tree4623382c58e42045c88e151071867496fa0b9c6c /fs_mgr/liblp
parenteb1213f1707bb6911fd4116d51e17f331abfaa90 (diff)
downloadsystem_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.cpp39
-rw-r--r--fs_mgr/liblp/io_test.cpp9
-rw-r--r--fs_mgr/liblp/reader.cpp3
-rw-r--r--fs_mgr/liblp/utility.cpp8
-rw-r--r--fs_mgr/liblp/utility.h1
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