Loading fs_mgr/liblp/Android.bp +16 −0 Original line number Diff line number Diff line Loading @@ -42,3 +42,19 @@ cc_library_static { ], export_include_dirs: ["include"], } cc_test { name: "liblp_test", defaults: ["fs_mgr_defaults"], static_libs: [ "libbase", "liblog", "libcrypto", "libcrypto_utils", "liblp", ], srcs: [ "builder_test.cpp", "utility_test.cpp", ], } fs_mgr/liblp/builder.cpp +5 −1 Original line number Diff line number Diff line Loading @@ -287,7 +287,7 @@ bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t requested_siz DCHECK(first_sector <= geometry_.last_logical_sector); // Note: the last usable sector is inclusive. if (first_sector + sectors_needed > geometry_.last_logical_sector) { if (geometry_.last_logical_sector + 1 - first_sector < sectors_needed) { LERROR << "Not enough free space to expand partition: " << partition->name(); return false; } Loading Loading @@ -347,5 +347,9 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() { return metadata; } uint64_t MetadataBuilder::AllocatableSpace() const { return (geometry_.last_logical_sector - geometry_.first_logical_sector + 1) * LP_SECTOR_SIZE; } } // namespace fs_mgr } // namespace android fs_mgr/liblp/builder_test.cpp 0 → 100644 +308 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <gtest/gtest.h> #include <liblp/builder.h> using namespace std; using namespace android::fs_mgr; static const char* TEST_GUID = "A799D1D6-669F-41D8-A3F0-EBB7572D8302"; static const char* TEST_GUID2 = "A799D1D6-669F-41D8-A3F0-EBB7572D8303"; TEST(liblp, BuildBasic) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); Partition* partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); ASSERT_NE(partition, nullptr); EXPECT_EQ(partition->name(), "system"); EXPECT_EQ(partition->guid(), TEST_GUID); EXPECT_EQ(partition->attributes(), LP_PARTITION_ATTR_READONLY); EXPECT_EQ(partition->size(), 0); EXPECT_EQ(builder->FindPartition("system"), partition); builder->RemovePartition("system"); EXPECT_EQ(builder->FindPartition("system"), nullptr); } TEST(liblp, ResizePartition) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); ASSERT_NE(system, nullptr); EXPECT_EQ(builder->GrowPartition(system, 65536), true); EXPECT_EQ(system->size(), 65536); ASSERT_EQ(system->extents().size(), 1); LinearExtent* extent = system->extents()[0]->AsLinearExtent(); ASSERT_NE(extent, nullptr); EXPECT_EQ(extent->num_sectors(), 65536 / LP_SECTOR_SIZE); // 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); 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); EXPECT_EQ(system->extents().size(), 1); EXPECT_EQ(system->extents()[0]->num_sectors(), 65536 / LP_SECTOR_SIZE); // Test shrinking within the same extent. builder->ShrinkPartition(system, 32768); EXPECT_EQ(system->size(), 32768); EXPECT_EQ(system->extents().size(), 1); extent = system->extents()[0]->AsLinearExtent(); ASSERT_NE(extent, nullptr); EXPECT_EQ(extent->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(extent->physical_sector(), 12); // Test shrinking to 0. builder->ShrinkPartition(system, 0); EXPECT_EQ(system->size(), 0); EXPECT_EQ(system->extents().size(), 0); } TEST(liblp, PartitionAlignment) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); // 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(system->size(), 10240); EXPECT_EQ(system->extents().size(), 1); builder->ShrinkPartition(system, 9000); EXPECT_EQ(system->size(), 9216); EXPECT_EQ(system->extents().size(), 1); } TEST(liblp, DiskAlignment) { static const uint64_t kDiskSize = 1000000; static const uint32_t kMetadataSize = 1024; static const uint32_t kMetadataSlots = 2; // If the disk size is not aligned to 512 bytes, make sure it still leaves // space at the end for backup metadata, and that it doesn't overlap with // the space for logical partitions. unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(kDiskSize, kMetadataSize, kMetadataSlots); unique_ptr<LpMetadata> exported = builder->Export(); ASSERT_NE(exported, nullptr); static const size_t kMetadataSpace = (kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE; uint64_t space_at_end = kDiskSize - (exported->geometry.last_logical_sector + 1) * LP_SECTOR_SIZE; EXPECT_GE(space_at_end, kMetadataSpace); } TEST(liblp, MetadataAlignment) { // Make sure metadata sizes get aligned up. unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1000, 2); unique_ptr<LpMetadata> exported = builder->Export(); ASSERT_NE(exported, nullptr); EXPECT_EQ(exported->geometry.metadata_max_size, 1024); } TEST(liblp, UseAllDiskSpace) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); EXPECT_EQ(builder->AllocatableSpace(), 1036288); Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); ASSERT_NE(system, nullptr); EXPECT_EQ(builder->GrowPartition(system, 1036288), true); EXPECT_EQ(system->size(), 1036288); EXPECT_EQ(builder->GrowPartition(system, 1036289), false); } TEST(liblp, BuildComplex) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); 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(system->size(), 98304); EXPECT_EQ(vendor->size(), 32768); // We now expect to have 3 extents total: 2 for system, 1 for vendor, since // our allocation strategy is greedy/first-fit. ASSERT_EQ(system->extents().size(), 2); ASSERT_EQ(vendor->extents().size(), 1); LinearExtent* system1 = system->extents()[0]->AsLinearExtent(); LinearExtent* system2 = system->extents()[1]->AsLinearExtent(); LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent(); ASSERT_NE(system1, nullptr); ASSERT_NE(system2, nullptr); ASSERT_NE(vendor1, nullptr); EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE); EXPECT_EQ(system1->physical_sector(), 12); EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(system2->physical_sector(), 204); EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(vendor1->physical_sector(), 140); EXPECT_EQ(system1->physical_sector() + system1->num_sectors(), vendor1->physical_sector()); EXPECT_EQ(vendor1->physical_sector() + vendor1->num_sectors(), system2->physical_sector()); } TEST(liblp, AddInvalidPartition) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); Partition* partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); ASSERT_NE(partition, nullptr); // Duplicate name. partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); EXPECT_EQ(partition, nullptr); // Empty name. partition = builder->AddPartition("", TEST_GUID, LP_PARTITION_ATTR_READONLY); EXPECT_EQ(partition, nullptr); } TEST(liblp, BuilderExport) { static const uint64_t kDiskSize = 1024 * 1024; static const uint32_t kMetadataSize = 1024; static const uint32_t kMetadataSlots = 2; unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(kDiskSize, kMetadataSize, kMetadataSlots); Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); 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); unique_ptr<LpMetadata> exported = builder->Export(); EXPECT_NE(exported, nullptr); // Verify geometry. Some details of this may change if we change the // metadata structures. So in addition to checking the exact values, we // also check that they are internally consistent after. const LpMetadataGeometry& geometry = exported->geometry; EXPECT_EQ(geometry.magic, LP_METADATA_GEOMETRY_MAGIC); EXPECT_EQ(geometry.struct_size, sizeof(geometry)); EXPECT_EQ(geometry.metadata_max_size, 1024); EXPECT_EQ(geometry.metadata_slot_count, 2); EXPECT_EQ(geometry.first_logical_sector, 12); EXPECT_EQ(geometry.last_logical_sector, 2035); static const size_t kMetadataSpace = (kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE; uint64_t space_at_end = kDiskSize - (geometry.last_logical_sector + 1) * LP_SECTOR_SIZE; EXPECT_GE(space_at_end, kMetadataSpace); EXPECT_GE(geometry.first_logical_sector * LP_SECTOR_SIZE, kMetadataSpace); // Verify header. const LpMetadataHeader& header = exported->header; EXPECT_EQ(header.magic, LP_METADATA_HEADER_MAGIC); EXPECT_EQ(header.major_version, LP_METADATA_MAJOR_VERSION); EXPECT_EQ(header.minor_version, LP_METADATA_MINOR_VERSION); ASSERT_EQ(exported->partitions.size(), 2); ASSERT_EQ(exported->extents.size(), 3); for (const auto& partition : exported->partitions) { Partition* original = builder->FindPartition(GetPartitionName(partition)); ASSERT_NE(original, nullptr); EXPECT_EQ(original->guid(), GetPartitionGuid(partition)); for (size_t i = 0; i < partition.num_extents; i++) { const auto& extent = exported->extents[partition.first_extent_index + i]; LinearExtent* original_extent = original->extents()[i]->AsLinearExtent(); EXPECT_EQ(extent.num_sectors, original_extent->num_sectors()); EXPECT_EQ(extent.target_type, LP_TARGET_TYPE_LINEAR); EXPECT_EQ(extent.target_data, original_extent->physical_sector()); } EXPECT_EQ(partition.attributes, original->attributes()); } } TEST(liblp, BuilderImport) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); 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); unique_ptr<LpMetadata> exported = builder->Export(); ASSERT_NE(exported, nullptr); builder = MetadataBuilder::New(*exported.get()); ASSERT_NE(builder, nullptr); system = builder->FindPartition("system"); ASSERT_NE(system, nullptr); vendor = builder->FindPartition("vendor"); ASSERT_NE(vendor, nullptr); EXPECT_EQ(system->size(), 98304); ASSERT_EQ(system->extents().size(), 2); EXPECT_EQ(system->guid(), TEST_GUID); EXPECT_EQ(system->attributes(), LP_PARTITION_ATTR_READONLY); EXPECT_EQ(vendor->size(), 32768); ASSERT_EQ(vendor->extents().size(), 1); EXPECT_EQ(vendor->guid(), TEST_GUID2); EXPECT_EQ(vendor->attributes(), LP_PARTITION_ATTR_READONLY); LinearExtent* system1 = system->extents()[0]->AsLinearExtent(); LinearExtent* system2 = system->extents()[1]->AsLinearExtent(); LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent(); EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE); EXPECT_EQ(system1->physical_sector(), 12); EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(system2->physical_sector(), 204); EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE); } TEST(liblp, ExportNameTooLong) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); std::string name = "abcdefghijklmnopqrstuvwxyz0123456789"; Partition* system = builder->AddPartition(name + name, TEST_GUID, LP_PARTITION_ATTR_READONLY); EXPECT_NE(system, nullptr); unique_ptr<LpMetadata> exported = builder->Export(); EXPECT_EQ(exported, nullptr); } TEST(liblp, ExportInvalidGuid) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); Partition* system = builder->AddPartition("system", "bad", LP_PARTITION_ATTR_READONLY); EXPECT_NE(system, nullptr); unique_ptr<LpMetadata> exported = builder->Export(); EXPECT_EQ(exported, nullptr); } fs_mgr/liblp/include/liblp/builder.h +3 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,9 @@ class MetadataBuilder { // underlying filesystem or contents of the partition on disk. void ShrinkPartition(Partition* partition, uint64_t requested_size); // Amount of space that can be allocated to logical partitions. uint64_t AllocatableSpace() const; private: MetadataBuilder(); bool Init(uint64_t blockdevice_size, uint32_t metadata_max_size, uint32_t metadata_slot_count); Loading fs_mgr/liblp/include/liblp/metadata_format.h +1 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ extern "C" { * READONLY - The partition should not be considered writable. When used with * device mapper, the block device will be created as read-only. */ #define LP_PARTITION_ATTR_NONE 0x0 #define LP_PARTITION_ATTR_READONLY 0x1 /* Mask that defines all valid attributes. */ Loading Loading
fs_mgr/liblp/Android.bp +16 −0 Original line number Diff line number Diff line Loading @@ -42,3 +42,19 @@ cc_library_static { ], export_include_dirs: ["include"], } cc_test { name: "liblp_test", defaults: ["fs_mgr_defaults"], static_libs: [ "libbase", "liblog", "libcrypto", "libcrypto_utils", "liblp", ], srcs: [ "builder_test.cpp", "utility_test.cpp", ], }
fs_mgr/liblp/builder.cpp +5 −1 Original line number Diff line number Diff line Loading @@ -287,7 +287,7 @@ bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t requested_siz DCHECK(first_sector <= geometry_.last_logical_sector); // Note: the last usable sector is inclusive. if (first_sector + sectors_needed > geometry_.last_logical_sector) { if (geometry_.last_logical_sector + 1 - first_sector < sectors_needed) { LERROR << "Not enough free space to expand partition: " << partition->name(); return false; } Loading Loading @@ -347,5 +347,9 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() { return metadata; } uint64_t MetadataBuilder::AllocatableSpace() const { return (geometry_.last_logical_sector - geometry_.first_logical_sector + 1) * LP_SECTOR_SIZE; } } // namespace fs_mgr } // namespace android
fs_mgr/liblp/builder_test.cpp 0 → 100644 +308 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <gtest/gtest.h> #include <liblp/builder.h> using namespace std; using namespace android::fs_mgr; static const char* TEST_GUID = "A799D1D6-669F-41D8-A3F0-EBB7572D8302"; static const char* TEST_GUID2 = "A799D1D6-669F-41D8-A3F0-EBB7572D8303"; TEST(liblp, BuildBasic) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); Partition* partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); ASSERT_NE(partition, nullptr); EXPECT_EQ(partition->name(), "system"); EXPECT_EQ(partition->guid(), TEST_GUID); EXPECT_EQ(partition->attributes(), LP_PARTITION_ATTR_READONLY); EXPECT_EQ(partition->size(), 0); EXPECT_EQ(builder->FindPartition("system"), partition); builder->RemovePartition("system"); EXPECT_EQ(builder->FindPartition("system"), nullptr); } TEST(liblp, ResizePartition) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); ASSERT_NE(system, nullptr); EXPECT_EQ(builder->GrowPartition(system, 65536), true); EXPECT_EQ(system->size(), 65536); ASSERT_EQ(system->extents().size(), 1); LinearExtent* extent = system->extents()[0]->AsLinearExtent(); ASSERT_NE(extent, nullptr); EXPECT_EQ(extent->num_sectors(), 65536 / LP_SECTOR_SIZE); // 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); 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); EXPECT_EQ(system->extents().size(), 1); EXPECT_EQ(system->extents()[0]->num_sectors(), 65536 / LP_SECTOR_SIZE); // Test shrinking within the same extent. builder->ShrinkPartition(system, 32768); EXPECT_EQ(system->size(), 32768); EXPECT_EQ(system->extents().size(), 1); extent = system->extents()[0]->AsLinearExtent(); ASSERT_NE(extent, nullptr); EXPECT_EQ(extent->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(extent->physical_sector(), 12); // Test shrinking to 0. builder->ShrinkPartition(system, 0); EXPECT_EQ(system->size(), 0); EXPECT_EQ(system->extents().size(), 0); } TEST(liblp, PartitionAlignment) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); // 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(system->size(), 10240); EXPECT_EQ(system->extents().size(), 1); builder->ShrinkPartition(system, 9000); EXPECT_EQ(system->size(), 9216); EXPECT_EQ(system->extents().size(), 1); } TEST(liblp, DiskAlignment) { static const uint64_t kDiskSize = 1000000; static const uint32_t kMetadataSize = 1024; static const uint32_t kMetadataSlots = 2; // If the disk size is not aligned to 512 bytes, make sure it still leaves // space at the end for backup metadata, and that it doesn't overlap with // the space for logical partitions. unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(kDiskSize, kMetadataSize, kMetadataSlots); unique_ptr<LpMetadata> exported = builder->Export(); ASSERT_NE(exported, nullptr); static const size_t kMetadataSpace = (kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE; uint64_t space_at_end = kDiskSize - (exported->geometry.last_logical_sector + 1) * LP_SECTOR_SIZE; EXPECT_GE(space_at_end, kMetadataSpace); } TEST(liblp, MetadataAlignment) { // Make sure metadata sizes get aligned up. unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1000, 2); unique_ptr<LpMetadata> exported = builder->Export(); ASSERT_NE(exported, nullptr); EXPECT_EQ(exported->geometry.metadata_max_size, 1024); } TEST(liblp, UseAllDiskSpace) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); EXPECT_EQ(builder->AllocatableSpace(), 1036288); Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); ASSERT_NE(system, nullptr); EXPECT_EQ(builder->GrowPartition(system, 1036288), true); EXPECT_EQ(system->size(), 1036288); EXPECT_EQ(builder->GrowPartition(system, 1036289), false); } TEST(liblp, BuildComplex) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); 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(system->size(), 98304); EXPECT_EQ(vendor->size(), 32768); // We now expect to have 3 extents total: 2 for system, 1 for vendor, since // our allocation strategy is greedy/first-fit. ASSERT_EQ(system->extents().size(), 2); ASSERT_EQ(vendor->extents().size(), 1); LinearExtent* system1 = system->extents()[0]->AsLinearExtent(); LinearExtent* system2 = system->extents()[1]->AsLinearExtent(); LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent(); ASSERT_NE(system1, nullptr); ASSERT_NE(system2, nullptr); ASSERT_NE(vendor1, nullptr); EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE); EXPECT_EQ(system1->physical_sector(), 12); EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(system2->physical_sector(), 204); EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(vendor1->physical_sector(), 140); EXPECT_EQ(system1->physical_sector() + system1->num_sectors(), vendor1->physical_sector()); EXPECT_EQ(vendor1->physical_sector() + vendor1->num_sectors(), system2->physical_sector()); } TEST(liblp, AddInvalidPartition) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); Partition* partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); ASSERT_NE(partition, nullptr); // Duplicate name. partition = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); EXPECT_EQ(partition, nullptr); // Empty name. partition = builder->AddPartition("", TEST_GUID, LP_PARTITION_ATTR_READONLY); EXPECT_EQ(partition, nullptr); } TEST(liblp, BuilderExport) { static const uint64_t kDiskSize = 1024 * 1024; static const uint32_t kMetadataSize = 1024; static const uint32_t kMetadataSlots = 2; unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(kDiskSize, kMetadataSize, kMetadataSlots); Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); 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); unique_ptr<LpMetadata> exported = builder->Export(); EXPECT_NE(exported, nullptr); // Verify geometry. Some details of this may change if we change the // metadata structures. So in addition to checking the exact values, we // also check that they are internally consistent after. const LpMetadataGeometry& geometry = exported->geometry; EXPECT_EQ(geometry.magic, LP_METADATA_GEOMETRY_MAGIC); EXPECT_EQ(geometry.struct_size, sizeof(geometry)); EXPECT_EQ(geometry.metadata_max_size, 1024); EXPECT_EQ(geometry.metadata_slot_count, 2); EXPECT_EQ(geometry.first_logical_sector, 12); EXPECT_EQ(geometry.last_logical_sector, 2035); static const size_t kMetadataSpace = (kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE; uint64_t space_at_end = kDiskSize - (geometry.last_logical_sector + 1) * LP_SECTOR_SIZE; EXPECT_GE(space_at_end, kMetadataSpace); EXPECT_GE(geometry.first_logical_sector * LP_SECTOR_SIZE, kMetadataSpace); // Verify header. const LpMetadataHeader& header = exported->header; EXPECT_EQ(header.magic, LP_METADATA_HEADER_MAGIC); EXPECT_EQ(header.major_version, LP_METADATA_MAJOR_VERSION); EXPECT_EQ(header.minor_version, LP_METADATA_MINOR_VERSION); ASSERT_EQ(exported->partitions.size(), 2); ASSERT_EQ(exported->extents.size(), 3); for (const auto& partition : exported->partitions) { Partition* original = builder->FindPartition(GetPartitionName(partition)); ASSERT_NE(original, nullptr); EXPECT_EQ(original->guid(), GetPartitionGuid(partition)); for (size_t i = 0; i < partition.num_extents; i++) { const auto& extent = exported->extents[partition.first_extent_index + i]; LinearExtent* original_extent = original->extents()[i]->AsLinearExtent(); EXPECT_EQ(extent.num_sectors, original_extent->num_sectors()); EXPECT_EQ(extent.target_type, LP_TARGET_TYPE_LINEAR); EXPECT_EQ(extent.target_data, original_extent->physical_sector()); } EXPECT_EQ(partition.attributes, original->attributes()); } } TEST(liblp, BuilderImport) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); 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); unique_ptr<LpMetadata> exported = builder->Export(); ASSERT_NE(exported, nullptr); builder = MetadataBuilder::New(*exported.get()); ASSERT_NE(builder, nullptr); system = builder->FindPartition("system"); ASSERT_NE(system, nullptr); vendor = builder->FindPartition("vendor"); ASSERT_NE(vendor, nullptr); EXPECT_EQ(system->size(), 98304); ASSERT_EQ(system->extents().size(), 2); EXPECT_EQ(system->guid(), TEST_GUID); EXPECT_EQ(system->attributes(), LP_PARTITION_ATTR_READONLY); EXPECT_EQ(vendor->size(), 32768); ASSERT_EQ(vendor->extents().size(), 1); EXPECT_EQ(vendor->guid(), TEST_GUID2); EXPECT_EQ(vendor->attributes(), LP_PARTITION_ATTR_READONLY); LinearExtent* system1 = system->extents()[0]->AsLinearExtent(); LinearExtent* system2 = system->extents()[1]->AsLinearExtent(); LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent(); EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE); EXPECT_EQ(system1->physical_sector(), 12); EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(system2->physical_sector(), 204); EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE); } TEST(liblp, ExportNameTooLong) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); std::string name = "abcdefghijklmnopqrstuvwxyz0123456789"; Partition* system = builder->AddPartition(name + name, TEST_GUID, LP_PARTITION_ATTR_READONLY); EXPECT_NE(system, nullptr); unique_ptr<LpMetadata> exported = builder->Export(); EXPECT_EQ(exported, nullptr); } TEST(liblp, ExportInvalidGuid) { unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2); Partition* system = builder->AddPartition("system", "bad", LP_PARTITION_ATTR_READONLY); EXPECT_NE(system, nullptr); unique_ptr<LpMetadata> exported = builder->Export(); EXPECT_EQ(exported, nullptr); }
fs_mgr/liblp/include/liblp/builder.h +3 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,9 @@ class MetadataBuilder { // underlying filesystem or contents of the partition on disk. void ShrinkPartition(Partition* partition, uint64_t requested_size); // Amount of space that can be allocated to logical partitions. uint64_t AllocatableSpace() const; private: MetadataBuilder(); bool Init(uint64_t blockdevice_size, uint32_t metadata_max_size, uint32_t metadata_slot_count); Loading
fs_mgr/liblp/include/liblp/metadata_format.h +1 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ extern "C" { * READONLY - The partition should not be considered writable. When used with * device mapper, the block device will be created as read-only. */ #define LP_PARTITION_ATTR_NONE 0x0 #define LP_PARTITION_ATTR_READONLY 0x1 /* Mask that defines all valid attributes. */ Loading