Loading fs_mgr/liblp/builder.cpp +58 −4 Original line number Original line Diff line number Diff line Loading @@ -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."; Loading Loading @@ -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; Loading @@ -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, Loading Loading @@ -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_; Loading @@ -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)); Loading Loading @@ -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; } } Loading Loading @@ -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 fs_mgr/liblp/builder_test.cpp +52 −0 Original line number Original line Diff line number Diff line Loading @@ -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; } } Loading fs_mgr/liblp/include/liblp/builder.h +21 −0 Original line number Original line Diff line number Diff line Loading @@ -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) {} Loading @@ -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_; }; }; Loading Loading @@ -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_; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading
fs_mgr/liblp/builder.cpp +58 −4 Original line number Original line Diff line number Diff line Loading @@ -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."; Loading Loading @@ -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; Loading @@ -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, Loading Loading @@ -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_; Loading @@ -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)); Loading Loading @@ -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; } } Loading Loading @@ -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
fs_mgr/liblp/builder_test.cpp +52 −0 Original line number Original line Diff line number Diff line Loading @@ -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; } } Loading
fs_mgr/liblp/include/liblp/builder.h +21 −0 Original line number Original line Diff line number Diff line Loading @@ -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) {} Loading @@ -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_; }; }; Loading Loading @@ -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_; Loading Loading @@ -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; Loading Loading @@ -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; Loading