diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/kernel/filesystem/ext2/inode.hpp | 3 | ||||
| -rw-r--r-- | kernel/kernel/filesystem/ext2/inode.tests.cpp | 165 | ||||
| -rw-r--r-- | kernel/kernel/test_support/filesystem/ext2.cpp | 12 | ||||
| -rw-r--r-- | kernel/kernel/test_support/filesystem/ext2.hpp | 4 |
4 files changed, 127 insertions, 57 deletions
diff --git a/kernel/kernel/filesystem/ext2/inode.hpp b/kernel/kernel/filesystem/ext2/inode.hpp index 6001c813..9c5f9beb 100644 --- a/kernel/kernel/filesystem/ext2/inode.hpp +++ b/kernel/kernel/filesystem/ext2/inode.hpp @@ -97,9 +97,10 @@ namespace kernel::filesystem::ext2 */ [[nodiscard]] auto size() const -> uint64_t; + auto set_size(uint64_t new_size) -> void; + private: auto append_blocks(size_t count) -> bool; - auto set_size(uint64_t new_size) -> void; filesystem * m_filesystem; uint32_t m_inode_number{}; diff --git a/kernel/kernel/filesystem/ext2/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp index 6aba8b77..752d17d7 100644 --- a/kernel/kernel/filesystem/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp @@ -2,6 +2,7 @@ #include <kernel/devices/storage/management.hpp> #include <kernel/filesystem/device_inode.hpp> +#include <kernel/filesystem/ext2/block_group_descriptor.hpp> #include <kernel/filesystem/ext2/filesystem.hpp> #include <kernel/filesystem/ext2/superblock.hpp> #include <kernel/filesystem/filesystem.hpp> @@ -17,8 +18,10 @@ #include <algorithm> #include <cstddef> +#include <cstdint> #include <filesystem> #include <string_view> +#include <vector> // NOLINTBEGIN(readability-magic-numbers) @@ -328,44 +331,84 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]") { - // auto const block_size = 1024uz; - // GIVEN("an ext2 inode with two direct blocks") - // { - // auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size); - // REQUIRE(device != nullptr); - // kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device); - - // auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); - - // auto fs = kernel::filesystem::ext2::filesystem{}; - // REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); - - // auto inode_data = kernel::filesystem::ext2::inode_data{}; - // inode_data.size = block_size * 2; - // inode_data.blocks = 2 * block_size / 512; - // inode_data.block[0] = 20; - // inode_data.block[1] = 21; - // inode_data.mode = kernel::filesystem::ext2::constants::mode_regular; - - // auto inode = kernel::filesystem::ext2::inode{&fs, 42, inode_data}; - - // THEN("writing over block boundaries updates backing device") - // { - // auto buffer = kstd::vector<std::byte>{std::byte{'H'}, std::byte{'e'}, std::byte{'l'}, std::byte{'l'}, - // std::byte{'o'}, std::byte{' '}, std::byte{'W'}, std::byte{'o'}, - // std::byte{'r'}, std::byte{'l'}, std::byte{'d'}, std::byte{'!'}}; - - // auto const bytes_written = inode.write(buffer.data(), block_size - 4, buffer.size()); - // REQUIRE(bytes_written == buffer.size()); - - // auto const text = - // std::string_view{reinterpret_cast<char const *>(device->data.data() + 21 * block_size - 4), bytes_written}; - // REQUIRE(text == "Hello World!"); - // } - // } + auto const block_size = 1024uz; + GIVEN("an ext2 inode with two direct blocks") + { + auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size); + REQUIRE(device != nullptr); + + auto superblock = kernel::filesystem::ext2::superblock{}; + superblock.magic = kernel::filesystem::ext2::constants::magic_number; + superblock.log_block_size = 0; + superblock.blocks_count = 64; + superblock.blocks_per_group = 64; + superblock.inodes_per_group = 32; + superblock.inode_size = 128; + superblock.rev_level = 1; + superblock.free_blocks_count = 64 - 15; + + auto block_group_descriptor = kernel::filesystem::ext2::block_group_descriptor{}; + block_group_descriptor.inode_table = 5; + block_group_descriptor.free_blocks_count = 64 - 15; + block_group_descriptor.block_bitmap = 10; + + kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device, superblock, block_group_descriptor); + + auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); + + auto block_bitmap = std::vector<std::byte>(block_size, std::byte{0x00}); + block_bitmap[0] = std::byte{0b1111'1111}; + block_bitmap[1] = std::byte{0b1111'1111}; + block_bitmap[2] = std::byte{0b0001'1000}; + + dev_inode->write(block_bitmap.data(), block_group_descriptor.block_bitmap * block_size, block_size); + + auto fs = kernel::filesystem::ext2::filesystem{}; + REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); + + auto inode_data = kernel::filesystem::ext2::inode_data{}; + inode_data.size = 5; + inode_data.blocks = 2 * block_size / 512; + inode_data.block[0] = 20; + inode_data.block[1] = 21; + inode_data.mode = kernel::filesystem::ext2::constants::mode_regular; + + uint32_t inode_number = 3; + auto inode = kernel::filesystem::ext2::inode{&fs, inode_number, inode_data}; + dev_inode->write(&inode, inode_number * block_size, sizeof(kernel::filesystem::ext2::inode_data)); + + THEN("writing over block boundaries updates backing device no additional blocks allocated") + { + auto buffer = kstd::vector<std::byte>{std::byte{'H'}, std::byte{'e'}, std::byte{'l'}, std::byte{'l'}, + std::byte{'o'}, std::byte{' '}, std::byte{'W'}, std::byte{'o'}, + std::byte{'r'}, std::byte{'l'}, std::byte{'d'}, std::byte{'!'}}; + + auto const offset = block_size - 4; + auto const bytes_written = inode.write(buffer.data(), offset, buffer.size()); + REQUIRE(bytes_written == buffer.size()); + + auto const text = + std::string_view{reinterpret_cast<char const *>(device->data.data() + 21 * block_size - 4), bytes_written}; + REQUIRE(text == "Hello World!"); + + auto read_block_bitmap = std::vector<std::byte>(block_size, std::byte{0x00}); + dev_inode->read(read_block_bitmap.data(), block_group_descriptor.block_bitmap * block_size, block_size); + REQUIRE(block_bitmap == read_block_bitmap); + + auto read_inode = kernel::filesystem::ext2::inode{&fs, inode_number, {}}; + dev_inode->read(&read_inode, inode_number * block_size, sizeof(kernel::filesystem::ext2::inode)); + REQUIRE(offset + 12 == inode.size()); + REQUIRE(inode_data.blocks == read_inode.data().blocks); + + auto const current_blocks = inode_data.block; + auto const read_blocks = read_inode.data().block; + REQUIRE(current_blocks == read_blocks); + } + } } -SCENARIO("Ext2 inode get_size() correctly returns size depending on revision level", "[filesystem][ext2][inode]") +SCENARIO("Ext2 inode get_size() and set_size() handles size correctly depending on revision level", + "[filesystem][ext2][inode]") { auto const block_size = 1024uz; @@ -394,22 +437,29 @@ SCENARIO("Ext2 inode get_size() correctly returns size depending on revision lev data.size = 256; data.dir_acl = 32; - THEN("the inode size is 256 if mode = regular") - { - data.mode = kernel::filesystem::ext2::constants::mode_regular; + auto const verify_size_and_set_size = [&](uint16_t mode, uint64_t expected_initial_size, + uint32_t expected_dir_acl_after_set_size) { + data.mode = mode; auto inode = kernel::filesystem::ext2::inode{&fs, 42, data}; - REQUIRE(inode.size() == 256); + REQUIRE(inode.size() == expected_initial_size); + + inode.set_size(12); + + REQUIRE(inode.size() == 12); + REQUIRE(inode.data().size == 12); + REQUIRE(inode.data().dir_acl == expected_dir_acl_after_set_size); + }; + + THEN("the inode size is 256 if mode = regular") + { + verify_size_and_set_size(kernel::filesystem::ext2::constants::mode_regular, 256, 32); } THEN("the inode size is 256 if mode = directory") { - data.mode = kernel::filesystem::ext2::constants::mode_directory; - - auto inode = kernel::filesystem::ext2::inode{&fs, 42, data}; - - REQUIRE(inode.size() == 256); + verify_size_and_set_size(kernel::filesystem::ext2::constants::mode_directory, 256, 32); } } @@ -430,22 +480,29 @@ SCENARIO("Ext2 inode get_size() correctly returns size depending on revision lev data.size = 256; data.dir_acl = 32; - THEN("the inode size is 256 if mode = regular") - { - data.mode = kernel::filesystem::ext2::constants::mode_regular; + auto const verify_size_and_set_size = [&](uint16_t mode, uint64_t expected_initial_size, + uint32_t expected_dir_acl_after_set_size) { + data.mode = mode; auto inode = kernel::filesystem::ext2::inode{&fs, 42, data}; - REQUIRE(inode.size() == 0x0000'0020'0000'0100); + REQUIRE(inode.size() == expected_initial_size); + + inode.set_size(12); + + REQUIRE(inode.size() == 12); + REQUIRE(inode.data().size == 12); + REQUIRE(inode.data().dir_acl == expected_dir_acl_after_set_size); + }; + + THEN("the inode size is 256 if mode = regular") + { + verify_size_and_set_size(kernel::filesystem::ext2::constants::mode_regular, 0x0000'0020'0000'0100, 0); } THEN("the inode size is 256 if mode = directory") { - data.mode = kernel::filesystem::ext2::constants::mode_directory; - - auto inode = kernel::filesystem::ext2::inode{&fs, 42, data}; - - REQUIRE(inode.size() == 256); + verify_size_and_set_size(kernel::filesystem::ext2::constants::mode_directory, 256, 32); } } } diff --git a/kernel/kernel/test_support/filesystem/ext2.cpp b/kernel/kernel/test_support/filesystem/ext2.cpp index 52b6efe7..3a7449ed 100644 --- a/kernel/kernel/test_support/filesystem/ext2.cpp +++ b/kernel/kernel/test_support/filesystem/ext2.cpp @@ -8,6 +8,7 @@ #include <cstdint> #include <cstring> +#include <vector> namespace kernel::tests::filesystem::ext2 { @@ -49,10 +50,17 @@ namespace kernel::tests::filesystem::ext2 auto setup_mock_ext2_layout(kernel::tests::devices::block_device & device, kernel::filesystem::ext2::superblock const & superblock) -> void { - write_bytes(device, kernel::filesystem::ext2::constants::superblock_offset, &superblock, sizeof(superblock)); - auto group_descriptor = kernel::filesystem::ext2::block_group_descriptor{}; group_descriptor.inode_table = 5; + + setup_mock_ext2_layout(device, superblock, group_descriptor); + } + + auto setup_mock_ext2_layout(kernel::tests::devices::block_device & device, + kernel::filesystem::ext2::superblock const & superblock, + kernel::filesystem::ext2::block_group_descriptor const & group_descriptor) -> void + { + write_bytes(device, kernel::filesystem::ext2::constants::superblock_offset, &superblock, sizeof(superblock)); write_bytes(device, 2048, &group_descriptor, sizeof(group_descriptor)); auto root_inode_data = kernel::filesystem::ext2::inode_data{}; diff --git a/kernel/kernel/test_support/filesystem/ext2.hpp b/kernel/kernel/test_support/filesystem/ext2.hpp index 18cef1c2..3dd80ea3 100644 --- a/kernel/kernel/test_support/filesystem/ext2.hpp +++ b/kernel/kernel/test_support/filesystem/ext2.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_KERNEL_TEST_SUPPORT_FILESYSTEM_EXT2_HPP #define TEACHOS_KERNEL_TEST_SUPPORT_FILESYSTEM_EXT2_HPP +#include <kernel/filesystem/ext2/block_group_descriptor.hpp> #include <kernel/filesystem/ext2/superblock.hpp> #include <kernel/test_support/devices/block_device.hpp> @@ -15,6 +16,9 @@ namespace kernel::tests::filesystem::ext2 auto setup_mock_ext2_layout(kernel::tests::devices::block_device & device) -> void; auto setup_mock_ext2_layout(kernel::tests::devices::block_device & device, kernel::filesystem::ext2::superblock const & superblock) -> void; + auto setup_mock_ext2_layout(kernel::tests::devices::block_device & device, + kernel::filesystem::ext2::superblock const & superblock, + kernel::filesystem::ext2::block_group_descriptor const & group_descriptor) -> void; } // namespace kernel::tests::filesystem::ext2 |
