Merge "liblp: Allocate "b" extents in the second half of super."
This commit is contained in:
commit
5cd7969177
|
@ -578,6 +578,12 @@ bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size)
|
|||
CHECK_NE(sectors_per_block, 0);
|
||||
CHECK(sectors_needed % sectors_per_block == 0);
|
||||
|
||||
if (IsABDevice() && !IsRetrofitDevice() && GetPartitionSlotSuffix(partition->name()) == "_b") {
|
||||
// Allocate "a" partitions top-down and "b" partitions bottom-up, to
|
||||
// minimize fragmentation during OTA.
|
||||
free_regions = PrioritizeSecondHalfOfSuper(free_regions);
|
||||
}
|
||||
|
||||
// Find gaps that we can use for new extents. Note we store new extents in a
|
||||
// temporary vector, and only commit them if we are guaranteed enough free
|
||||
// space.
|
||||
|
@ -621,6 +627,40 @@ bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size)
|
|||
return true;
|
||||
}
|
||||
|
||||
std::vector<MetadataBuilder::Interval> MetadataBuilder::PrioritizeSecondHalfOfSuper(
|
||||
const std::vector<Interval>& free_list) {
|
||||
const auto& super = block_devices_[0];
|
||||
uint64_t first_sector = super.first_logical_sector;
|
||||
uint64_t last_sector = super.size / LP_SECTOR_SIZE;
|
||||
uint64_t midpoint = first_sector + (last_sector - first_sector) / 2;
|
||||
|
||||
// Choose an aligned sector for the midpoint. This could lead to one half
|
||||
// being slightly larger than the other, but this will not restrict the
|
||||
// size of partitions (it might lead to one extra extent if "B" overflows).
|
||||
midpoint = AlignSector(super, midpoint);
|
||||
|
||||
std::vector<Interval> first_half;
|
||||
std::vector<Interval> second_half;
|
||||
for (const auto& region : free_list) {
|
||||
// Note: deprioritze if not the main super partition. Even though we
|
||||
// don't call this for retrofit devices, we will allow adding additional
|
||||
// block devices on non-retrofit devices.
|
||||
if (region.device_index != 0 || region.end <= midpoint) {
|
||||
first_half.emplace_back(region);
|
||||
continue;
|
||||
}
|
||||
if (region.start < midpoint && region.end > midpoint) {
|
||||
// Split this into two regions.
|
||||
first_half.emplace_back(region.device_index, region.start, midpoint);
|
||||
second_half.emplace_back(region.device_index, midpoint, region.end);
|
||||
} else {
|
||||
second_half.emplace_back(region);
|
||||
}
|
||||
}
|
||||
second_half.insert(second_half.end(), first_half.begin(), first_half.end());
|
||||
return second_half;
|
||||
}
|
||||
|
||||
void MetadataBuilder::ShrinkPartition(Partition* partition, uint64_t aligned_size) {
|
||||
partition->ShrinkTo(aligned_size);
|
||||
}
|
||||
|
@ -930,5 +970,9 @@ bool MetadataBuilder::IsABDevice() const {
|
|||
return android::base::GetBoolProperty("ro.build.ab_update", false);
|
||||
}
|
||||
|
||||
bool MetadataBuilder::IsRetrofitDevice() const {
|
||||
return GetBlockDevicePartitionName(block_devices_[0]) != LP_METADATA_DEFAULT_PARTITION_NAME;
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
|
|
|
@ -720,3 +720,41 @@ TEST_F(BuilderTest, UnsuffixedPartitions) {
|
|||
ASSERT_EQ(builder->AddPartition("system", 0), nullptr);
|
||||
ASSERT_NE(builder->AddPartition("system_a", 0), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(BuilderTest, ABExtents) {
|
||||
BlockDeviceInfo device_info("super", 10_GiB, 768 * 1024, 0, 4096);
|
||||
|
||||
// A and B slots should be allocated from separate halves of the partition,
|
||||
// to mitigate allocating too many extents. (b/120433288)
|
||||
MetadataBuilder::OverrideABForTesting(true);
|
||||
auto builder = MetadataBuilder::New(device_info, 65536, 2);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
Partition* system_a = builder->AddPartition("system_a", 0);
|
||||
ASSERT_NE(system_a, nullptr);
|
||||
Partition* system_b = builder->AddPartition("system_b", 0);
|
||||
ASSERT_NE(system_b, nullptr);
|
||||
ASSERT_TRUE(builder->ResizePartition(system_a, 2_GiB));
|
||||
ASSERT_TRUE(builder->ResizePartition(system_b, 2_GiB));
|
||||
|
||||
builder->RemovePartition("system_a");
|
||||
system_a = builder->AddPartition("system_a", 0);
|
||||
ASSERT_NE(system_a, nullptr);
|
||||
ASSERT_TRUE(builder->ResizePartition(system_a, 3_GiB));
|
||||
|
||||
EXPECT_EQ(system_a->extents().size(), static_cast<size_t>(1));
|
||||
EXPECT_EQ(system_b->extents().size(), static_cast<size_t>(1));
|
||||
ASSERT_TRUE(builder->ResizePartition(system_b, 6_GiB));
|
||||
EXPECT_EQ(system_b->extents().size(), static_cast<size_t>(3));
|
||||
|
||||
unique_ptr<LpMetadata> exported = builder->Export();
|
||||
ASSERT_NE(exported, nullptr);
|
||||
ASSERT_EQ(exported->extents.size(), static_cast<size_t>(4));
|
||||
EXPECT_EQ(exported->extents[0].target_data, 10487808);
|
||||
EXPECT_EQ(exported->extents[0].num_sectors, 4194304);
|
||||
EXPECT_EQ(exported->extents[1].target_data, 14682624);
|
||||
EXPECT_EQ(exported->extents[1].num_sectors, 6288896);
|
||||
EXPECT_EQ(exported->extents[2].target_data, 6292992);
|
||||
EXPECT_EQ(exported->extents[2].num_sectors, 2099712);
|
||||
EXPECT_EQ(exported->extents[3].target_data, 1536);
|
||||
EXPECT_EQ(exported->extents[3].num_sectors, 6291456);
|
||||
}
|
||||
|
|
|
@ -275,6 +275,7 @@ class MetadataBuilder {
|
|||
const LpMetadataPartition& source);
|
||||
bool ImportPartition(const LpMetadata& metadata, const LpMetadataPartition& source);
|
||||
bool IsABDevice() const;
|
||||
bool IsRetrofitDevice() const;
|
||||
|
||||
struct Interval {
|
||||
uint32_t device_index;
|
||||
|
@ -294,6 +295,7 @@ class MetadataBuilder {
|
|||
std::vector<Interval> GetFreeRegions() const;
|
||||
void ExtentsToFreeList(const std::vector<Interval>& extents,
|
||||
std::vector<Interval>* free_regions) const;
|
||||
std::vector<Interval> PrioritizeSecondHalfOfSuper(const std::vector<Interval>& free_list);
|
||||
|
||||
static bool sABOverrideValue;
|
||||
static bool sABOverrideSet;
|
||||
|
|
Loading…
Reference in New Issue