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

Commit 652fae87 authored by David Anderson's avatar David Anderson Committed by android-build-merger
Browse files

Merge "liblp: Add helpers for modifying groups." am: 34ad8ca7 am: e49bd84b

am: 2d247f95

Change-Id: Icdee6024d19591607d00cb131c7f25795112665c
parents cba1ada0 2d247f95
Loading
Loading
Loading
Loading
+58 −4
Original line number Original line Diff line number Diff line
@@ -33,6 +33,8 @@ namespace fs_mgr {
bool MetadataBuilder::sABOverrideSet;
bool MetadataBuilder::sABOverrideSet;
bool MetadataBuilder::sABOverrideValue;
bool MetadataBuilder::sABOverrideValue;


static const std::string kDefaultGroup = "default";

bool LinearExtent::AddTo(LpMetadata* out) const {
bool LinearExtent::AddTo(LpMetadata* out) const {
    if (device_index_ >= out->block_devices.size()) {
    if (device_index_ >= out->block_devices.size()) {
        LERROR << "Extent references unknown block device.";
        LERROR << "Extent references unknown block device.";
@@ -403,7 +405,7 @@ bool MetadataBuilder::Init(const std::vector<BlockDeviceInfo>& block_devices,
    geometry_.metadata_slot_count = metadata_slot_count;
    geometry_.metadata_slot_count = metadata_slot_count;
    geometry_.logical_block_size = logical_block_size;
    geometry_.logical_block_size = logical_block_size;


    if (!AddGroup("default", 0)) {
    if (!AddGroup(kDefaultGroup, 0)) {
        return false;
        return false;
    }
    }
    return true;
    return true;
@@ -419,7 +421,7 @@ bool MetadataBuilder::AddGroup(const std::string& group_name, uint64_t maximum_s
}
}


Partition* MetadataBuilder::AddPartition(const std::string& name, uint32_t attributes) {
Partition* MetadataBuilder::AddPartition(const std::string& name, uint32_t attributes) {
    return AddPartition(name, "default", attributes);
    return AddPartition(name, kDefaultGroup, attributes);
}
}


Partition* MetadataBuilder::AddPartition(const std::string& name, const std::string& group_name,
Partition* MetadataBuilder::AddPartition(const std::string& name, const std::string& group_name,
@@ -675,6 +677,10 @@ void MetadataBuilder::ShrinkPartition(Partition* partition, uint64_t aligned_siz
}
}


std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
    if (!ValidatePartitionGroups()) {
        return nullptr;
    }

    std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
    std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
    metadata->header = header_;
    metadata->header = header_;
    metadata->geometry = geometry_;
    metadata->geometry = geometry_;
@@ -695,7 +701,7 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
            LERROR << "Partition group name is too long: " << group->name();
            LERROR << "Partition group name is too long: " << group->name();
            return nullptr;
            return nullptr;
        }
        }
        if (auto_slot_suffixing_ && group->name() != "default") {
        if (auto_slot_suffixing_ && group->name() != kDefaultGroup) {
            out.flags |= LP_GROUP_SLOT_SUFFIXED;
            out.flags |= LP_GROUP_SLOT_SUFFIXED;
        }
        }
        strncpy(out.name, group->name().c_str(), sizeof(out.name));
        strncpy(out.name, group->name().c_str(), sizeof(out.name));
@@ -877,7 +883,7 @@ std::vector<std::string> MetadataBuilder::ListGroups() const {
}
}


void MetadataBuilder::RemoveGroupAndPartitions(const std::string& group_name) {
void MetadataBuilder::RemoveGroupAndPartitions(const std::string& group_name) {
    if (group_name == "default") {
    if (group_name == kDefaultGroup) {
        // Cannot remove the default group.
        // Cannot remove the default group.
        return;
        return;
    }
    }
@@ -1000,5 +1006,53 @@ bool MetadataBuilder::AddLinearExtent(Partition* partition, const std::string& b
    return true;
    return true;
}
}


std::vector<Partition*> MetadataBuilder::ListPartitionsInGroup(const std::string& group_name) {
    std::vector<Partition*> partitions;
    for (const auto& partition : partitions_) {
        if (partition->group_name() == group_name) {
            partitions.emplace_back(partition.get());
        }
    }
    return partitions;
}

bool MetadataBuilder::ChangePartitionGroup(Partition* partition, const std::string& group_name) {
    if (!FindGroup(group_name)) {
        LERROR << "Partition cannot change to unknown group: " << group_name;
        return false;
    }
    partition->set_group_name(group_name);
    return true;
}

bool MetadataBuilder::ValidatePartitionGroups() const {
    for (const auto& group : groups_) {
        if (!group->maximum_size()) {
            continue;
        }
        uint64_t used = TotalSizeOfGroup(group.get());
        if (used > group->maximum_size()) {
            LERROR << "Partition group " << group->name() << " exceeds maximum size (" << used
                   << " bytes used, maximum " << group->maximum_size() << ")";
            return false;
        }
    }
    return true;
}

bool MetadataBuilder::ChangeGroupSize(const std::string& group_name, uint64_t maximum_size) {
    if (group_name == kDefaultGroup) {
        LERROR << "Cannot change the size of the default group";
        return false;
    }
    PartitionGroup* group = FindGroup(group_name);
    if (!group) {
        LERROR << "Cannot change size of unknown partition group: " << group_name;
        return false;
    }
    group->set_maximum_size(maximum_size);
    return true;
}

}  // namespace fs_mgr
}  // namespace fs_mgr
}  // namespace android
}  // namespace android
+52 −0
Original line number Original line Diff line number Diff line
@@ -549,6 +549,58 @@ TEST_F(BuilderTest, GroupSizeLimits) {
    EXPECT_EQ(partition->size(), 16384);
    EXPECT_EQ(partition->size(), 16384);
}
}


