Loading fs_mgr/fs_mgr_dm_linear.cpp +37 −11 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ #include <sstream> #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> Loading @@ -50,8 +51,21 @@ using DmTarget = android::dm::DmTarget; using DmTargetZero = android::dm::DmTargetZero; using DmTargetLinear = android::dm::DmTargetLinear; static bool CreateDmTable(const std::string& block_device, const LpMetadata& metadata, const LpMetadataPartition& partition, DmTable* table) { bool GetPhysicalPartitionDevicePath(const LpMetadataBlockDevice& block_device, std::string* result) { // Note: device-mapper will not accept symlinks, so we must use realpath // here. std::string name = GetBlockDevicePartitionName(block_device); std::string path = "/dev/block/by-name/" + name; if (!android::base::Realpath(path, result)) { PERROR << "realpath: " << path; return false; } return true; } static bool CreateDmTable(const LpMetadata& metadata, const LpMetadataPartition& partition, DmTable* table) { uint64_t sector = 0; for (size_t i = 0; i < partition.num_extents; i++) { const auto& extent = metadata.extents[partition.first_extent_index + i]; Loading @@ -60,10 +74,22 @@ static bool CreateDmTable(const std::string& block_device, const LpMetadata& met case LP_TARGET_TYPE_ZERO: target = std::make_unique<DmTargetZero>(sector, extent.num_sectors); break; case LP_TARGET_TYPE_LINEAR: target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, block_device, case LP_TARGET_TYPE_LINEAR: { auto block_device = GetMetadataSuperBlockDevice(metadata); if (!block_device) { LOG(ERROR) << "Could not identify the super block device"; return false; } std::string path; if (!GetPhysicalPartitionDevicePath(*block_device, &path)) { LOG(ERROR) << "Unable to complete device-mapper table, unknown block device"; return false; } target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, path, extent.target_data); break; } default: LOG(ERROR) << "Unknown target type in metadata: " << extent.target_type; return false; Loading @@ -79,13 +105,13 @@ static bool CreateDmTable(const std::string& block_device, const LpMetadata& met return true; } static bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata, const LpMetadataPartition& partition, bool force_writable, const std::chrono::milliseconds& timeout_ms, std::string* path) { static bool CreateLogicalPartition(const LpMetadata& metadata, const LpMetadataPartition& partition, bool force_writable, const std::chrono::milliseconds& timeout_ms, std::string* path) { DeviceMapper& dm = DeviceMapper::Instance(); DmTable table; if (!CreateDmTable(block_device, metadata, partition, &table)) { if (!CreateDmTable(metadata, partition, &table)) { return false; } if (force_writable) { Loading Loading @@ -122,7 +148,7 @@ bool CreateLogicalPartitions(const std::string& block_device) { continue; } std::string path; if (!CreateLogicalPartition(block_device, *metadata.get(), partition, false, {}, &path)) { if (!CreateLogicalPartition(*metadata.get(), partition, false, {}, &path)) { LERROR << "Could not create logical partition: " << GetPartitionName(partition); return false; } Loading @@ -140,8 +166,8 @@ bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_s } for (const auto& partition : metadata->partitions) { if (GetPartitionName(partition) == partition_name) { return CreateLogicalPartition(block_device, *metadata.get(), partition, force_writable, timeout_ms, path); return CreateLogicalPartition(*metadata.get(), partition, force_writable, timeout_ms, path); } } LERROR << "Could not find any partition with name: " << partition_name; Loading fs_mgr/liblp/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ cc_library { srcs: [ "builder.cpp", "images.cpp", "partition_opener.cpp", "reader.cpp", "utility.cpp", "writer.cpp", Loading Loading @@ -59,6 +60,7 @@ cc_test { srcs: [ "builder_test.cpp", "io_test.cpp", "test_partition_opener.cpp", "utility_test.cpp", ], } fs_mgr/liblp/builder.cpp +40 −63 Original line number Diff line number Diff line Loading @@ -16,11 +16,7 @@ #include "liblp/builder.h" #if defined(__linux__) #include <linux/fs.h> #endif #include <string.h> #include <sys/ioctl.h> #include <algorithm> Loading @@ -33,43 +29,6 @@ namespace android { namespace fs_mgr { bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) { #if defined(__linux__) android::base::unique_fd fd(open(block_device.c_str(), O_RDONLY)); if (fd < 0) { PERROR << __PRETTY_FUNCTION__ << "open '" << block_device << "' failed"; return false; } if (!GetDescriptorSize(fd, &device_info->size)) { return false; } if (ioctl(fd, BLKIOMIN, &device_info->alignment) < 0) { PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed"; return false; } int alignment_offset; if (ioctl(fd, BLKALIGNOFF, &alignment_offset) < 0) { PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed"; return false; } int logical_block_size; if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0) { PERROR << __PRETTY_FUNCTION__ << "BLKSSZGET failed"; return false; } device_info->alignment_offset = static_cast<uint32_t>(alignment_offset); device_info->logical_block_size = static_cast<uint32_t>(logical_block_size); return true; #else (void)block_device; (void)device_info; LERROR << __PRETTY_FUNCTION__ << ": Not supported on this operating system."; return false; #endif } void LinearExtent::AddTo(LpMetadata* out) const { out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_LINEAR, physical_sector_}); } Loading Loading @@ -138,9 +97,10 @@ uint64_t Partition::BytesOnDisk() const { return sectors * LP_SECTOR_SIZE; } std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_device, std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const IPartitionOpener& opener, const std::string& super_partition, uint32_t slot_number) { std::unique_ptr<LpMetadata> metadata = ReadMetadata(block_device.c_str(), slot_number); std::unique_ptr<LpMetadata> metadata = ReadMetadata(opener, super_partition, slot_number); if (!metadata) { return nullptr; } Loading @@ -149,12 +109,17 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_d return nullptr; } BlockDeviceInfo device_info; if (fs_mgr::GetBlockDeviceInfo(block_device, &device_info)) { if (opener.GetInfo(super_partition, &device_info)) { builder->UpdateBlockDeviceInfo(device_info); } return builder; } std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_partition, uint32_t slot_number) { return New(PartitionOpener(), super_partition, slot_number); } std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const BlockDeviceInfo& device_info, uint32_t metadata_max_size, uint32_t metadata_slot_count) { Loading Loading @@ -186,6 +151,7 @@ MetadataBuilder::MetadataBuilder() { header_.partitions.entry_size = sizeof(LpMetadataPartition); header_.extents.entry_size = sizeof(LpMetadataExtent); header_.groups.entry_size = sizeof(LpMetadataPartitionGroup); header_.block_devices.entry_size = sizeof(LpMetadataBlockDevice); } bool MetadataBuilder::Init(const LpMetadata& metadata) { Loading @@ -198,6 +164,10 @@ bool MetadataBuilder::Init(const LpMetadata& metadata) { } } for (const auto& block_device : metadata.block_devices) { block_devices_.push_back(block_device); } for (const auto& partition : metadata.partitions) { std::string group_name = GetPartitionGroupName(metadata.groups[partition.group_index]); Partition* builder = Loading Loading @@ -259,9 +229,7 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata // We reserve a geometry block (4KB) plus space for each copy of the // maximum size of a metadata blob. Then, we double that space since // we store a backup copy of everything. uint64_t reserved = LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count); uint64_t total_reserved = LP_PARTITION_RESERVED_BYTES + reserved * 2; uint64_t total_reserved = GetTotalMetadataSize(metadata_max_size, metadata_slot_count); if (device_info.size < total_reserved) { LERROR << "Attempting to create metadata on a block device that is too small."; return false; Loading @@ -285,12 +253,16 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata return false; } geometry_.first_logical_sector = first_sector; block_devices_.push_back(LpMetadataBlockDevice{ first_sector, device_info.alignment, device_info.alignment_offset, device_info.size, "super", }); geometry_.metadata_max_size = metadata_max_size; geometry_.metadata_slot_count = metadata_slot_count; geometry_.alignment = device_info.alignment; geometry_.alignment_offset = device_info.alignment_offset; geometry_.block_device_size = device_info.size; geometry_.logical_block_size = device_info.logical_block_size; if (!AddGroup("default", 0)) { Loading Loading @@ -408,9 +380,10 @@ auto MetadataBuilder::GetFreeRegions() const -> std::vector<Interval> { } // Add 0-length intervals for the first and last sectors. This will cause // ExtentsToFreeList() to treat the space in between as available. uint64_t last_sector = geometry_.block_device_size / LP_SECTOR_SIZE; extents.emplace_back(geometry_.first_logical_sector, geometry_.first_logical_sector); // ExtentToFreeList() to treat the space in between as available. uint64_t first_sector = super_device().first_logical_sector; uint64_t last_sector = super_device().size / LP_SECTOR_SIZE; extents.emplace_back(first_sector, first_sector); extents.emplace_back(last_sector, last_sector); std::sort(extents.begin(), extents.end()); Loading Loading @@ -547,14 +520,18 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() { metadata->partitions.push_back(part); } metadata->block_devices = block_devices_; metadata->header.partitions.num_entries = static_cast<uint32_t>(metadata->partitions.size()); metadata->header.extents.num_entries = static_cast<uint32_t>(metadata->extents.size()); metadata->header.groups.num_entries = static_cast<uint32_t>(metadata->groups.size()); metadata->header.block_devices.num_entries = static_cast<uint32_t>(metadata->block_devices.size()); return metadata; } uint64_t MetadataBuilder::AllocatableSpace() const { return geometry_.block_device_size - (geometry_.first_logical_sector * LP_SECTOR_SIZE); return super_device().size - (super_device().first_logical_sector * LP_SECTOR_SIZE); } uint64_t MetadataBuilder::UsedSpace() const { Loading @@ -569,22 +546,22 @@ uint64_t MetadataBuilder::AlignSector(uint64_t sector) const { // Note: when reading alignment info from the Kernel, we don't assume it // is aligned to the sector size, so we round up to the nearest sector. uint64_t lba = sector * LP_SECTOR_SIZE; uint64_t aligned = AlignTo(lba, geometry_.alignment, geometry_.alignment_offset); uint64_t aligned = AlignTo(lba, super_device().alignment, super_device().alignment_offset); return AlignTo(aligned, LP_SECTOR_SIZE) / LP_SECTOR_SIZE; } bool MetadataBuilder::GetBlockDeviceInfo(BlockDeviceInfo* info) const { info->size = geometry_.block_device_size; info->alignment = geometry_.alignment; info->alignment_offset = geometry_.alignment_offset; info->size = super_device().size; info->alignment = super_device().alignment; info->alignment_offset = super_device().alignment_offset; info->logical_block_size = geometry_.logical_block_size; return true; } bool MetadataBuilder::UpdateBlockDeviceInfo(const BlockDeviceInfo& device_info) { if (device_info.size != geometry_.block_device_size) { if (device_info.size != super_device().size) { LERROR << "Device size does not match (got " << device_info.size << ", expected " << geometry_.block_device_size << ")"; << super_device().size << ")"; return false; } if (device_info.logical_block_size != geometry_.logical_block_size) { Loading @@ -596,10 +573,10 @@ bool MetadataBuilder::UpdateBlockDeviceInfo(const BlockDeviceInfo& device_info) // The kernel does not guarantee these values are present, so we only // replace existing values if the new values are non-zero. if (device_info.alignment) { geometry_.alignment = device_info.alignment; super_device().alignment = device_info.alignment; } if (device_info.alignment_offset) { geometry_.alignment_offset = device_info.alignment_offset; super_device().alignment_offset = device_info.alignment_offset; } return true; } Loading fs_mgr/liblp/builder_test.cpp +19 −11 Original line number Diff line number Diff line Loading @@ -132,7 +132,9 @@ TEST(liblp, InternalAlignment) { ASSERT_NE(builder, nullptr); unique_ptr<LpMetadata> exported = builder->Export(); ASSERT_NE(exported, nullptr); EXPECT_EQ(exported->geometry.first_logical_sector, 1536); auto super_device = GetMetadataSuperBlockDevice(*exported.get()); ASSERT_NE(super_device, nullptr); EXPECT_EQ(super_device->first_logical_sector, 1536); // Test a large alignment offset thrown in. device_info.alignment_offset = 753664; Loading @@ -140,7 +142,9 @@ TEST(liblp, InternalAlignment) { ASSERT_NE(builder, nullptr); exported = builder->Export(); ASSERT_NE(exported, nullptr); EXPECT_EQ(exported->geometry.first_logical_sector, 1472); super_device = GetMetadataSuperBlockDevice(*exported.get()); ASSERT_NE(super_device, nullptr); EXPECT_EQ(super_device->first_logical_sector, 1472); // Alignment offset without alignment doesn't mean anything. device_info.alignment = 0; Loading @@ -154,7 +158,9 @@ TEST(liblp, InternalAlignment) { ASSERT_NE(builder, nullptr); exported = builder->Export(); ASSERT_NE(exported, nullptr); EXPECT_EQ(exported->geometry.first_logical_sector, 174); super_device = GetMetadataSuperBlockDevice(*exported.get()); ASSERT_NE(super_device, nullptr); EXPECT_EQ(super_device->first_logical_sector, 174); // Test a small alignment with no alignment offset. device_info.alignment = 11 * 1024; Loading @@ -162,7 +168,9 @@ TEST(liblp, InternalAlignment) { ASSERT_NE(builder, nullptr); exported = builder->Export(); ASSERT_NE(exported, nullptr); EXPECT_EQ(exported->geometry.first_logical_sector, 160); super_device = GetMetadataSuperBlockDevice(*exported.get()); ASSERT_NE(super_device, nullptr); EXPECT_EQ(super_device->first_logical_sector, 160); } TEST(liblp, InternalPartitionAlignment) { Loading Loading @@ -292,6 +300,9 @@ TEST(liblp, BuilderExport) { unique_ptr<LpMetadata> exported = builder->Export(); EXPECT_NE(exported, nullptr); auto super_device = GetMetadataSuperBlockDevice(*exported.get()); ASSERT_NE(super_device, 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. Loading @@ -300,11 +311,11 @@ TEST(liblp, BuilderExport) { 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, 32); EXPECT_EQ(super_device->first_logical_sector, 32); static const size_t kMetadataSpace = ((kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE) * 2; EXPECT_GE(geometry.first_logical_sector * LP_SECTOR_SIZE, kMetadataSpace); EXPECT_GE(super_device->first_logical_sector * LP_SECTOR_SIZE, kMetadataSpace); // Verify header. const LpMetadataHeader& header = exported->header; Loading Loading @@ -413,13 +424,10 @@ TEST(liblp, block_device_info) { fs_mgr_free_fstab); ASSERT_NE(fstab, nullptr); // This should read from the "super" partition once we have a well-defined // way to access it. struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), "/data"); ASSERT_NE(rec, nullptr); PartitionOpener opener; BlockDeviceInfo device_info; ASSERT_TRUE(GetBlockDeviceInfo(rec->blk_device, &device_info)); ASSERT_TRUE(opener.GetInfo(fs_mgr_get_super_partition_name(), &device_info)); // Sanity check that the device doesn't give us some weird inefficient // alignment. Loading fs_mgr/liblp/images.cpp +8 −11 Original line number Diff line number Diff line Loading @@ -99,11 +99,12 @@ SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size, block_size_(block_size), file_(nullptr, sparse_file_destroy), images_(images) { uint64_t total_size = GetTotalSuperPartitionSize(metadata); if (block_size % LP_SECTOR_SIZE != 0) { LERROR << "Block size must be a multiple of the sector size, " << LP_SECTOR_SIZE; return; } if (metadata.geometry.block_device_size % block_size != 0) { if (total_size % block_size != 0) { LERROR << "Device size must be a multiple of the block size, " << block_size; return; } Loading @@ -120,7 +121,7 @@ SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size, return; } uint64_t num_blocks = metadata.geometry.block_device_size % block_size; uint64_t num_blocks = total_size % block_size; if (num_blocks >= UINT_MAX) { // libsparse counts blocks in unsigned 32-bit integers, so we check to // make sure we're not going to overflow. Loading @@ -128,7 +129,10 @@ SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size, return; } file_.reset(sparse_file_new(block_size_, geometry_.block_device_size)); file_.reset(sparse_file_new(block_size_, total_size)); if (!file_) { LERROR << "Could not allocate sparse file of size " << total_size; } } bool SparseBuilder::Export(const char* file) { Loading Loading @@ -333,14 +337,7 @@ int SparseBuilder::OpenImageFile(const std::string& file) { bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size, const std::map<std::string, std::string>& images) { SparseBuilder builder(metadata, block_size, images); if (!builder.IsValid()) { LERROR << "Could not allocate sparse file of size " << metadata.geometry.block_device_size; return false; } if (!builder.Build()) { return false; } return builder.Export(file); return builder.IsValid() && builder.Build() && builder.Export(file); } } // namespace fs_mgr Loading Loading
fs_mgr/fs_mgr_dm_linear.cpp +37 −11 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ #include <sstream> #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> Loading @@ -50,8 +51,21 @@ using DmTarget = android::dm::DmTarget; using DmTargetZero = android::dm::DmTargetZero; using DmTargetLinear = android::dm::DmTargetLinear; static bool CreateDmTable(const std::string& block_device, const LpMetadata& metadata, const LpMetadataPartition& partition, DmTable* table) { bool GetPhysicalPartitionDevicePath(const LpMetadataBlockDevice& block_device, std::string* result) { // Note: device-mapper will not accept symlinks, so we must use realpath // here. std::string name = GetBlockDevicePartitionName(block_device); std::string path = "/dev/block/by-name/" + name; if (!android::base::Realpath(path, result)) { PERROR << "realpath: " << path; return false; } return true; } static bool CreateDmTable(const LpMetadata& metadata, const LpMetadataPartition& partition, DmTable* table) { uint64_t sector = 0; for (size_t i = 0; i < partition.num_extents; i++) { const auto& extent = metadata.extents[partition.first_extent_index + i]; Loading @@ -60,10 +74,22 @@ static bool CreateDmTable(const std::string& block_device, const LpMetadata& met case LP_TARGET_TYPE_ZERO: target = std::make_unique<DmTargetZero>(sector, extent.num_sectors); break; case LP_TARGET_TYPE_LINEAR: target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, block_device, case LP_TARGET_TYPE_LINEAR: { auto block_device = GetMetadataSuperBlockDevice(metadata); if (!block_device) { LOG(ERROR) << "Could not identify the super block device"; return false; } std::string path; if (!GetPhysicalPartitionDevicePath(*block_device, &path)) { LOG(ERROR) << "Unable to complete device-mapper table, unknown block device"; return false; } target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, path, extent.target_data); break; } default: LOG(ERROR) << "Unknown target type in metadata: " << extent.target_type; return false; Loading @@ -79,13 +105,13 @@ static bool CreateDmTable(const std::string& block_device, const LpMetadata& met return true; } static bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata, const LpMetadataPartition& partition, bool force_writable, const std::chrono::milliseconds& timeout_ms, std::string* path) { static bool CreateLogicalPartition(const LpMetadata& metadata, const LpMetadataPartition& partition, bool force_writable, const std::chrono::milliseconds& timeout_ms, std::string* path) { DeviceMapper& dm = DeviceMapper::Instance(); DmTable table; if (!CreateDmTable(block_device, metadata, partition, &table)) { if (!CreateDmTable(metadata, partition, &table)) { return false; } if (force_writable) { Loading Loading @@ -122,7 +148,7 @@ bool CreateLogicalPartitions(const std::string& block_device) { continue; } std::string path; if (!CreateLogicalPartition(block_device, *metadata.get(), partition, false, {}, &path)) { if (!CreateLogicalPartition(*metadata.get(), partition, false, {}, &path)) { LERROR << "Could not create logical partition: " << GetPartitionName(partition); return false; } Loading @@ -140,8 +166,8 @@ bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_s } for (const auto& partition : metadata->partitions) { if (GetPartitionName(partition) == partition_name) { return CreateLogicalPartition(block_device, *metadata.get(), partition, force_writable, timeout_ms, path); return CreateLogicalPartition(*metadata.get(), partition, force_writable, timeout_ms, path); } } LERROR << "Could not find any partition with name: " << partition_name; Loading
fs_mgr/liblp/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ cc_library { srcs: [ "builder.cpp", "images.cpp", "partition_opener.cpp", "reader.cpp", "utility.cpp", "writer.cpp", Loading Loading @@ -59,6 +60,7 @@ cc_test { srcs: [ "builder_test.cpp", "io_test.cpp", "test_partition_opener.cpp", "utility_test.cpp", ], }
fs_mgr/liblp/builder.cpp +40 −63 Original line number Diff line number Diff line Loading @@ -16,11 +16,7 @@ #include "liblp/builder.h" #if defined(__linux__) #include <linux/fs.h> #endif #include <string.h> #include <sys/ioctl.h> #include <algorithm> Loading @@ -33,43 +29,6 @@ namespace android { namespace fs_mgr { bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) { #if defined(__linux__) android::base::unique_fd fd(open(block_device.c_str(), O_RDONLY)); if (fd < 0) { PERROR << __PRETTY_FUNCTION__ << "open '" << block_device << "' failed"; return false; } if (!GetDescriptorSize(fd, &device_info->size)) { return false; } if (ioctl(fd, BLKIOMIN, &device_info->alignment) < 0) { PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed"; return false; } int alignment_offset; if (ioctl(fd, BLKALIGNOFF, &alignment_offset) < 0) { PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed"; return false; } int logical_block_size; if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0) { PERROR << __PRETTY_FUNCTION__ << "BLKSSZGET failed"; return false; } device_info->alignment_offset = static_cast<uint32_t>(alignment_offset); device_info->logical_block_size = static_cast<uint32_t>(logical_block_size); return true; #else (void)block_device; (void)device_info; LERROR << __PRETTY_FUNCTION__ << ": Not supported on this operating system."; return false; #endif } void LinearExtent::AddTo(LpMetadata* out) const { out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_LINEAR, physical_sector_}); } Loading Loading @@ -138,9 +97,10 @@ uint64_t Partition::BytesOnDisk() const { return sectors * LP_SECTOR_SIZE; } std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_device, std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const IPartitionOpener& opener, const std::string& super_partition, uint32_t slot_number) { std::unique_ptr<LpMetadata> metadata = ReadMetadata(block_device.c_str(), slot_number); std::unique_ptr<LpMetadata> metadata = ReadMetadata(opener, super_partition, slot_number); if (!metadata) { return nullptr; } Loading @@ -149,12 +109,17 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_d return nullptr; } BlockDeviceInfo device_info; if (fs_mgr::GetBlockDeviceInfo(block_device, &device_info)) { if (opener.GetInfo(super_partition, &device_info)) { builder->UpdateBlockDeviceInfo(device_info); } return builder; } std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_partition, uint32_t slot_number) { return New(PartitionOpener(), super_partition, slot_number); } std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const BlockDeviceInfo& device_info, uint32_t metadata_max_size, uint32_t metadata_slot_count) { Loading Loading @@ -186,6 +151,7 @@ MetadataBuilder::MetadataBuilder() { header_.partitions.entry_size = sizeof(LpMetadataPartition); header_.extents.entry_size = sizeof(LpMetadataExtent); header_.groups.entry_size = sizeof(LpMetadataPartitionGroup); header_.block_devices.entry_size = sizeof(LpMetadataBlockDevice); } bool MetadataBuilder::Init(const LpMetadata& metadata) { Loading @@ -198,6 +164,10 @@ bool MetadataBuilder::Init(const LpMetadata& metadata) { } } for (const auto& block_device : metadata.block_devices) { block_devices_.push_back(block_device); } for (const auto& partition : metadata.partitions) { std::string group_name = GetPartitionGroupName(metadata.groups[partition.group_index]); Partition* builder = Loading Loading @@ -259,9 +229,7 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata // We reserve a geometry block (4KB) plus space for each copy of the // maximum size of a metadata blob. Then, we double that space since // we store a backup copy of everything. uint64_t reserved = LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count); uint64_t total_reserved = LP_PARTITION_RESERVED_BYTES + reserved * 2; uint64_t total_reserved = GetTotalMetadataSize(metadata_max_size, metadata_slot_count); if (device_info.size < total_reserved) { LERROR << "Attempting to create metadata on a block device that is too small."; return false; Loading @@ -285,12 +253,16 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata return false; } geometry_.first_logical_sector = first_sector; block_devices_.push_back(LpMetadataBlockDevice{ first_sector, device_info.alignment, device_info.alignment_offset, device_info.size, "super", }); geometry_.metadata_max_size = metadata_max_size; geometry_.metadata_slot_count = metadata_slot_count; geometry_.alignment = device_info.alignment; geometry_.alignment_offset = device_info.alignment_offset; geometry_.block_device_size = device_info.size; geometry_.logical_block_size = device_info.logical_block_size; if (!AddGroup("default", 0)) { Loading Loading @@ -408,9 +380,10 @@ auto MetadataBuilder::GetFreeRegions() const -> std::vector<Interval> { } // Add 0-length intervals for the first and last sectors. This will cause // ExtentsToFreeList() to treat the space in between as available. uint64_t last_sector = geometry_.block_device_size / LP_SECTOR_SIZE; extents.emplace_back(geometry_.first_logical_sector, geometry_.first_logical_sector); // ExtentToFreeList() to treat the space in between as available. uint64_t first_sector = super_device().first_logical_sector; uint64_t last_sector = super_device().size / LP_SECTOR_SIZE; extents.emplace_back(first_sector, first_sector); extents.emplace_back(last_sector, last_sector); std::sort(extents.begin(), extents.end()); Loading Loading @@ -547,14 +520,18 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() { metadata->partitions.push_back(part); } metadata->block_devices = block_devices_; metadata->header.partitions.num_entries = static_cast<uint32_t>(metadata->partitions.size()); metadata->header.extents.num_entries = static_cast<uint32_t>(metadata->extents.size()); metadata->header.groups.num_entries = static_cast<uint32_t>(metadata->groups.size()); metadata->header.block_devices.num_entries = static_cast<uint32_t>(metadata->block_devices.size()); return metadata; } uint64_t MetadataBuilder::AllocatableSpace() const { return geometry_.block_device_size - (geometry_.first_logical_sector * LP_SECTOR_SIZE); return super_device().size - (super_device().first_logical_sector * LP_SECTOR_SIZE); } uint64_t MetadataBuilder::UsedSpace() const { Loading @@ -569,22 +546,22 @@ uint64_t MetadataBuilder::AlignSector(uint64_t sector) const { // Note: when reading alignment info from the Kernel, we don't assume it // is aligned to the sector size, so we round up to the nearest sector. uint64_t lba = sector * LP_SECTOR_SIZE; uint64_t aligned = AlignTo(lba, geometry_.alignment, geometry_.alignment_offset); uint64_t aligned = AlignTo(lba, super_device().alignment, super_device().alignment_offset); return AlignTo(aligned, LP_SECTOR_SIZE) / LP_SECTOR_SIZE; } bool MetadataBuilder::GetBlockDeviceInfo(BlockDeviceInfo* info) const { info->size = geometry_.block_device_size; info->alignment = geometry_.alignment; info->alignment_offset = geometry_.alignment_offset; info->size = super_device().size; info->alignment = super_device().alignment; info->alignment_offset = super_device().alignment_offset; info->logical_block_size = geometry_.logical_block_size; return true; } bool MetadataBuilder::UpdateBlockDeviceInfo(const BlockDeviceInfo& device_info) { if (device_info.size != geometry_.block_device_size) { if (device_info.size != super_device().size) { LERROR << "Device size does not match (got " << device_info.size << ", expected " << geometry_.block_device_size << ")"; << super_device().size << ")"; return false; } if (device_info.logical_block_size != geometry_.logical_block_size) { Loading @@ -596,10 +573,10 @@ bool MetadataBuilder::UpdateBlockDeviceInfo(const BlockDeviceInfo& device_info) // The kernel does not guarantee these values are present, so we only // replace existing values if the new values are non-zero. if (device_info.alignment) { geometry_.alignment = device_info.alignment; super_device().alignment = device_info.alignment; } if (device_info.alignment_offset) { geometry_.alignment_offset = device_info.alignment_offset; super_device().alignment_offset = device_info.alignment_offset; } return true; } Loading
fs_mgr/liblp/builder_test.cpp +19 −11 Original line number Diff line number Diff line Loading @@ -132,7 +132,9 @@ TEST(liblp, InternalAlignment) { ASSERT_NE(builder, nullptr); unique_ptr<LpMetadata> exported = builder->Export(); ASSERT_NE(exported, nullptr); EXPECT_EQ(exported->geometry.first_logical_sector, 1536); auto super_device = GetMetadataSuperBlockDevice(*exported.get()); ASSERT_NE(super_device, nullptr); EXPECT_EQ(super_device->first_logical_sector, 1536); // Test a large alignment offset thrown in. device_info.alignment_offset = 753664; Loading @@ -140,7 +142,9 @@ TEST(liblp, InternalAlignment) { ASSERT_NE(builder, nullptr); exported = builder->Export(); ASSERT_NE(exported, nullptr); EXPECT_EQ(exported->geometry.first_logical_sector, 1472); super_device = GetMetadataSuperBlockDevice(*exported.get()); ASSERT_NE(super_device, nullptr); EXPECT_EQ(super_device->first_logical_sector, 1472); // Alignment offset without alignment doesn't mean anything. device_info.alignment = 0; Loading @@ -154,7 +158,9 @@ TEST(liblp, InternalAlignment) { ASSERT_NE(builder, nullptr); exported = builder->Export(); ASSERT_NE(exported, nullptr); EXPECT_EQ(exported->geometry.first_logical_sector, 174); super_device = GetMetadataSuperBlockDevice(*exported.get()); ASSERT_NE(super_device, nullptr); EXPECT_EQ(super_device->first_logical_sector, 174); // Test a small alignment with no alignment offset. device_info.alignment = 11 * 1024; Loading @@ -162,7 +168,9 @@ TEST(liblp, InternalAlignment) { ASSERT_NE(builder, nullptr); exported = builder->Export(); ASSERT_NE(exported, nullptr); EXPECT_EQ(exported->geometry.first_logical_sector, 160); super_device = GetMetadataSuperBlockDevice(*exported.get()); ASSERT_NE(super_device, nullptr); EXPECT_EQ(super_device->first_logical_sector, 160); } TEST(liblp, InternalPartitionAlignment) { Loading Loading @@ -292,6 +300,9 @@ TEST(liblp, BuilderExport) { unique_ptr<LpMetadata> exported = builder->Export(); EXPECT_NE(exported, nullptr); auto super_device = GetMetadataSuperBlockDevice(*exported.get()); ASSERT_NE(super_device, 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. Loading @@ -300,11 +311,11 @@ TEST(liblp, BuilderExport) { 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, 32); EXPECT_EQ(super_device->first_logical_sector, 32); static const size_t kMetadataSpace = ((kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE) * 2; EXPECT_GE(geometry.first_logical_sector * LP_SECTOR_SIZE, kMetadataSpace); EXPECT_GE(super_device->first_logical_sector * LP_SECTOR_SIZE, kMetadataSpace); // Verify header. const LpMetadataHeader& header = exported->header; Loading Loading @@ -413,13 +424,10 @@ TEST(liblp, block_device_info) { fs_mgr_free_fstab); ASSERT_NE(fstab, nullptr); // This should read from the "super" partition once we have a well-defined // way to access it. struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), "/data"); ASSERT_NE(rec, nullptr); PartitionOpener opener; BlockDeviceInfo device_info; ASSERT_TRUE(GetBlockDeviceInfo(rec->blk_device, &device_info)); ASSERT_TRUE(opener.GetInfo(fs_mgr_get_super_partition_name(), &device_info)); // Sanity check that the device doesn't give us some weird inefficient // alignment. Loading
fs_mgr/liblp/images.cpp +8 −11 Original line number Diff line number Diff line Loading @@ -99,11 +99,12 @@ SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size, block_size_(block_size), file_(nullptr, sparse_file_destroy), images_(images) { uint64_t total_size = GetTotalSuperPartitionSize(metadata); if (block_size % LP_SECTOR_SIZE != 0) { LERROR << "Block size must be a multiple of the sector size, " << LP_SECTOR_SIZE; return; } if (metadata.geometry.block_device_size % block_size != 0) { if (total_size % block_size != 0) { LERROR << "Device size must be a multiple of the block size, " << block_size; return; } Loading @@ -120,7 +121,7 @@ SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size, return; } uint64_t num_blocks = metadata.geometry.block_device_size % block_size; uint64_t num_blocks = total_size % block_size; if (num_blocks >= UINT_MAX) { // libsparse counts blocks in unsigned 32-bit integers, so we check to // make sure we're not going to overflow. Loading @@ -128,7 +129,10 @@ SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size, return; } file_.reset(sparse_file_new(block_size_, geometry_.block_device_size)); file_.reset(sparse_file_new(block_size_, total_size)); if (!file_) { LERROR << "Could not allocate sparse file of size " << total_size; } } bool SparseBuilder::Export(const char* file) { Loading Loading @@ -333,14 +337,7 @@ int SparseBuilder::OpenImageFile(const std::string& file) { bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size, const std::map<std::string, std::string>& images) { SparseBuilder builder(metadata, block_size, images); if (!builder.IsValid()) { LERROR << "Could not allocate sparse file of size " << metadata.geometry.block_device_size; return false; } if (!builder.Build()) { return false; } return builder.Export(file); return builder.IsValid() && builder.Build() && builder.Export(file); } } // namespace fs_mgr Loading