Fix double-accounting bug in liblp.

When flashing in fastbootd, we create a new MetadataBuilder using the
given super_empty.img and attempt to import the existing partition
table. This will fail if there is some incompatibility in the partition
layout or partition quotas.

This import code was accidentally double-accounting partitions when
determining if they could fit within the group quota, preventing
"fastboot flashall" once partitions reached a certain size.

Bug: 126930319
Test: liblp_test gtest
Change-Id: I89a69cba110b62719197c9a4885cfc5bcf8f009f
This commit is contained in:
David Anderson 2019-03-01 16:14:48 -08:00
parent 33f344cb36
commit 88e36c1514
3 changed files with 81 additions and 5 deletions

View File

@ -550,11 +550,11 @@ auto MetadataBuilder::GetFreeRegions() const -> std::vector<Interval> {
}
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;
}

View File

@ -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<std::string> partitions_to_keep{"system_a", "vendor_a", "product_a"};
ASSERT_TRUE(builder->ImportPartitions(*on_disk.get(), partitions_to_keep));
}

View File

@ -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);