diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp index c39fbe790..ebd699717 100644 --- a/fs_mgr/liblp/builder.cpp +++ b/fs_mgr/liblp/builder.cpp @@ -550,11 +550,11 @@ auto MetadataBuilder::GetFreeRegions() const -> std::vector { } bool MetadataBuilder::ValidatePartitionSizeChange(Partition* partition, uint64_t old_size, - uint64_t new_size) { + uint64_t new_size, bool force_check) { PartitionGroup* group = FindGroup(partition->group_name()); CHECK(group); - if (new_size <= old_size) { + if (!force_check && new_size <= old_size) { return true; } @@ -861,7 +861,7 @@ bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_s uint64_t aligned_size = AlignTo(requested_size, geometry_.logical_block_size); uint64_t old_size = partition->size(); - if (!ValidatePartitionSizeChange(partition, old_size, aligned_size)) { + if (!ValidatePartitionSizeChange(partition, old_size, aligned_size, false)) { return false; } @@ -973,7 +973,12 @@ bool MetadataBuilder::ImportPartition(const LpMetadata& metadata, ImportExtents(partition, metadata, source); - if (!ValidatePartitionSizeChange(partition, 0, partition->size())) { + // Note: we've already increased the partition size by calling + // ImportExtents(). In order to figure out the size before that, + // we would have to iterate the extents and add up the linear + // segments. Instead, we just force ValidatePartitionSizeChange + // to check if the current configuration is acceptable. + if (!ValidatePartitionSizeChange(partition, partition->size(), partition->size(), true)) { partition->RemoveExtents(); return false; } diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp index 69724f873..81305b3a0 100644 --- a/fs_mgr/liblp/builder_test.cpp +++ b/fs_mgr/liblp/builder_test.cpp @@ -835,3 +835,73 @@ TEST_F(BuilderTest, PartialExtents) { EXPECT_EQ(exported->extents[1].target_data, 4608); EXPECT_EQ(exported->extents[1].num_sectors, 1536); } + +TEST_F(BuilderTest, UpdateSuper) { + // Build the on-disk metadata that we saw before flashing. + auto builder = MetadataBuilder::New(8145338368ULL, 65536, 3); + ASSERT_NE(builder, nullptr); + + ASSERT_TRUE(builder->AddGroup("google_dynamic_partitions_a", 4068474880ULL)); + ASSERT_TRUE(builder->AddGroup("google_dynamic_partitions_b", 4068474880ULL)); + + Partition* partition = builder->AddPartition("system_a", "google_dynamic_partitions_a", + LP_PARTITION_ATTR_READONLY); + ASSERT_NE(partition, nullptr); + ASSERT_TRUE(builder->AddLinearExtent(partition, "super", 1901568, 3608576)); + + partition = builder->AddPartition("vendor_a", "google_dynamic_partitions_a", + LP_PARTITION_ATTR_READONLY); + ASSERT_NE(partition, nullptr); + ASSERT_TRUE(builder->AddLinearExtent(partition, "super", 1521664, 5510144)); + + partition = builder->AddPartition("product_a", "google_dynamic_partitions_a", + LP_PARTITION_ATTR_READONLY); + ASSERT_NE(partition, nullptr); + ASSERT_TRUE(builder->AddLinearExtent(partition, "super", 3606528, 2048)); + + partition = builder->AddPartition("system_b", "google_dynamic_partitions_b", + LP_PARTITION_ATTR_READONLY); + ASSERT_NE(partition, nullptr); + ASSERT_TRUE(builder->AddLinearExtent(partition, "super", 1901568, 7955456)); + + partition = builder->AddPartition("vendor_b", "google_dynamic_partitions_b", + LP_PARTITION_ATTR_READONLY); + ASSERT_NE(partition, nullptr); + ASSERT_TRUE(builder->AddLinearExtent(partition, "super", 1521664, 9857024)); + + partition = builder->AddPartition("product_b", "google_dynamic_partitions_b", + LP_PARTITION_ATTR_READONLY); + ASSERT_NE(partition, nullptr); + ASSERT_TRUE(builder->AddLinearExtent(partition, "super", 3606528, 11378688)); + + auto on_disk = builder->Export(); + ASSERT_NE(on_disk, nullptr); + + // Build the super_empty from the new build. + builder = MetadataBuilder::New(8145338368ULL, 65536, 3); + ASSERT_NE(builder, nullptr); + + ASSERT_TRUE(builder->AddGroup("google_dynamic_partitions_a", 4068474880ULL)); + ASSERT_TRUE(builder->AddGroup("google_dynamic_partitions_b", 4068474880ULL)); + ASSERT_NE(builder->AddPartition("system_a", "google_dynamic_partitions_a", + LP_PARTITION_ATTR_READONLY), + nullptr); + ASSERT_NE(builder->AddPartition("system_b", "google_dynamic_partitions_b", + LP_PARTITION_ATTR_READONLY), + nullptr); + ASSERT_NE(builder->AddPartition("vendor_a", "google_dynamic_partitions_a", + LP_PARTITION_ATTR_READONLY), + nullptr); + ASSERT_NE(builder->AddPartition("vendor_b", "google_dynamic_partitions_b", + LP_PARTITION_ATTR_READONLY), + nullptr); + ASSERT_NE(builder->AddPartition("product_a", "google_dynamic_partitions_a", + LP_PARTITION_ATTR_READONLY), + nullptr); + ASSERT_NE(builder->AddPartition("product_b", "google_dynamic_partitions_b", + LP_PARTITION_ATTR_READONLY), + nullptr); + + std::set partitions_to_keep{"system_a", "vendor_a", "product_a"}; + ASSERT_TRUE(builder->ImportPartitions(*on_disk.get(), partitions_to_keep)); +} diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h index 53f480fba..486a71f75 100644 --- a/fs_mgr/liblp/include/liblp/builder.h +++ b/fs_mgr/liblp/include/liblp/builder.h @@ -297,7 +297,8 @@ class MetadataBuilder { uint64_t TotalSizeOfGroup(PartitionGroup* group) const; bool UpdateBlockDeviceInfo(size_t index, const BlockDeviceInfo& info); bool FindBlockDeviceByName(const std::string& partition_name, uint32_t* index) const; - bool ValidatePartitionSizeChange(Partition* partition, uint64_t old_size, uint64_t new_size); + bool ValidatePartitionSizeChange(Partition* partition, uint64_t old_size, uint64_t new_size, + bool force_check); void ImportExtents(Partition* dest, const LpMetadata& metadata, const LpMetadataPartition& source); bool ImportPartition(const LpMetadata& metadata, const LpMetadataPartition& source);