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

Commit fb0386f7 authored by Yifan Hong's avatar Yifan Hong Committed by android-build-merger
Browse files

Merge "liblp: Indicate usable regions in ResizePartition"

am: d6c426c0

Change-Id: Ia555bc10e05cd60fec50f7974581ff9a1269c67d
parents ab92aeb6 d6c426c0
Loading
Loading
Loading
Loading
+31 −4
Original line number Original line Diff line number Diff line
@@ -579,12 +579,38 @@ bool MetadataBuilder::ValidatePartitionSizeChange(Partition* partition, uint64_t
    return true;
    return true;
}
}


bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size) {
Interval Interval::Intersect(const Interval& a, const Interval& b) {
    Interval ret = a;
    if (a.device_index != b.device_index) {
        ret.start = ret.end = a.start;  // set length to 0 to indicate no intersection.
        return ret;
    }
    ret.start = std::max(a.start, b.start);
    ret.end = std::max(ret.start, std::min(a.end, b.end));
    return ret;
}

std::vector<Interval> Interval::Intersect(const std::vector<Interval>& a,
                                          const std::vector<Interval>& b) {
    std::vector<Interval> ret;
    for (const Interval& a_interval : a) {
        for (const Interval& b_interval : b) {
            auto intersect = Intersect(a_interval, b_interval);
            if (intersect.length() > 0) ret.emplace_back(std::move(intersect));
        }
    }
    return ret;
}

bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size,
                                    const std::vector<Interval>& free_region_hint) {
    uint64_t space_needed = aligned_size - partition->size();
    uint64_t space_needed = aligned_size - partition->size();
    uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE;
    uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE;
    DCHECK(sectors_needed * LP_SECTOR_SIZE == space_needed);
    DCHECK(sectors_needed * LP_SECTOR_SIZE == space_needed);


    std::vector<Interval> free_regions = GetFreeRegions();
    std::vector<Interval> free_regions = GetFreeRegions();
    if (!free_region_hint.empty())
        free_regions = Interval::Intersect(free_regions, free_region_hint);


    const uint64_t sectors_per_block = geometry_.logical_block_size / LP_SECTOR_SIZE;
    const uint64_t sectors_per_block = geometry_.logical_block_size / LP_SECTOR_SIZE;
    CHECK_NE(sectors_per_block, 0);
    CHECK_NE(sectors_per_block, 0);
@@ -650,7 +676,7 @@ bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size)
    return true;
    return true;
}
}


std::vector<MetadataBuilder::Interval> MetadataBuilder::PrioritizeSecondHalfOfSuper(
std::vector<Interval> MetadataBuilder::PrioritizeSecondHalfOfSuper(
        const std::vector<Interval>& free_list) {
        const std::vector<Interval>& free_list) {
    const auto& super = block_devices_[0];
    const auto& super = block_devices_[0];
    uint64_t first_sector = super.first_logical_sector;
    uint64_t first_sector = super.first_logical_sector;
@@ -926,7 +952,8 @@ bool MetadataBuilder::UpdateBlockDeviceInfo(size_t index, const BlockDeviceInfo&
    return true;
    return true;
}
}


bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size) {
bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size,
                                      const std::vector<Interval>& free_region_hint) {
    // Align the space needed up to the nearest sector.
    // Align the space needed up to the nearest sector.
    uint64_t aligned_size = AlignTo(requested_size, geometry_.logical_block_size);
    uint64_t aligned_size = AlignTo(requested_size, geometry_.logical_block_size);
    uint64_t old_size = partition->size();
    uint64_t old_size = partition->size();
@@ -936,7 +963,7 @@ bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_s
    }
    }


    if (aligned_size > old_size) {
    if (aligned_size > old_size) {
        if (!GrowPartition(partition, aligned_size)) {
        if (!GrowPartition(partition, aligned_size, free_region_hint)) {
            return false;
            return false;
        }
        }
    } else if (aligned_size < partition->size()) {
    } else if (aligned_size < partition->size()) {
+35 −0
Original line number Original line Diff line number Diff line
@@ -887,3 +887,38 @@ TEST_F(BuilderTest, UpdateSuper) {
    std::set<std::string> partitions_to_keep{"system_a", "vendor_a", "product_a"};
    std::set<std::string> partitions_to_keep{"system_a", "vendor_a", "product_a"};
    ASSERT_TRUE(builder->ImportPartitions(*on_disk.get(), partitions_to_keep));
    ASSERT_TRUE(builder->ImportPartitions(*on_disk.get(), partitions_to_keep));
}
}

// Interval has operator< defined; it is not appropriate to re-define Interval::operator== that
// compares device index.
namespace android {
namespace fs_mgr {
bool operator==(const Interval& a, const Interval& b) {
    return a.device_index == b.device_index && a.start == b.start && a.end == b.end;
}
}  // namespace fs_mgr
}  // namespace android

TEST_F(BuilderTest, Interval) {
    EXPECT_EQ(0u, Interval::Intersect(Interval(0, 100, 200), Interval(0, 50, 100)).length());
    EXPECT_EQ(Interval(0, 100, 150),
              Interval::Intersect(Interval(0, 100, 200), Interval(0, 50, 150)));
    EXPECT_EQ(Interval(0, 100, 200),
              Interval::Intersect(Interval(0, 100, 200), Interval(0, 50, 200)));
    EXPECT_EQ(Interval(0, 100, 200),
              Interval::Intersect(Interval(0, 100, 200), Interval(0, 50, 250)));
    EXPECT_EQ(Interval(0, 100, 200),
              Interval::Intersect(Interval(0, 100, 200), Interval(0, 100, 200)));
    EXPECT_EQ(Interval(0, 150, 200),
              Interval::Intersect(Interval(0, 100, 200), Interval(0, 150, 250)));
    EXPECT_EQ(0u, Interval::Intersect(Interval(0, 100, 200), Interval(0, 200, 250)).length());

    auto v = Interval::Intersect(std::vector<Interval>{Interval(0, 0, 50), Interval(0, 100, 150)},
                                 std::vector<Interval>{Interval(0, 25, 125)});
    ASSERT_EQ(2, v.size());
    EXPECT_EQ(Interval(0, 25, 50), v[0]);
    EXPECT_EQ(Interval(0, 100, 125), v[1]);

    EXPECT_EQ(0u, Interval::Intersect(std::vector<Interval>{Interval(0, 0, 50)},
                                      std::vector<Interval>{Interval(0, 100, 150)})
                          .size());
}
+37 −18
Original line number Original line Diff line number Diff line
@@ -138,6 +138,33 @@ class Partition final {
    uint64_t size_;
    uint64_t size_;
};
};


