| // Copyright 2021 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/storage/volume_image/adapter/minfs_partition.h" |
| |
| #include <zircon/hw/gpt.h> |
| |
| #include <limits> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "src/storage/fvm/format.h" |
| #include "src/storage/minfs/format.h" |
| #include "src/storage/minfs/fsck.h" |
| #include "src/storage/minfs/transaction_limits.h" |
| #include "src/storage/volume_image/fvm/options.h" |
| #include "src/storage/volume_image/utils/block_utils.h" |
| #include "src/storage/volume_image/utils/fd_reader.h" |
| #include "src/storage/volume_image/utils/guid.h" |
| #include "src/storage/volume_image/utils/reader.h" |
| |
| namespace storage::volume_image { |
| namespace { |
| |
| constexpr std::string_view kMinfsImagePath = |
| STORAGE_VOLUME_IMAGE_ADAPTER_TEST_IMAGE_PATH "test_minfs.blk"; |
| |
| std::array<uint8_t, kGuidLength> kMinfsTypeGuid = GUID_DATA_VALUE; |
| std::array<uint8_t, kGuidLength> kMinfsInstanceGuid = fvm::kPlaceHolderInstanceGuid; |
| |
| FvmOptions MakeFvmOptions(uint64_t slice_size) { |
| FvmOptions options; |
| options.slice_size = slice_size; |
| return options; |
| } |
| |
| constexpr uint64_t kSliceSize = 32u * (1u << 10); |
| |
| class FakeReader final : public Reader { |
| public: |
| uint64_t length() const final { return 0; } |
| |
| fit::result<void, std::string> Read(uint64_t offset, fbl::Span<uint8_t> buffer) const final { |
| memset(buffer.data(), 0, buffer.size()); |
| if (offset == 0) { |
| memcpy(buffer.data(), &superblock_, std::min(sizeof(superblock_), buffer.size())); |
| } |
| return fit::ok(); |
| } |
| |
| minfs::Superblock& superblock() { return superblock_; } |
| |
| private: |
| minfs::Superblock superblock_ = {}; |
| }; |
| |
| TEST(MinfsPartitionTest, SliceSizeNotMultipleOfMinfsBlockSizeIsError) { |
| auto fvm_options = MakeFvmOptions(minfs::kMinfsBlockSize - 1); |
| PartitionOptions partition_options; |
| |
| auto fake_reader = std::make_unique<FakeReader>(); |
| ASSERT_TRUE( |
| CreateMinfsFvmPartition(std::move(fake_reader), partition_options, fvm_options).is_error()); |
| } |
| |
| TEST(MinfsPartitionTest, ImageWithBadMagicIsError) { |
| auto fvm_options = MakeFvmOptions(kSliceSize); |
| PartitionOptions partition_options; |
| |
| auto fake_reader = std::make_unique<FakeReader>(); |
| fake_reader->superblock().magic0 = minfs::kMinfsMagic0; |
| fake_reader->superblock().magic1 = 1; |
| ASSERT_TRUE( |
| CreateMinfsFvmPartition(std::move(fake_reader), partition_options, fvm_options).is_error()); |
| |
| fake_reader = std::make_unique<FakeReader>(); |
| fake_reader->superblock().magic0 = 0; |
| fake_reader->superblock().magic1 = minfs::kMinfsMagic1; |
| ASSERT_TRUE( |
| CreateMinfsFvmPartition(std::move(fake_reader), partition_options, fvm_options).is_error()); |
| } |
| |
| std::optional<AddressMap> FindMappingStartingAt(uint64_t target_offset, |
| const AddressDescriptor& address) { |
| for (const auto& mapping : address.mappings) { |
| if (mapping.target == target_offset) { |
| return mapping; |
| } |
| } |
| |
| return std::nullopt; |
| } |
| |
| void CheckPartition(const Partition& partition, const minfs::Superblock& original_superblock) { |
| EXPECT_EQ(partition.volume().name, "data"); |
| EXPECT_THAT(partition.volume().instance, testing::ElementsAreArray(kMinfsInstanceGuid)); |
| EXPECT_THAT(partition.volume().type, testing::ElementsAreArray(kMinfsTypeGuid)); |
| |
| // 6 total different regions, including superblock region. |
| ASSERT_EQ(partition.address().mappings.size(), 6u); |
| |
| auto superblock_mapping = FindMappingStartingAt(0, partition.address()); |
| ASSERT_TRUE(superblock_mapping.has_value()); |
| EXPECT_EQ(superblock_mapping->source, 0u); |
| EXPECT_EQ(superblock_mapping->count, sizeof(minfs::Superblock)); |
| EXPECT_THAT(superblock_mapping->options, |
| testing::Contains(testing::Pair(EnumAsString(AddressMapOption::kFill), 0u))); |
| |
| auto inode_bitmap_mapping = FindMappingStartingAt( |
| minfs::kFVMBlockInodeBmStart * minfs::kMinfsBlockSize, partition.address()); |
| ASSERT_TRUE(inode_bitmap_mapping.has_value()); |
| EXPECT_EQ(inode_bitmap_mapping->source, original_superblock.ibm_block * minfs::kMinfsBlockSize); |
| EXPECT_THAT(inode_bitmap_mapping->options, |
| testing::Contains(testing::Pair(EnumAsString(AddressMapOption::kFill), 0u))); |
| |
| auto data_bitmap_mapping = FindMappingStartingAt( |
| minfs::kFVMBlockDataBmStart * minfs::kMinfsBlockSize, partition.address()); |
| ASSERT_TRUE(data_bitmap_mapping.has_value()); |
| EXPECT_EQ(data_bitmap_mapping->source, original_superblock.abm_block * minfs::kMinfsBlockSize); |
| EXPECT_THAT(data_bitmap_mapping->options, |
| testing::Contains(testing::Pair(EnumAsString(AddressMapOption::kFill), 0u))); |
| |
| auto inode_mapping = FindMappingStartingAt(minfs::kFVMBlockInodeStart * minfs::kMinfsBlockSize, |
| partition.address()); |
| ASSERT_TRUE(inode_mapping.has_value()); |
| EXPECT_EQ(inode_mapping->source, original_superblock.ino_block * minfs::kMinfsBlockSize); |
| EXPECT_THAT(inode_mapping->options, |
| testing::Contains(testing::Pair(EnumAsString(AddressMapOption::kFill), 0u))); |
| |
| auto integrity_mapping = FindMappingStartingAt( |
| minfs::kFvmSuperblockBackup * minfs::kMinfsBlockSize, partition.address()); |
| ASSERT_TRUE(integrity_mapping.has_value()); |
| EXPECT_EQ(integrity_mapping->source, |
| original_superblock.integrity_start_block * minfs::kMinfsBlockSize); |
| |
| auto data_mapping = FindMappingStartingAt(minfs::kFVMBlockDataStart * minfs::kMinfsBlockSize, |
| partition.address()); |
| ASSERT_TRUE(data_mapping.has_value()); |
| EXPECT_EQ(data_mapping->source, original_superblock.dat_block * minfs::kMinfsBlockSize); |
| } |
| |
| struct SuperBlocks { |
| std::vector<uint8_t> original_superblock; |
| std::vector<uint8_t> actual_superblock; |
| }; |
| |
| std::optional<SuperBlocks> ReadSuperblocks(const Partition& partition, const Reader& source_image) { |
| std::vector<uint8_t> original_superblock; |
| original_superblock.resize(minfs::kMinfsBlockSize, 0); |
| auto original_superblock_result = source_image.Read(0, original_superblock); |
| EXPECT_TRUE(original_superblock_result.is_ok()) << original_superblock_result.error(); |
| |
| std::vector<uint8_t> superblock; |
| superblock.resize(minfs::kMinfsBlockSize, 0); |
| auto superblock_result = partition.reader()->Read(0, superblock); |
| EXPECT_TRUE(superblock_result.is_ok()) << superblock_result.error(); |
| |
| auto integrity_mapping = FindMappingStartingAt( |
| minfs::kFvmSuperblockBackup * minfs::kMinfsBlockSize, partition.address()); |
| EXPECT_TRUE(integrity_mapping.has_value()); |
| if (testing::Test::HasFailure()) { |
| return std::nullopt; |
| } |
| |
| std::vector<uint8_t> backup_superblock; |
| backup_superblock.resize(minfs::kMinfsBlockSize, 0); |
| auto backup_superblock_result = |
| partition.reader()->Read(integrity_mapping->source, backup_superblock); |
| EXPECT_TRUE(backup_superblock_result.is_ok()) << backup_superblock_result.error(); |
| |
| if (testing::Test::HasFailure()) { |
| return std::nullopt; |
| } |
| |
| EXPECT_TRUE(memcmp(superblock.data(), backup_superblock.data(), backup_superblock.size()) == 0); |
| |
| if (testing::Test::HasFailure()) { |
| return std::nullopt; |
| } |
| |
| return SuperBlocks{original_superblock, superblock}; |
| } |
| |
| void CheckSuperblock(const minfs::Superblock& actual_superblock, |
| const minfs::Superblock& original_superblock, const FvmOptions& fvm_options, |
| const PartitionOptions& partition_options) { |
| // This should not be altered at all. |
| EXPECT_EQ(actual_superblock.magic0, original_superblock.magic0); |
| EXPECT_EQ(actual_superblock.magic1, original_superblock.magic1); |
| EXPECT_EQ(actual_superblock.block_size, original_superblock.block_size); |
| EXPECT_EQ(actual_superblock.alloc_block_count, original_superblock.alloc_block_count); |
| EXPECT_EQ(actual_superblock.alloc_inode_count, original_superblock.alloc_inode_count); |
| EXPECT_EQ(actual_superblock.format_version, original_superblock.format_version); |
| EXPECT_EQ(actual_superblock.inode_size, original_superblock.inode_size); |
| EXPECT_EQ(actual_superblock.oldest_revision, original_superblock.oldest_revision); |
| EXPECT_EQ(actual_superblock.unlinked_head, original_superblock.unlinked_head); |
| EXPECT_EQ(actual_superblock.unlinked_tail, original_superblock.unlinked_tail); |
| |
| // The FVM flag MUST be set. |
| EXPECT_TRUE((actual_superblock.flags & minfs::kMinfsFlagFVM) != 0); |
| EXPECT_EQ(actual_superblock.slice_size, fvm_options.slice_size); |
| |
| // This are updated as a result of slice allocation, and aligning blocks with slices. |
| // At the very least contain enough for the original data. |
| // Also check that partition parameters are honored. |
| uint64_t inode_count = static_cast<uint64_t>(original_superblock.inode_count); |
| uint64_t inode_blocks = original_superblock.integrity_start_block - original_superblock.ino_block; |
| uint64_t inode_bitmap_blocks = original_superblock.abm_block - original_superblock.ibm_block; |
| if (inode_count < partition_options.min_inode_count.value_or(0)) { |
| inode_blocks = minfs::BlocksRequiredForInode(partition_options.min_inode_count.value()); |
| } |
| |
| inode_bitmap_blocks = std::max(static_cast<uint64_t>(minfs::BlocksRequiredForBits(inode_count)), |
| inode_bitmap_blocks); |
| |
| uint64_t data_blocks = |
| GetBlockCount(minfs::kFVMBlockDataStart, partition_options.min_data_bytes.value_or(0), |
| minfs::kMinfsBlockSize); |
| if (data_blocks < original_superblock.block_count) { |
| data_blocks = original_superblock.block_count; |
| } |
| |
| uint64_t data_bitmap_blocks = |
| std::max(original_superblock.ino_block - original_superblock.abm_block, |
| minfs::BlocksRequiredForBits(data_blocks)); |
| |
| uint64_t integrity_blocks = |
| original_superblock.dat_block - original_superblock.integrity_start_block; |
| minfs::TransactionLimits limits(original_superblock); |
| integrity_blocks = |
| std::max(integrity_blocks, static_cast<uint64_t>(limits.GetRecommendedIntegrityBlocks())); |
| |
| auto get_slice_count = [&fvm_options](uint64_t block_count) { |
| return GetBlockCount(0, block_count * minfs::kMinfsBlockSize, fvm_options.slice_size); |
| }; |
| auto get_slice_bytes = [&fvm_options, &get_slice_count](uint64_t block_count) { |
| return get_slice_count(block_count) * fvm_options.slice_size; |
| }; |
| |
| EXPECT_EQ(actual_superblock.inode_count, get_slice_bytes(inode_blocks) / minfs::kMinfsInodeSize); |
| EXPECT_EQ(actual_superblock.block_count, get_slice_bytes(data_blocks) / minfs::kMinfsBlockSize); |
| EXPECT_EQ(actual_superblock.ibm_block, minfs::kFVMBlockInodeBmStart); |
| EXPECT_EQ(actual_superblock.abm_block, minfs::kFVMBlockDataBmStart); |
| EXPECT_EQ(actual_superblock.ino_block, minfs::kFVMBlockInodeStart); |
| EXPECT_EQ(actual_superblock.integrity_start_block, minfs::kFvmSuperblockBackup); |
| EXPECT_EQ(actual_superblock.integrity_start_block, minfs::kFvmSuperblockBackup); |
| |
| // Now slices allocated for each extent should be correct as well. |
| EXPECT_EQ(actual_superblock.ino_slices, get_slice_count(inode_blocks)); |
| EXPECT_EQ(actual_superblock.dat_slices, get_slice_count(data_blocks)); |
| EXPECT_EQ(actual_superblock.ibm_slices, get_slice_count(inode_bitmap_blocks)); |
| EXPECT_EQ(actual_superblock.abm_slices, get_slice_count(data_bitmap_blocks)); |
| EXPECT_EQ(actual_superblock.integrity_slices, get_slice_count(integrity_blocks)); |
| } |
| |
| void CheckNoNSuperBlockMappingContents(const Partition& partition, const Reader& original_reader) { |
| std::vector<uint8_t> original_mapping_contents; |
| std::vector<uint8_t> mapping_contents; |
| // Now check that the reader has the correct data for the rest of the mappings. |
| for (uint64_t mapping_index = 1; mapping_index < partition.address().mappings.size(); |
| ++mapping_index) { |
| const auto& mapping = partition.address().mappings[mapping_index]; |
| SCOPED_TRACE(testing::Message() << "Comparing mapping index " << mapping_index |
| << " mapping: \n " << mapping.DebugString()); |
| |
| // Skip checking the backup superblock. |
| if (mapping.target == minfs::kFvmSuperblockBackup * minfs::kMinfsBlockSize) { |
| continue; |
| } |
| |
| // Only count bytes are backed by source data. |
| mapping_contents.resize(mapping.count, 0); |
| original_mapping_contents.resize(mapping.count, 0); |
| |
| // Adjust source for the extra block added for the backup superblock. |
| auto original_read_result = original_reader.Read(mapping.source, original_mapping_contents); |
| ASSERT_TRUE(original_read_result.is_ok()) << original_read_result.error(); |
| |
| auto read_result = partition.reader()->Read(mapping.source, mapping_contents); |
| ASSERT_TRUE(read_result.is_ok()) << read_result.error(); |
| |
| EXPECT_TRUE(memcmp(mapping_contents.data(), original_mapping_contents.data(), |
| mapping_contents.size()) == 0); |
| } |
| } |
| |
| TEST(MinfsPartitionTest, PartitionDataAndReaderIsCorrect) { |
| auto fvm_options = MakeFvmOptions(kSliceSize); |
| PartitionOptions partition_options; |
| |
| auto original_minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(original_minfs_reader_or.is_ok()) << original_minfs_reader_or.error(); |
| auto original_minfs_reader = original_minfs_reader_or.take_value(); |
| |
| auto minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(minfs_reader_or.is_ok()) << minfs_reader_or.error(); |
| std::unique_ptr<Reader> minfs_reader = std::make_unique<FdReader>(minfs_reader_or.take_value()); |
| |
| auto partition_or = |
| CreateMinfsFvmPartition(std::move(minfs_reader), partition_options, fvm_options); |
| ASSERT_TRUE(partition_or.is_ok()) << partition_or.error(); |
| auto partition = partition_or.take_value(); |
| |
| auto superblocks = ReadSuperblocks(partition, original_minfs_reader); |
| ASSERT_TRUE(superblocks.has_value()); |
| auto [original_superblock, actual_superblock] = std::move(superblocks.value()); |
| |
| const minfs::Superblock* actual_sb = |
| reinterpret_cast<minfs::Superblock*>(actual_superblock.data()); |
| const minfs::Superblock* original_sb = |
| reinterpret_cast<minfs::Superblock*>(original_superblock.data()); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| CheckSuperblock(*actual_sb, *original_sb, fvm_options, partition_options)); |
| ASSERT_NO_FATAL_FAILURE(CheckPartition(partition, *original_sb)); |
| ASSERT_NO_FATAL_FAILURE(CheckNoNSuperBlockMappingContents(partition, original_minfs_reader)); |
| } |
| |
| TEST(MinfsPartitionTest, PartitionDataAndReaderIsCorrectWithMinimumInodeCountHigherThanImage) { |
| auto fvm_options = MakeFvmOptions(kSliceSize); |
| PartitionOptions partition_options; |
| |
| auto original_minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(original_minfs_reader_or.is_ok()) << original_minfs_reader_or.error(); |
| auto original_minfs_reader = original_minfs_reader_or.take_value(); |
| |
| minfs::Superblock sb_tmp = {}; |
| auto read_result = original_minfs_reader.Read( |
| 0, fbl::Span<uint8_t>(reinterpret_cast<uint8_t*>(&sb_tmp), sizeof(sb_tmp))); |
| ASSERT_TRUE(read_result.is_ok()) << read_result.error(); |
| |
| // Add as many inodes such that at least an extra slice is allocated. |
| partition_options.min_inode_count = |
| sb_tmp.inode_count + GetBlockCount(0, 3 * fvm_options.slice_size, minfs::kMinfsInodeSize); |
| |
| auto minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(minfs_reader_or.is_ok()) << minfs_reader_or.error(); |
| std::unique_ptr<Reader> minfs_reader = std::make_unique<FdReader>(minfs_reader_or.take_value()); |
| |
| auto partition_or = |
| CreateMinfsFvmPartition(std::move(minfs_reader), partition_options, fvm_options); |
| ASSERT_TRUE(partition_or.is_ok()) << partition_or.error(); |
| auto partition = partition_or.take_value(); |
| |
| auto superblocks = ReadSuperblocks(partition, original_minfs_reader); |
| ASSERT_TRUE(superblocks.has_value()); |
| auto [original_superblock, actual_superblock] = std::move(superblocks.value()); |
| |
| const minfs::Superblock* actual_sb = |
| reinterpret_cast<minfs::Superblock*>(actual_superblock.data()); |
| const minfs::Superblock* original_sb = |
| reinterpret_cast<minfs::Superblock*>(original_superblock.data()); |
| |
| // Adjust the expected inode count such that it matches the amount of slices that would be |
| // required for the requested options. |
| auto expected_inode_count = |
| GetBlockCount(minfs::kFVMBlockInodeStart, |
| minfs::BlocksRequiredForInode(partition_options.min_inode_count.value()) * |
| minfs::kMinfsBlockSize, |
| minfs::kMinfsInodeSize); |
| ASSERT_EQ(actual_sb->inode_count, expected_inode_count); |
| ASSERT_NO_FATAL_FAILURE( |
| CheckSuperblock(*actual_sb, *original_sb, fvm_options, partition_options)); |
| ASSERT_NO_FATAL_FAILURE(CheckPartition(partition, *original_sb)); |
| ASSERT_NO_FATAL_FAILURE(CheckNoNSuperBlockMappingContents(partition, original_minfs_reader)); |
| } |
| |
| TEST(MinfsPartitionTest, PartitionDataAndReaderIsCorrectWithMinimumInodeCountLowerThanImage) { |
| auto fvm_options = MakeFvmOptions(kSliceSize); |
| PartitionOptions partition_options; |
| |
| auto original_minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(original_minfs_reader_or.is_ok()) << original_minfs_reader_or.error(); |
| auto original_minfs_reader = original_minfs_reader_or.take_value(); |
| |
| partition_options.min_inode_count = 1; |
| |
| auto minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(minfs_reader_or.is_ok()) << minfs_reader_or.error(); |
| std::unique_ptr<Reader> minfs_reader = std::make_unique<FdReader>(minfs_reader_or.take_value()); |
| |
| auto partition_or = |
| CreateMinfsFvmPartition(std::move(minfs_reader), partition_options, fvm_options); |
| ASSERT_TRUE(partition_or.is_ok()) << partition_or.error(); |
| auto partition = partition_or.take_value(); |
| |
| auto superblocks = ReadSuperblocks(partition, original_minfs_reader); |
| ASSERT_TRUE(superblocks.has_value()); |
| auto [original_superblock, actual_superblock] = std::move(superblocks.value()); |
| |
| const minfs::Superblock* actual_sb = |
| reinterpret_cast<minfs::Superblock*>(actual_superblock.data()); |
| const minfs::Superblock* original_sb = |
| reinterpret_cast<minfs::Superblock*>(original_superblock.data()); |
| |
| // Adjust the expected inode count such that it matches the amount of slices that would be |
| // required for the requested options. |
| ASSERT_EQ(actual_sb->inode_count, original_sb->inode_count); |
| ASSERT_NO_FATAL_FAILURE( |
| CheckSuperblock(*actual_sb, *original_sb, fvm_options, partition_options)); |
| ASSERT_NO_FATAL_FAILURE(CheckPartition(partition, *original_sb)); |
| ASSERT_NO_FATAL_FAILURE(CheckNoNSuperBlockMappingContents(partition, original_minfs_reader)); |
| } |
| |
| TEST(MinfsPartitionTest, PartitionDataAndReaderIsCorrectWithMinimumDataBytesHigherThanImage) { |
| auto fvm_options = MakeFvmOptions(kSliceSize); |
| PartitionOptions partition_options; |
| |
| auto original_minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(original_minfs_reader_or.is_ok()) << original_minfs_reader_or.error(); |
| auto original_minfs_reader = original_minfs_reader_or.take_value(); |
| |
| minfs::Superblock sb_tmp = {}; |
| auto read_result = original_minfs_reader.Read( |
| 0, fbl::Span<uint8_t>(reinterpret_cast<uint8_t*>(&sb_tmp), sizeof(sb_tmp))); |
| ASSERT_TRUE(read_result.is_ok()) << read_result.error(); |
| |
| // Add as many inodes such that at least an extra slice is allocated. |
| partition_options.min_data_bytes = sb_tmp.block_count + 3 * fvm_options.slice_size; |
| |
| auto minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(minfs_reader_or.is_ok()) << minfs_reader_or.error(); |
| std::unique_ptr<Reader> minfs_reader = std::make_unique<FdReader>(minfs_reader_or.take_value()); |
| |
| auto partition_or = |
| CreateMinfsFvmPartition(std::move(minfs_reader), partition_options, fvm_options); |
| ASSERT_TRUE(partition_or.is_ok()) << partition_or.error(); |
| auto partition = partition_or.take_value(); |
| |
| auto superblocks = ReadSuperblocks(partition, original_minfs_reader); |
| ASSERT_TRUE(superblocks.has_value()); |
| auto [original_superblock, actual_superblock] = std::move(superblocks.value()); |
| |
| const minfs::Superblock* actual_sb = |
| reinterpret_cast<minfs::Superblock*>(actual_superblock.data()); |
| const minfs::Superblock* original_sb = |
| reinterpret_cast<minfs::Superblock*>(original_superblock.data()); |
| |
| // Round to fvm slices, then to minfs blocks. |
| auto expected_data_block_count = GetBlockCount( |
| 0, |
| GetBlockCount(minfs::kFVMBlockDataStart, partition_options.min_data_bytes.value(), |
| fvm_options.slice_size) * |
| fvm_options.slice_size, |
| minfs::kMinfsBlockSize); |
| ASSERT_EQ(actual_sb->block_count, expected_data_block_count); |
| ASSERT_NO_FATAL_FAILURE( |
| CheckSuperblock(*actual_sb, *original_sb, fvm_options, partition_options)); |
| ASSERT_NO_FATAL_FAILURE(CheckPartition(partition, *original_sb)); |
| ASSERT_NO_FATAL_FAILURE(CheckNoNSuperBlockMappingContents(partition, original_minfs_reader)); |
| } |
| |
| TEST(MinfsPartitionTest, PartitionDataAndReaderIsCorrectWithMinimumDataBytesLowerThanImage) { |
| auto fvm_options = MakeFvmOptions(kSliceSize); |
| PartitionOptions partition_options; |
| |
| auto original_minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(original_minfs_reader_or.is_ok()) << original_minfs_reader_or.error(); |
| auto original_minfs_reader = original_minfs_reader_or.take_value(); |
| |
| auto minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(minfs_reader_or.is_ok()) << minfs_reader_or.error(); |
| std::unique_ptr<Reader> minfs_reader = std::make_unique<FdReader>(minfs_reader_or.take_value()); |
| |
| auto partition_or = |
| CreateMinfsFvmPartition(std::move(minfs_reader), partition_options, fvm_options); |
| ASSERT_TRUE(partition_or.is_ok()) << partition_or.error(); |
| auto partition = partition_or.take_value(); |
| |
| auto superblocks = ReadSuperblocks(partition, original_minfs_reader); |
| ASSERT_TRUE(superblocks.has_value()); |
| auto [original_superblock, actual_superblock] = std::move(superblocks.value()); |
| |
| const minfs::Superblock* actual_sb = |
| reinterpret_cast<minfs::Superblock*>(actual_superblock.data()); |
| const minfs::Superblock* original_sb = |
| reinterpret_cast<minfs::Superblock*>(original_superblock.data()); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| CheckSuperblock(*actual_sb, *original_sb, fvm_options, partition_options)); |
| ASSERT_NO_FATAL_FAILURE(CheckPartition(partition, *original_sb)); |
| ASSERT_NO_FATAL_FAILURE(CheckNoNSuperBlockMappingContents(partition, original_minfs_reader)); |
| } |
| |
| TEST(MinfsPartitionTest, PartitionDataAndReaderIsCorrectWithMaxBytesHigherThanImage) { |
| auto fvm_options = MakeFvmOptions(kSliceSize); |
| PartitionOptions partition_options; |
| |
| auto original_minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(original_minfs_reader_or.is_ok()) << original_minfs_reader_or.error(); |
| auto original_minfs_reader = original_minfs_reader_or.take_value(); |
| |
| partition_options.max_bytes = std::numeric_limits<uint64_t>::max(); |
| |
| auto minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(minfs_reader_or.is_ok()) << minfs_reader_or.error(); |
| std::unique_ptr<Reader> minfs_reader = std::make_unique<FdReader>(minfs_reader_or.take_value()); |
| |
| auto partition_or = |
| CreateMinfsFvmPartition(std::move(minfs_reader), partition_options, fvm_options); |
| ASSERT_TRUE(partition_or.is_ok()) << partition_or.error(); |
| auto partition = partition_or.take_value(); |
| |
| auto superblocks = ReadSuperblocks(partition, original_minfs_reader); |
| ASSERT_TRUE(superblocks.has_value()); |
| auto [original_superblock, actual_superblock] = std::move(superblocks.value()); |
| |
| const minfs::Superblock* actual_sb = |
| reinterpret_cast<minfs::Superblock*>(actual_superblock.data()); |
| const minfs::Superblock* original_sb = |
| reinterpret_cast<minfs::Superblock*>(original_superblock.data()); |
| |
| // Adjust the expected inode count such that it matches the amount of slices that would be |
| // required for the requested options. |
| ASSERT_NO_FATAL_FAILURE( |
| CheckSuperblock(*actual_sb, *original_sb, fvm_options, partition_options)); |
| ASSERT_NO_FATAL_FAILURE(CheckPartition(partition, *original_sb)); |
| ASSERT_NO_FATAL_FAILURE(CheckNoNSuperBlockMappingContents(partition, original_minfs_reader)); |
| } |
| |
| TEST(MinfsPartitionTest, ExceedingMaxBytesIsError) { |
| auto fvm_options = MakeFvmOptions(kSliceSize); |
| PartitionOptions partition_options; |
| |
| auto original_minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(original_minfs_reader_or.is_ok()) << original_minfs_reader_or.error(); |
| auto original_minfs_reader = original_minfs_reader_or.take_value(); |
| |
| partition_options.max_bytes = 1; |
| |
| auto minfs_reader_or = FdReader::Create(kMinfsImagePath); |
| ASSERT_TRUE(minfs_reader_or.is_ok()) << minfs_reader_or.error(); |
| std::unique_ptr<Reader> minfs_reader = std::make_unique<FdReader>(minfs_reader_or.take_value()); |
| |
| auto partition_or = |
| CreateMinfsFvmPartition(std::move(minfs_reader), partition_options, fvm_options); |
| ASSERT_TRUE(partition_or.is_error()); |
| } |
| |
| } // namespace |
| } // namespace storage::volume_image |