| // Copyright 2019 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 <fcntl.h> |
| #include <string.h> |
| |
| #include <algorithm> |
| #include <memory> |
| #include <vector> |
| |
| #include <lib/ftl-mtd/ftl-volume-wrapper.h> |
| #include <lib/ftl-mtd/nand-volume-driver.h> |
| #include <lib/mtd/mtd-interface.h> |
| #include <zxtest/zxtest.h> |
| |
| using namespace ftl_mtd; |
| |
| // FtlVolumeWrapperIntegrationTest relies on a device file located at /dev/mtd0/ |
| // On the host machine, nandsim is used to create a virtual MTD device. |
| // The following command was used to create the device for this test. |
| // $ sudo modprobe nandsim id_bytes=0x2c,0xdc,0x90,0xa6,0x54,0x0 badblocks=5 |
| |
| namespace { |
| |
| constexpr const char* kTestDevicePath = "/dev/mtd0"; |
| constexpr uint32_t kBlockOffset = 0; |
| constexpr uint32_t kMaxBadBlocks = 10; |
| |
| class FtlVolumeWrapperIntegrationTest : public zxtest::Test { |
| protected: |
| void SetUp() override { |
| ftl_volume_wrapper_ = std::make_unique<FtlVolumeWrapper>(); |
| auto mtd_interface = mtd::MtdInterface::Create(kTestDevicePath); |
| interface_ = mtd_interface.get(); |
| WipeNandInterface(); |
| |
| std::unique_ptr<NandVolumeDriver> nand_volume_driver; |
| ASSERT_OK(NandVolumeDriver::Create(kBlockOffset, kMaxBadBlocks, std::move(mtd_interface), |
| &nand_volume_driver)); |
| |
| ASSERT_NULL(nand_volume_driver->Init()); |
| ASSERT_OK(ftl_volume_wrapper_->Init(std::move(nand_volume_driver))); |
| } |
| |
| void WipeNandInterface() { |
| uint32_t size = interface_->Size(); |
| uint32_t block_size = interface_->BlockSize(); |
| |
| for (uint32_t block_offset = 0; block_offset < size; block_offset += block_size) { |
| bool is_bad_block; |
| ASSERT_OK(interface_->IsBadBlock(block_offset, &is_bad_block)); |
| |
| if (!is_bad_block) { |
| ASSERT_OK(interface_->EraseBlock(block_offset)); |
| } |
| } |
| } |
| |
| mtd::NandInterface* interface_; |
| std::unique_ptr<FtlVolumeWrapper> ftl_volume_wrapper_; |
| }; |
| |
| TEST_F(FtlVolumeWrapperIntegrationTest, ReadWriteSucceeds) { |
| uint32_t page_count = 2; |
| uint32_t byte_count = page_count * interface_->PageSize(); |
| uint32_t seek_offset = 15 * interface_->BlockSize(); |
| std::vector<uint8_t> buffer(byte_count); |
| |
| // Wrapper should always start at 0. |
| ASSERT_EQ(0, ftl_volume_wrapper_->Tell()); |
| |
| // 1. Write one set of values. |
| memset(buffer.data(), 0xAB, byte_count); |
| ASSERT_EQ(byte_count, ftl_volume_wrapper_->Write(buffer.data(), byte_count)); |
| ASSERT_EQ(byte_count, ftl_volume_wrapper_->Tell()); |
| |
| // 2. Write a different set of values. |
| memset(buffer.data(), 0xCD, byte_count); |
| ASSERT_EQ(byte_count, ftl_volume_wrapper_->Write(buffer.data(), byte_count)); |
| ASSERT_EQ(2 * byte_count, ftl_volume_wrapper_->Tell()); |
| |
| // 3. Seek to a different place and write yet another different set of values. |
| ASSERT_EQ(seek_offset, ftl_volume_wrapper_->Seek(seek_offset, SEEK_SET)); |
| memset(buffer.data(), 0x1F, byte_count); |
| ASSERT_EQ(byte_count, ftl_volume_wrapper_->Write(buffer.data(), byte_count)); |
| ASSERT_EQ(seek_offset + byte_count, ftl_volume_wrapper_->Tell()); |
| |
| ASSERT_OK(ftl_volume_wrapper_->Sync()); |
| |
| // Read back the bytes and ensure they're what we expect. |
| ASSERT_EQ(0, ftl_volume_wrapper_->Seek(0, SEEK_SET)); |
| memset(buffer.data(), 0, byte_count); |
| ASSERT_EQ(byte_count, ftl_volume_wrapper_->Read(buffer.data(), byte_count)); |
| ASSERT_TRUE(std::all_of(buffer.begin(), buffer.end(), [](uint8_t val) { return val == 0xAB; })); |
| ASSERT_EQ(byte_count, ftl_volume_wrapper_->Tell()); |
| |
| memset(buffer.data(), 0, byte_count); |
| ASSERT_EQ(byte_count, ftl_volume_wrapper_->Read(buffer.data(), byte_count)); |
| ASSERT_TRUE(std::all_of(buffer.begin(), buffer.end(), [](uint8_t val) { return val == 0xCD; })); |
| ASSERT_EQ(2 * byte_count, ftl_volume_wrapper_->Tell()); |
| |
| ASSERT_EQ(seek_offset, ftl_volume_wrapper_->Seek(seek_offset, SEEK_SET)); |
| memset(buffer.data(), 0, byte_count); |
| ASSERT_EQ(byte_count, ftl_volume_wrapper_->Read(buffer.data(), byte_count)); |
| ASSERT_TRUE(std::all_of(buffer.begin(), buffer.end(), [](uint8_t val) { return val == 0x1F; })); |
| ASSERT_EQ(seek_offset + byte_count, ftl_volume_wrapper_->Tell()); |
| } |
| |
| } // namespace |