TEST_F(BuilderTest, ListPartitionsInGroup) {
    BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 4096);
    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
    ASSERT_NE(builder, nullptr);

    ASSERT_TRUE(builder->AddGroup("groupA", 16384));
    ASSERT_TRUE(builder->AddGroup("groupB", 16384));

    Partition* system = builder->AddPartition("system", "groupA", 0);
    Partition* vendor = builder->AddPartition("vendor", "groupA", 0);
    Partition* product = builder->AddPartition("product", "groupB", 0);
    ASSERT_NE(system, nullptr);
    ASSERT_NE(vendor, nullptr);
    ASSERT_NE(product, nullptr);

    auto groupA = builder->ListPartitionsInGroup("groupA");
    auto groupB = builder->ListPartitionsInGroup("groupB");
    auto groupC = builder->ListPartitionsInGroup("groupC");
    ASSERT_THAT(groupA, ElementsAre(system, vendor));
    ASSERT_THAT(groupB, ElementsAre(product));
    ASSERT_TRUE(groupC.empty());
}

TEST_F(BuilderTest, ChangeGroups) {
    BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 4096);
    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
    ASSERT_NE(builder, nullptr);

    ASSERT_TRUE(builder->AddGroup("groupA", 16384));
    ASSERT_TRUE(builder->AddGroup("groupB", 32768));

    Partition* system = builder->AddPartition("system", "groupA", 0);
    Partition* vendor = builder->AddPartition("vendor", "groupB", 0);
    ASSERT_NE(system, nullptr);
    ASSERT_NE(vendor, nullptr);
    ASSERT_NE(builder->Export(), nullptr);

    ASSERT_FALSE(builder->ChangePartitionGroup(system, "groupXYZ"));
    ASSERT_TRUE(builder->ChangePartitionGroup(system, "groupB"));
    ASSERT_NE(builder->Export(), nullptr);

    // Violate group constraint by reassigning groups.
    ASSERT_TRUE(builder->ResizePartition(system, 16384 + 4096));
    ASSERT_TRUE(builder->ChangePartitionGroup(system, "groupA"));
    ASSERT_EQ(builder->Export(), nullptr);

    ASSERT_FALSE(builder->ChangeGroupSize("default", 2));
    ASSERT_FALSE(builder->ChangeGroupSize("unknown", 2));
    ASSERT_TRUE(builder->ChangeGroupSize("groupA", 32768));
    ASSERT_NE(builder->Export(), nullptr);
}

constexpr unsigned long long operator"" _GiB(unsigned long long x) {  // NOLINT
constexpr unsigned long long operator"" _GiB(unsigned long long x) {  // NOLINT
    return x << 30;
    return x << 30;
}
}
+21 −0
Original line number Original line Diff line number Diff line
@@ -80,6 +80,8 @@ class ZeroExtent final : public Extent {
};
};


class PartitionGroup final {
class PartitionGroup final {
    friend class MetadataBuilder;

  public:
  public:
    explicit PartitionGroup(const std::string& name, uint64_t maximum_size)
    explicit PartitionGroup(const std::string& name, uint64_t maximum_size)
        : name_(name), maximum_size_(maximum_size) {}
        : name_(name), maximum_size_(maximum_size) {}
@@ -88,6 +90,8 @@ class PartitionGroup final {
    uint64_t maximum_size() const { return maximum_size_; }
    uint64_t maximum_size() const { return maximum_size_; }


  private:
  private:
    void set_maximum_size(uint64_t maximum_size) { maximum_size_ = maximum_size; }

    std::string name_;
    std::string name_;
    uint64_t maximum_size_;
    uint64_t maximum_size_;
};
};
@@ -116,6 +120,7 @@ class Partition final {


  private:
  private:
    void ShrinkTo(uint64_t aligned_size);
    void ShrinkTo(uint64_t aligned_size);
    void set_group_name(const std::string& group_name) { group_name_ = group_name; }


    std::string name_;
    std::string name_;
    std::string group_name_;
    std::string group_name_;
@@ -235,6 +240,21 @@ class MetadataBuilder {
    // 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);
    bool ResizePartition(Partition* partition, uint64_t requested_size);


    // Return the list of partitions belonging to a group.
    std::vector<Partition*> ListPartitionsInGroup(const std::string& group_name);

    // Changes a partition's group. Size constraints will not be checked until
    // the metadata is exported, to avoid errors during potential group and
    // size shuffling operations. This will return false if the new group does
    // not exist.
    bool ChangePartitionGroup(Partition* partition, const std::string& group_name);

    // Changes the size of a partition group. Size constraints will not be
    // checked until metadata is exported, to avoid errors during group
    // reshuffling. This will return false if the group does not exist, or if
    // the group name is "default".
    bool ChangeGroupSize(const std::string& group_name, uint64_t maximum_size);

    // Amount of space that can be allocated to logical partitions.
    // Amount of space that can be allocated to logical partitions.
    uint64_t AllocatableSpace() const;
    uint64_t AllocatableSpace() const;
    uint64_t UsedSpace() const;
    uint64_t UsedSpace() const;
@@ -283,6 +303,7 @@ class MetadataBuilder {
    bool ImportPartition(const LpMetadata& metadata, const LpMetadataPartition& source);
    bool ImportPartition(const LpMetadata& metadata, const LpMetadataPartition& source);
    bool IsABDevice() const;
    bool IsABDevice() const;
    bool IsRetrofitDevice() const;
    bool IsRetrofitDevice() const;
    bool ValidatePartitionGroups() const;


    struct Interval {
    struct Interval {
        uint32_t device_index;
        uint32_t device_index;