// An interval in the metadata. This is similar to a LinearExtent with one difference.
// LinearExtent represents a "used" region in the metadata, while Interval can also represent
// an "unused" region.
struct Interval {
    uint32_t device_index;
    uint64_t start;
    uint64_t end;

    Interval(uint32_t device_index, uint64_t start, uint64_t end)
        : device_index(device_index), start(start), end(end) {}
    uint64_t length() const { return end - start; }

    // Note: the device index is not included in sorting (intervals are
    // sorted in per-device lists).
    bool operator<(const Interval& other) const {
        return (start == other.start) ? end < other.end : start < other.start;
    }

    // Intersect |a| with |b|.
    // If no intersection, result has 0 length().
    static Interval Intersect(const Interval& a, const Interval& b);

    // Intersect two lists of intervals, and store result to |a|.
    static std::vector<Interval> Intersect(const std::vector<Interval>& a,
                                           const std::vector<Interval>& b);
};

class MetadataBuilder {
class MetadataBuilder {
  public:
  public:
    // Construct an empty logical partition table builder given the specified
    // Construct an empty logical partition table builder given the specified
@@ -244,7 +271,11 @@ class MetadataBuilder {
    //
    //
    // Note, this is an in-memory operation, and it does not alter the
    // Note, this is an in-memory operation, and it does not alter the
    // underlying filesystem or contents of the partition on disk.
    // underlying filesystem or contents of the partition on disk.
    bool ResizePartition(Partition* partition, uint64_t requested_size);
    //
    // If |free_region_hint| is not empty, it will only try to allocate extents
    // in regions within the list.
    bool ResizePartition(Partition* partition, uint64_t requested_size,
                         const std::vector<Interval>& free_region_hint = {});


    // Return the list of partitions belonging to a group.
    // Return the list of partitions belonging to a group.
    std::vector<Partition*> ListPartitionsInGroup(const std::string& group_name);
    std::vector<Partition*> ListPartitionsInGroup(const std::string& group_name);
@@ -291,6 +322,9 @@ class MetadataBuilder {
    // Return the name of the block device at |index|.
    // Return the name of the block device at |index|.
    std::string GetBlockDevicePartitionName(uint64_t index) const;
    std::string GetBlockDevicePartitionName(uint64_t index) const;


    // Return the list of free regions not occupied by extents in the metadata.
    std::vector<Interval> GetFreeRegions() const;

  private:
  private:
    MetadataBuilder();
    MetadataBuilder();
    MetadataBuilder(const MetadataBuilder&) = delete;
    MetadataBuilder(const MetadataBuilder&) = delete;
@@ -300,7 +334,8 @@ class MetadataBuilder {
    bool Init(const std::vector<BlockDeviceInfo>& block_devices, const std::string& super_partition,
    bool Init(const std::vector<BlockDeviceInfo>& block_devices, const std::string& super_partition,
              uint32_t metadata_max_size, uint32_t metadata_slot_count);
              uint32_t metadata_max_size, uint32_t metadata_slot_count);
    bool Init(const LpMetadata& metadata);
    bool Init(const LpMetadata& metadata);
    bool GrowPartition(Partition* partition, uint64_t aligned_size);
    bool GrowPartition(Partition* partition, uint64_t aligned_size,
                       const std::vector<Interval>& free_region_hint);
    void ShrinkPartition(Partition* partition, uint64_t aligned_size);
    void ShrinkPartition(Partition* partition, uint64_t aligned_size);
    uint64_t AlignSector(const LpMetadataBlockDevice& device, uint64_t sector) const;
    uint64_t AlignSector(const LpMetadataBlockDevice& device, uint64_t sector) const;
    uint64_t TotalSizeOfGroup(PartitionGroup* group) const;
    uint64_t TotalSizeOfGroup(PartitionGroup* group) const;
@@ -323,22 +358,6 @@ class MetadataBuilder {


    bool ValidatePartitionGroups() const;
    bool ValidatePartitionGroups() const;


    struct Interval {
        uint32_t device_index;
        uint64_t start;
        uint64_t end;

        Interval(uint32_t device_index, uint64_t start, uint64_t end)
            : device_index(device_index), start(start), end(end) {}
        uint64_t length() const { return end - start; }

        // Note: the device index is not included in sorting (intervals are
        // sorted in per-device lists).
        bool operator<(const Interval& other) const {
            return (start == other.start) ? end < other.end : start < other.start;
        }
    };
    std::vector<Interval> GetFreeRegions() const;
    bool IsAnyRegionCovered(const std::vector<Interval>& regions,
    bool IsAnyRegionCovered(const std::vector<Interval>& regions,
                            const LinearExtent& candidate) const;
                            const LinearExtent& candidate) const;
    bool IsAnyRegionAllocated(const LinearExtent& candidate) const;
    bool IsAnyRegionAllocated(const LinearExtent& candidate) const;