Merge "liblp: Add helpers for modifying groups."
This commit is contained in:
commit
34ad8ca773
3 changed files with 131 additions and 4 deletions
|
@ -33,6 +33,8 @@ namespace fs_mgr {
|
|||
bool MetadataBuilder::sABOverrideSet;
|
||||
bool MetadataBuilder::sABOverrideValue;
|
||||
|
||||
static const std::string kDefaultGroup = "default";
|
||||
|
||||
bool LinearExtent::AddTo(LpMetadata* out) const {
|
||||
if (device_index_ >= out->block_devices.size()) {
|
||||
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_.logical_block_size = logical_block_size;
|
||||
|
||||
if (!AddGroup("default", 0)) {
|
||||
if (!AddGroup(kDefaultGroup, 0)) {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
return AddPartition(name, "default", attributes);
|
||||
return AddPartition(name, kDefaultGroup, attributes);
|
||||
}
|
||||
|
||||
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() {
|
||||
if (!ValidatePartitionGroups()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
|
||||
metadata->header = header_;
|
||||
metadata->geometry = geometry_;
|
||||
|
@ -695,7 +701,7 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
|
|||
LERROR << "Partition group name is too long: " << group->name();
|
||||
return nullptr;
|
||||
}
|
||||
if (auto_slot_suffixing_ && group->name() != "default") {
|
||||
if (auto_slot_suffixing_ && group->name() != kDefaultGroup) {
|
||||
out.flags |= LP_GROUP_SLOT_SUFFIXED;
|
||||
}
|
||||
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) {
|
||||
if (group_name == "default") {
|
||||
if (group_name == kDefaultGroup) {
|
||||
// Cannot remove the default group.
|
||||
return;
|
||||
}
|
||||
|
@ -1000,5 +1006,53 @@ bool MetadataBuilder::AddLinearExtent(Partition* partition, const std::string& b
|
|||
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 android
|
||||
|
|
|
@ -549,6 +549,58 @@ TEST_F(BuilderTest, GroupSizeLimits) {
|
|||
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
|
||||
return x << 30;
|
||||
}
|
||||
|
|
|
@ -80,6 +80,8 @@ class ZeroExtent final : public Extent {
|
|||
};
|
||||
|
||||
class PartitionGroup final {
|
||||
friend class MetadataBuilder;
|
||||
|
||||
public:
|
||||
explicit PartitionGroup(const std::string& name, uint64_t maximum_size)
|
||||
: name_(name), maximum_size_(maximum_size) {}
|
||||
|
@ -88,6 +90,8 @@ class PartitionGroup final {
|
|||
uint64_t maximum_size() const { return maximum_size_; }
|
||||
|
||||
private:
|
||||
void set_maximum_size(uint64_t maximum_size) { maximum_size_ = maximum_size; }
|
||||
|
||||
std::string name_;
|
||||
uint64_t maximum_size_;
|
||||
};
|
||||
|
@ -116,6 +120,7 @@ class Partition final {
|
|||
|
||||
private:
|
||||
void ShrinkTo(uint64_t aligned_size);
|
||||
void set_group_name(const std::string& group_name) { group_name_ = group_name; }
|
||||
|
||||
std::string name_;
|
||||
std::string group_name_;
|
||||
|
@ -235,6 +240,21 @@ class MetadataBuilder {
|
|||
// underlying filesystem or contents of the partition on disk.
|
||||
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.
|
||||
uint64_t AllocatableSpace() const;
|
||||
uint64_t UsedSpace() const;
|
||||
|
@ -283,6 +303,7 @@ class MetadataBuilder {
|
|||
bool ImportPartition(const LpMetadata& metadata, const LpMetadataPartition& source);
|
||||
bool IsABDevice() const;
|
||||
bool IsRetrofitDevice() const;
|
||||
bool ValidatePartitionGroups() const;
|
||||
|
||||
struct Interval {
|
||||
uint32_t device_index;
|
||||
|
|
Loading…
Reference in a new issue