Loading fs_mgr/liblp/builder.cpp +57 −13 Original line number Diff line number Diff line Loading @@ -113,18 +113,7 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const IPartitionOpener& op if (!metadata) { return nullptr; } std::unique_ptr<MetadataBuilder> builder = New(*metadata.get()); if (!builder) { return nullptr; } for (size_t i = 0; i < builder->block_devices_.size(); i++) { std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]); BlockDeviceInfo device_info; if (opener.GetInfo(partition_name, &device_info)) { builder->UpdateBlockDeviceInfo(i, device_info); } } return builder; return New(*metadata.get(), &opener); } std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_partition, Loading @@ -142,14 +131,69 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New( return builder; } std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata) { std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata, const IPartitionOpener* opener) { std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder()); if (!builder->Init(metadata)) { return nullptr; } if (opener) { for (size_t i = 0; i < builder->block_devices_.size(); i++) { std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]); BlockDeviceInfo device_info; if (opener->GetInfo(partition_name, &device_info)) { builder->UpdateBlockDeviceInfo(i, device_info); } } } return builder; } std::unique_ptr<MetadataBuilder> MetadataBuilder::NewForUpdate(const IPartitionOpener& opener, const std::string& source_partition, uint32_t source_slot_number, uint32_t target_slot_number) { auto metadata = ReadMetadata(opener, source_partition, source_slot_number); if (!metadata) { 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)); } auto new_block_devices = metadata->block_devices; // 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); std::string slot_suffix = GetPartitionSlotSuffix(partition_name); if (slot_suffix.empty() || slot_suffix != source_slot_suffix) { continue; } 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; 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 = new_block_devices; return New(*metadata.get(), &opener); } MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) { memset(&geometry_, 0, sizeof(geometry_)); geometry_.magic = LP_METADATA_GEOMETRY_MAGIC; Loading fs_mgr/liblp/include/liblp/builder.h +16 −2 Original line number Diff line number Diff line Loading @@ -150,10 +150,24 @@ class MetadataBuilder { static std::unique_ptr<MetadataBuilder> New(const std::string& super_partition, uint32_t slot_number); // This is when performing an A/B update. The source partition must be a // super partition. On a normal device, the metadata for the source slot // is imported and the target slot is ignored. On a retrofit device, the // metadata may not have the target slot's devices listed yet, in which // case, it is automatically upgraded to include all available block // devices. static std::unique_ptr<MetadataBuilder> NewForUpdate(const IPartitionOpener& opener, const std::string& source_partition, uint32_t source_slot_number, uint32_t target_slot_number); // Import an existing table for modification. If the table is not valid, for // example it contains duplicate partition names, then nullptr is returned. // This method is for testing or changing off-line tables. static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata); // // If an IPartitionOpener is specified, then block device informatiom will // be updated. static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata, const IPartitionOpener* opener = nullptr); // Helper function for a single super partition, for tests. static std::unique_ptr<MetadataBuilder> New(const BlockDeviceInfo& device_info, Loading fs_mgr/liblp/io_test.cpp +39 −0 Original line number Diff line number Diff line Loading @@ -649,3 +649,42 @@ TEST(liblp, AutoSlotSuffixing) { ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1)); EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_a"); } TEST(liblp, UpdateRetrofit) { unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder(); ASSERT_NE(builder, nullptr); ASSERT_TRUE(AddDefaultPartitions(builder.get())); builder->SetAutoSlotSuffixing(); auto fd = CreateFakeDisk(); ASSERT_GE(fd, 0); // Note: we bind the same fd to both names, since we want to make sure the // exact same bits are getting read back in each test. TestPartitionOpener opener({{"super_a", fd}, {"super_b", fd}}, {{"super_a", kSuperInfo}, {"super_b", kSuperInfo}}); auto exported = builder->Export(); ASSERT_NE(exported, nullptr); ASSERT_TRUE(FlashPartitionTable(opener, "super_a", *exported.get())); builder = MetadataBuilder::NewForUpdate(opener, "super_a", 0, 1); 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"); } TEST(liblp, UpdateNonRetrofit) { unique_fd fd = CreateFlashedDisk(); ASSERT_GE(fd, 0); DefaultPartitionOpener opener(fd); auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1); ASSERT_NE(builder, nullptr); auto updated = builder->Export(); ASSERT_NE(updated, nullptr); ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1)); EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super"); } fs_mgr/liblp/reader.cpp +1 −3 Original line number Diff line number Diff line Loading @@ -369,12 +369,10 @@ bool AdjustMetadataForSlot(LpMetadata* metadata, uint32_t slot_number) { continue; } std::string partition_name = GetBlockDevicePartitionName(block_device) + slot_suffix; if (partition_name.size() > sizeof(block_device.partition_name)) { if (!UpdateBlockDevicePartitionName(&block_device, partition_name)) { LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name; return false; } strncpy(block_device.partition_name, partition_name.c_str(), sizeof(block_device.partition_name)); block_device.flags &= ~LP_BLOCK_DEVICE_SLOT_SUFFIXED; } return true; Loading fs_mgr/liblp/utility.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -137,5 +137,13 @@ std::string SlotSuffixForSlotNumber(uint32_t slot_number) { return (slot_number == 0) ? "_a" : "_b"; } bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::string& name) { if (name.size() > sizeof(device->partition_name)) { return false; } strncpy(device->partition_name, name.c_str(), sizeof(device->partition_name)); return true; } } // namespace fs_mgr } // namespace android Loading
fs_mgr/liblp/builder.cpp +57 −13 Original line number Diff line number Diff line Loading @@ -113,18 +113,7 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const IPartitionOpener& op if (!metadata) { return nullptr; } std::unique_ptr<MetadataBuilder> builder = New(*metadata.get()); if (!builder) { return nullptr; } for (size_t i = 0; i < builder->block_devices_.size(); i++) { std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]); BlockDeviceInfo device_info; if (opener.GetInfo(partition_name, &device_info)) { builder->UpdateBlockDeviceInfo(i, device_info); } } return builder; return New(*metadata.get(), &opener); } std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_partition, Loading @@ -142,14 +131,69 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New( return builder; } std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata) { std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata, const IPartitionOpener* opener) { std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder()); if (!builder->Init(metadata)) { return nullptr; } if (opener) { for (size_t i = 0; i < builder->block_devices_.size(); i++) { std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]); BlockDeviceInfo device_info; if (opener->GetInfo(partition_name, &device_info)) { builder->UpdateBlockDeviceInfo(i, device_info); } } } return builder; } std::unique_ptr<MetadataBuilder> MetadataBuilder::NewForUpdate(const IPartitionOpener& opener, const std::string& source_partition, uint32_t source_slot_number, uint32_t target_slot_number) { auto metadata = ReadMetadata(opener, source_partition, source_slot_number); if (!metadata) { 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)); } auto new_block_devices = metadata->block_devices; // 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); std::string slot_suffix = GetPartitionSlotSuffix(partition_name); if (slot_suffix.empty() || slot_suffix != source_slot_suffix) { continue; } 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; 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 = new_block_devices; return New(*metadata.get(), &opener); } MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) { memset(&geometry_, 0, sizeof(geometry_)); geometry_.magic = LP_METADATA_GEOMETRY_MAGIC; Loading
fs_mgr/liblp/include/liblp/builder.h +16 −2 Original line number Diff line number Diff line Loading @@ -150,10 +150,24 @@ class MetadataBuilder { static std::unique_ptr<MetadataBuilder> New(const std::string& super_partition, uint32_t slot_number); // This is when performing an A/B update. The source partition must be a // super partition. On a normal device, the metadata for the source slot // is imported and the target slot is ignored. On a retrofit device, the // metadata may not have the target slot's devices listed yet, in which // case, it is automatically upgraded to include all available block // devices. static std::unique_ptr<MetadataBuilder> NewForUpdate(const IPartitionOpener& opener, const std::string& source_partition, uint32_t source_slot_number, uint32_t target_slot_number); // Import an existing table for modification. If the table is not valid, for // example it contains duplicate partition names, then nullptr is returned. // This method is for testing or changing off-line tables. static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata); // // If an IPartitionOpener is specified, then block device informatiom will // be updated. static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata, const IPartitionOpener* opener = nullptr); // Helper function for a single super partition, for tests. static std::unique_ptr<MetadataBuilder> New(const BlockDeviceInfo& device_info, Loading
fs_mgr/liblp/io_test.cpp +39 −0 Original line number Diff line number Diff line Loading @@ -649,3 +649,42 @@ TEST(liblp, AutoSlotSuffixing) { ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1)); EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_a"); } TEST(liblp, UpdateRetrofit) { unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder(); ASSERT_NE(builder, nullptr); ASSERT_TRUE(AddDefaultPartitions(builder.get())); builder->SetAutoSlotSuffixing(); auto fd = CreateFakeDisk(); ASSERT_GE(fd, 0); // Note: we bind the same fd to both names, since we want to make sure the // exact same bits are getting read back in each test. TestPartitionOpener opener({{"super_a", fd}, {"super_b", fd}}, {{"super_a", kSuperInfo}, {"super_b", kSuperInfo}}); auto exported = builder->Export(); ASSERT_NE(exported, nullptr); ASSERT_TRUE(FlashPartitionTable(opener, "super_a", *exported.get())); builder = MetadataBuilder::NewForUpdate(opener, "super_a", 0, 1); 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"); } TEST(liblp, UpdateNonRetrofit) { unique_fd fd = CreateFlashedDisk(); ASSERT_GE(fd, 0); DefaultPartitionOpener opener(fd); auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1); ASSERT_NE(builder, nullptr); auto updated = builder->Export(); ASSERT_NE(updated, nullptr); ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1)); EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super"); }
fs_mgr/liblp/reader.cpp +1 −3 Original line number Diff line number Diff line Loading @@ -369,12 +369,10 @@ bool AdjustMetadataForSlot(LpMetadata* metadata, uint32_t slot_number) { continue; } std::string partition_name = GetBlockDevicePartitionName(block_device) + slot_suffix; if (partition_name.size() > sizeof(block_device.partition_name)) { if (!UpdateBlockDevicePartitionName(&block_device, partition_name)) { LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name; return false; } strncpy(block_device.partition_name, partition_name.c_str(), sizeof(block_device.partition_name)); block_device.flags &= ~LP_BLOCK_DEVICE_SLOT_SUFFIXED; } return true; Loading
fs_mgr/liblp/utility.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -137,5 +137,13 @@ std::string SlotSuffixForSlotNumber(uint32_t slot_number) { return (slot_number == 0) ? "_a" : "_b"; } bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::string& name) { if (name.size() > sizeof(device->partition_name)) { return false; } strncpy(device->partition_name, name.c_str(), sizeof(device->partition_name)); return true; } } // namespace fs_mgr } // namespace android