Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e755e38 authored by David Anderson's avatar David Anderson
Browse files

liblp: Add a ResizePartition helper to MetadataBuilder.

This change is to assist with implementing the fastbootd "resize-partition"
command. The GrowPartition and ShrinkPartition functions are now
private.

Bug: 78793464
Test: N/A
Change-Id: Ic66a3052359e2558663272ff6e014704206b197e
parent d5f825c7
Loading
Loading
Loading
Loading
+18 −15
Original line number Diff line number Diff line
@@ -82,11 +82,7 @@ void Partition::RemoveExtents() {
    extents_.clear();
}

void Partition::ShrinkTo(uint64_t requested_size) {
    uint64_t aligned_size = AlignTo(requested_size, LP_SECTOR_SIZE);
    if (size_ <= aligned_size) {
        return;
    }
void Partition::ShrinkTo(uint64_t aligned_size) {
    if (aligned_size == 0) {
        RemoveExtents();
        return;
@@ -106,7 +102,7 @@ void Partition::ShrinkTo(uint64_t requested_size) {
        sectors_to_remove -= extent->num_sectors();
        extents_.pop_back();
    }
    DCHECK(size_ == requested_size);
    DCHECK(size_ == aligned_size);
}

std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_device,
@@ -290,13 +286,7 @@ void MetadataBuilder::RemovePartition(const std::string& name) {
    }
}

bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t requested_size) {
    // Align the space needed up to the nearest sector.
    uint64_t aligned_size = AlignTo(requested_size, LP_SECTOR_SIZE);
    if (partition->size() >= aligned_size) {
        return true;
    }

bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size) {
    // Figure out how much we need to allocate.
    uint64_t space_needed = aligned_size - partition->size();
    uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE;
@@ -394,8 +384,8 @@ bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t requested_siz
    return true;
}

void MetadataBuilder::ShrinkPartition(Partition* partition, uint64_t requested_size) {
    partition->ShrinkTo(requested_size);
void MetadataBuilder::ShrinkPartition(Partition* partition, uint64_t aligned_size) {
    partition->ShrinkTo(aligned_size);
}

std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
@@ -465,5 +455,18 @@ void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info)
    }
}

bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size) {
    // Align the space needed up to the nearest sector.
    uint64_t aligned_size = AlignTo(requested_size, LP_SECTOR_SIZE);

    if (aligned_size > partition->size()) {
        return GrowPartition(partition, aligned_size);
    }
    if (aligned_size < partition->size()) {
        ShrinkPartition(partition, aligned_size);
    }
    return true;
}

}  // namespace fs_mgr
}  // namespace android
+28 −29
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ TEST(liblp, ResizePartition) {

    Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
    ASSERT_NE(system, nullptr);
    EXPECT_EQ(builder->GrowPartition(system, 65536), true);
    EXPECT_EQ(builder->ResizePartition(system, 65536), true);
    EXPECT_EQ(system->size(), 65536);
    ASSERT_EQ(system->extents().size(), 1);

@@ -55,24 +55,23 @@ TEST(liblp, ResizePartition) {
    // The first logical sector will be (4096+1024*2)/512 = 12.
    EXPECT_EQ(extent->physical_sector(), 12);

    // Test growing to the same size.
    EXPECT_EQ(builder->GrowPartition(system, 65536), true);
    // Test resizing to the same size.
    EXPECT_EQ(builder->ResizePartition(system, 65536), true);
    EXPECT_EQ(system->size(), 65536);
    EXPECT_EQ(system->extents().size(), 1);
    EXPECT_EQ(system->extents()[0]->num_sectors(), 65536 / LP_SECTOR_SIZE);
    // Test growing to a smaller size.
    EXPECT_EQ(builder->GrowPartition(system, 0), true);
    EXPECT_EQ(system->size(), 65536);
    EXPECT_EQ(system->extents().size(), 1);
    EXPECT_EQ(system->extents()[0]->num_sectors(), 65536 / LP_SECTOR_SIZE);
    // Test shrinking to a greater size.
    builder->ShrinkPartition(system, 131072);
    EXPECT_EQ(system->size(), 65536);
    // Test resizing to a smaller size.
    EXPECT_EQ(builder->ResizePartition(system, 0), true);
    EXPECT_EQ(system->size(), 0);
    EXPECT_EQ(system->extents().size(), 0);
    // Test resizing to a greater size.
    builder->ResizePartition(system, 131072);
    EXPECT_EQ(system->size(), 131072);
    EXPECT_EQ(system->extents().size(), 1);
    EXPECT_EQ(system->extents()[0]->num_sectors(), 65536 / LP_SECTOR_SIZE);
    EXPECT_EQ(system->extents()[0]->num_sectors(), 131072 / LP_SECTOR_SIZE);

    // Test shrinking within the same extent.
    builder->ShrinkPartition(system, 32768);
    builder->ResizePartition(system, 32768);
    EXPECT_EQ(system->size(), 32768);
    EXPECT_EQ(system->extents().size(), 1);
    extent = system->extents()[0]->AsLinearExtent();
@@ -81,7 +80,7 @@ TEST(liblp, ResizePartition) {
    EXPECT_EQ(extent->physical_sector(), 12);

    // Test shrinking to 0.
    builder->ShrinkPartition(system, 0);
    builder->ResizePartition(system, 0);
    EXPECT_EQ(system->size(), 0);
    EXPECT_EQ(system->extents().size(), 0);
}
@@ -92,11 +91,11 @@ TEST(liblp, PartitionAlignment) {
    // Test that we align up to one sector.
    Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
    ASSERT_NE(system, nullptr);
    EXPECT_EQ(builder->GrowPartition(system, 10000), true);
    EXPECT_EQ(builder->ResizePartition(system, 10000), true);
    EXPECT_EQ(system->size(), 10240);
    EXPECT_EQ(system->extents().size(), 1);

    builder->ShrinkPartition(system, 9000);
    builder->ResizePartition(system, 9000);
    EXPECT_EQ(system->size(), 9216);
    EXPECT_EQ(system->extents().size(), 1);
}
@@ -174,8 +173,8 @@ TEST(liblp, InternalPartitionAlignment) {

    // Add a bunch of small extents to each, interleaving.
    for (size_t i = 0; i < 10; i++) {
        ASSERT_TRUE(builder->GrowPartition(a, a->size() + 4096));
        ASSERT_TRUE(builder->GrowPartition(b, b->size() + 4096));
        ASSERT_TRUE(builder->ResizePartition(a, a->size() + 4096));
        ASSERT_TRUE(builder->ResizePartition(b, b->size() + 4096));
    }
    EXPECT_EQ(a->size(), 40960);
    EXPECT_EQ(b->size(), 40960);
@@ -203,9 +202,9 @@ TEST(liblp, UseAllDiskSpace) {

    Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
    ASSERT_NE(system, nullptr);
    EXPECT_EQ(builder->GrowPartition(system, 1036288), true);
    EXPECT_EQ(builder->ResizePartition(system, 1036288), true);
    EXPECT_EQ(system->size(), 1036288);
    EXPECT_EQ(builder->GrowPartition(system, 1036289), false);
    EXPECT_EQ(builder->ResizePartition(system, 1036289), false);
}

TEST(liblp, BuildComplex) {
@@ -215,9 +214,9 @@ TEST(liblp, BuildComplex) {
    Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
    ASSERT_NE(system, nullptr);
    ASSERT_NE(vendor, nullptr);
    EXPECT_EQ(builder->GrowPartition(system, 65536), true);
    EXPECT_EQ(builder->GrowPartition(vendor, 32768), true);
    EXPECT_EQ(builder->GrowPartition(system, 98304), true);
    EXPECT_EQ(builder->ResizePartition(system, 65536), true);
    EXPECT_EQ(builder->ResizePartition(vendor, 32768), true);
    EXPECT_EQ(builder->ResizePartition(system, 98304), true);
    EXPECT_EQ(system->size(), 98304);
    EXPECT_EQ(vendor->size(), 32768);

@@ -268,9 +267,9 @@ TEST(liblp, BuilderExport) {
    Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
    ASSERT_NE(system, nullptr);
    ASSERT_NE(vendor, nullptr);
    EXPECT_EQ(builder->GrowPartition(system, 65536), true);
    EXPECT_EQ(builder->GrowPartition(vendor, 32768), true);
    EXPECT_EQ(builder->GrowPartition(system, 98304), true);
    EXPECT_EQ(builder->ResizePartition(system, 65536), true);
    EXPECT_EQ(builder->ResizePartition(vendor, 32768), true);
    EXPECT_EQ(builder->ResizePartition(system, 98304), true);

    unique_ptr<LpMetadata> exported = builder->Export();
    EXPECT_NE(exported, nullptr);
@@ -323,9 +322,9 @@ TEST(liblp, BuilderImport) {
    Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
    ASSERT_NE(system, nullptr);
    ASSERT_NE(vendor, nullptr);
    EXPECT_EQ(builder->GrowPartition(system, 65536), true);
    EXPECT_EQ(builder->GrowPartition(vendor, 32768), true);
    EXPECT_EQ(builder->GrowPartition(system, 98304), true);
    EXPECT_EQ(builder->ResizePartition(system, 65536), true);
    EXPECT_EQ(builder->ResizePartition(vendor, 32768), true);
    EXPECT_EQ(builder->ResizePartition(system, 98304), true);

    unique_ptr<LpMetadata> exported = builder->Export();
    ASSERT_NE(exported, nullptr);
+9 −20
Original line number Diff line number Diff line
@@ -162,29 +162,17 @@ class MetadataBuilder {
    // Find a partition by name. If no partition is found, nullptr is returned.
    Partition* FindPartition(const std::string& name);

    // Grow a partition to the requested size. If the partition's size is already
    // greater or equal to the requested size, this will return true and the
    // partition table will not be changed. Otherwise, a greedy algorithm is
    // used to find free gaps in the partition table and allocate them for this
    // partition. If not enough space can be allocated, false is returned, and
    // the parition table will not be modified.
    // Grow or shrink a partition to the requested size. This size will be
    // rounded UP to the nearest block (512 bytes).
    //
    // The size will be rounded UP to the nearest sector.
    // When growing a partition, a greedy algorithm is used to find free gaps
    // in the partition table and allocate them. If not enough space can be
    // allocated, false is returned, and the parition table will not be
    // modified.
    //
    // Note, this is an in-memory operation, and it does not alter the
    // underlying filesystem or contents of the partition on disk.
    bool GrowPartition(Partition* partition, uint64_t requested_size);

    // Shrink a partition to the requested size. If the partition is already
    // smaller than the given size, this will return and the partition table
    // will not be changed. Otherwise, extents will be removed and/or shrunk
    // from the end of the partition until it is the requested size.
    //
    // The size will be rounded UP to the nearest sector.
    //
    // Note, this is an in-memory operation, and it does not alter the
    // underlying filesystem or contents of the partition on disk.
    void ShrinkPartition(Partition* partition, uint64_t requested_size);
    bool ResizePartition(Partition* partition, uint64_t requested_size);

    // Amount of space that can be allocated to logical partitions.
    uint64_t AllocatableSpace() const;
@@ -198,7 +186,8 @@ class MetadataBuilder {
    MetadataBuilder();
    bool Init(const BlockDeviceInfo& info, uint32_t metadata_max_size, uint32_t metadata_slot_count);
    bool Init(const LpMetadata& metadata);

    bool GrowPartition(Partition* partition, uint64_t aligned_size);
    void ShrinkPartition(Partition* partition, uint64_t aligned_size);
    uint64_t AlignSector(uint64_t sector);

    LpMetadataGeometry geometry_;
+2 −2
Original line number Diff line number Diff line
@@ -85,7 +85,7 @@ static bool AddDefaultPartitions(MetadataBuilder* builder) {
    if (!system) {
        return false;
    }
    return builder->GrowPartition(system, 24 * 1024);
    return builder->ResizePartition(system, 24 * 1024);
}

// Create a temporary disk and flash it with the default partition setup.
@@ -345,7 +345,7 @@ TEST(liblp, TooManyPartitions) {
    ASSERT_NE(partition, nullptr);
    // Add one extent to any partition to fill up more space - we're at 508
    // bytes after this, out of 512.
    ASSERT_TRUE(builder->GrowPartition(partition, 1024));
    ASSERT_TRUE(builder->ResizePartition(partition, 1024));

    unique_ptr<LpMetadata> exported = builder->Export();
    ASSERT_NE(exported, nullptr);