aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-08-22 13:47:30 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-08-26 11:16:16 +0200
commitc2f73da69d368f4488b878c5b4e957be630a3a7b (patch)
tree5d2f7ab5e8e967c2c28841fe05d4d9c5ee038ef7 /kernel
parentf3183a93826b1dabe4a446c2d834eae7de06b3e0 (diff)
downloadkernel-c2f73da69d368f4488b878c5b4e957be630a3a7b.tar.xz
kernel-c2f73da69d368f4488b878c5b4e957be630a3a7b.zip
kernel/fs: remove raw filesystem pointer from inode.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kernel/filesystem/error.cpp4
-rw-r--r--kernel/kernel/filesystem/error.hpp1
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.cpp16
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.hpp3
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.tests.cpp97
-rw-r--r--kernel/kernel/filesystem/ext2/inode.cpp114
-rw-r--r--kernel/kernel/filesystem/ext2/inode.hpp9
-rw-r--r--kernel/kernel/filesystem/ext2/inode.tests.cpp116
8 files changed, 220 insertions, 140 deletions
diff --git a/kernel/kernel/filesystem/error.cpp b/kernel/kernel/filesystem/error.cpp
index 80ad1097..d288693e 100644
--- a/kernel/kernel/filesystem/error.cpp
+++ b/kernel/kernel/filesystem/error.cpp
@@ -54,6 +54,8 @@ namespace kernel::filesystem
return "no such device";
case vfs_errc::invalid_argument:
return "invalid argument";
+ case vfs_errc::not_mounted:
+ return "filesystem is not mounted";
default:
return "unknown VFS error";
}
@@ -91,6 +93,8 @@ namespace kernel::filesystem
return make_error_condition(kstd::errc::file_exists);
case vfs_errc::no_such_device:
return make_error_condition(kstd::errc::no_such_device);
+ case vfs_errc::not_mounted:
+ return make_error_condition(kstd::errc::not_connected);
default:
return kstd::error_condition{value, *this};
}
diff --git a/kernel/kernel/filesystem/error.hpp b/kernel/kernel/filesystem/error.hpp
index 83b11902..41009bb7 100644
--- a/kernel/kernel/filesystem/error.hpp
+++ b/kernel/kernel/filesystem/error.hpp
@@ -27,6 +27,7 @@ namespace kernel::filesystem
file_exists,
no_such_device,
invalid_argument,
+ not_mounted,
};
[[nodiscard]] auto vfs_category() noexcept -> kstd::error_category const &;
diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp
index c6180fe1..58d24fc1 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.cpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.cpp
@@ -134,7 +134,7 @@ namespace kernel::filesystem::ext2
return kstd::failure(read_result.error());
}
- auto root = read_inode(constants::root_inode_number);
+ auto root = read_inode(constants::root_inode_number, nullptr);
if (!root)
{
@@ -187,7 +187,7 @@ namespace kernel::filesystem::ext2
auto const entry_name = std::string_view{entry->name.data(), entry->name_len};
if (entry_name == name)
{
- return read_inode(entry->inode);
+ return read_inode(entry->inode, ext2_parent->owning_mount().lock());
}
bytes_read += kstd::bytes{entry->rec_len};
@@ -223,7 +223,7 @@ namespace kernel::filesystem::ext2
auto * ext2_parent = static_cast<inode *>(parent.get());
if (!ext2_parent)
{
- return nullptr;
+ return kstd::failure(vfs_errc::invalid_argument);
}
auto maybe_inode_number = allocate_inode();
@@ -257,7 +257,8 @@ namespace kernel::filesystem::ext2
return kstd::failure(result.error());
}
- auto new_inode = kstd::make_shared<inode>(this, inode_number, new_inode_data);
+ auto new_inode = kstd::make_shared<inode>(inode_number, new_inode_data);
+ new_inode->set_owning_mount(ext2_parent->owning_mount().lock());
if (new_inode->is_directory())
{
@@ -394,7 +395,8 @@ namespace kernel::filesystem::ext2
kstd::libc::memcpy(entry->name.data(), name.data(), name_len);
}
- auto filesystem::read_inode(uint32_t inode_number) const -> kstd::result<kstd::shared_ptr<inode>>
+ auto filesystem::read_inode(uint32_t inode_number, kstd::shared_ptr<struct mount> const & mount) const
+ -> kstd::result<kstd::shared_ptr<inode>>
{
if (auto inode_offset = calculate_inode_offset(inode_number))
{
@@ -407,7 +409,9 @@ namespace kernel::filesystem::ext2
}
else
{
- return kstd::make_shared<inode>(const_cast<filesystem *>(this), inode_number, new_inode_data);
+ auto inode = kstd::make_shared<struct inode>(inode_number, new_inode_data);
+ inode->set_owning_mount(mount);
+ return inode;
}
}
else
diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp
index 23629928..2f9d0d58 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.hpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.hpp
@@ -178,7 +178,8 @@ namespace kernel::filesystem::ext2
std::string_view name, uint8_t file_type) -> void;
[[nodiscard]] auto calculate_inode_offset(uint32_t inode_number) const -> kstd::result<kstd::bytes>;
- [[nodiscard]] auto read_inode(uint32_t inode_number) const -> kstd::result<kstd::shared_ptr<inode>>;
+ [[nodiscard]] auto read_inode(uint32_t inode_number, kstd::shared_ptr<struct mount> const & mount) const
+ -> kstd::result<kstd::shared_ptr<inode>>;
[[nodiscard]] auto read_block_number_at_index(uint32_t block_number, size_t index) const -> kstd::result<uint32_t>;
[[nodiscard]] auto block_group_descriptor_table_offset() const -> kstd::bytes;
diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp
index bf7c89ae..5feea017 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp
@@ -7,6 +7,7 @@
#include <kernel/filesystem/ext2/inode.hpp>
#include <kernel/filesystem/ext2/superblock.hpp>
#include <kernel/filesystem/filesystem.hpp>
+#include <kernel/filesystem/mount.hpp>
#include <kernel/test_support/cpu.hpp>
#include <kernel/test_support/devices/block_device.hpp>
#include <kernel/test_support/filesystem/ext2.hpp>
@@ -47,38 +48,39 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture,
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(boot_device);
- auto fs = kernel::filesystem::ext2::filesystem{};
- auto root = fs.mount(dev_inode);
- REQUIRE(root);
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode);
+ auto root = (*mount)->root_dentry()->get_inode();
+ REQUIRE(mount);
THEN("the root inode is available and is a directory")
{
- REQUIRE(*root);
- REQUIRE((*root)->is_directory());
+ REQUIRE(root);
+ REQUIRE((root)->is_directory());
}
THEN("lookup resolves known entries from the image")
{
- auto information = fs.lookup(*root, "information");
+ auto information = fs->lookup(root, "information");
REQUIRE(information);
REQUIRE(information.value()->is_directory());
- auto info_1 = fs.lookup(*information, "info_1.txt");
+ auto info_1 = fs->lookup(*information, "info_1.txt");
REQUIRE(info_1);
REQUIRE(info_1.value()->is_regular());
}
THEN("lookup returns null for invalid inputs")
{
- REQUIRE(!fs.lookup(nullptr, "information"));
+ REQUIRE(!fs->lookup(nullptr, "information"));
- auto information = fs.lookup(*root, "information");
+ auto information = fs->lookup(root, "information");
REQUIRE(information);
- auto info_1 = fs.lookup(*information, "info_1.txt");
+ auto info_1 = fs->lookup(*information, "info_1.txt");
REQUIRE(info_1);
- REQUIRE(!fs.lookup(*info_1, "anything"));
- REQUIRE(!fs.lookup(*root, "does_not_exist"));
+ REQUIRE(!fs->lookup(*info_1, "anything"));
+ REQUIRE(!fs->lookup(root, "does_not_exist"));
}
}
}
@@ -98,52 +100,53 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture,
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(boot_device);
- auto fs = kernel::filesystem::ext2::filesystem{};
- auto root = fs.mount(dev_inode);
- REQUIRE(root);
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode);
+ auto root = (*mount)->root_dentry()->get_inode();
+ REQUIRE(mount);
THEN("a file can be created")
{
- auto lookup_result = fs.lookup(*root, "blub");
+ auto lookup_result = fs->lookup(root, "blub");
REQUIRE(!lookup_result);
- auto new_inode = fs.create_inode(*root, "blub", kapi::filesystem::file_type::regular);
+ auto new_inode = fs->create_inode(root, "blub", kapi::filesystem::file_type::regular);
REQUIRE(new_inode);
REQUIRE(new_inode.value()->is_regular());
- lookup_result = fs.lookup(*root, "blub");
+ lookup_result = fs->lookup(root, "blub");
REQUIRE(lookup_result);
}
THEN("a directory can be created")
{
- auto lookup_result = fs.lookup(*root, "blub");
+ auto lookup_result = fs->lookup(root, "blub");
REQUIRE(!lookup_result);
- auto new_directory = fs.create_inode(*root, "blub", kapi::filesystem::file_type::directory);
+ auto new_directory = fs->create_inode(root, "blub", kapi::filesystem::file_type::directory);
REQUIRE(new_directory);
REQUIRE(new_directory.value()->is_directory());
- lookup_result = fs.lookup(*root, "blub");
+ lookup_result = fs->lookup(root, "blub");
REQUIRE(lookup_result);
}
THEN("a directory and a file within can be created")
{
- auto new_directory = fs.create_inode(*root, "blub", kapi::filesystem::file_type::directory);
+ auto new_directory = fs->create_inode(root, "blub", kapi::filesystem::file_type::directory);
REQUIRE(new_directory);
- auto new_file = fs.create_inode(new_directory.value(), "blub_file", kapi::filesystem::file_type::regular);
+ auto new_file = fs->create_inode(new_directory.value(), "blub_file", kapi::filesystem::file_type::regular);
REQUIRE(new_file);
- auto lookup_result = fs.lookup(new_directory.value(), "blub_file");
+ auto lookup_result = fs->lookup(new_directory.value(), "blub_file");
REQUIRE(lookup_result);
REQUIRE(lookup_result.value()->is_regular());
}
THEN("a file can be created and written to")
{
- auto new_inode = fs.create_inode(*root, "blub", kapi::filesystem::file_type::regular);
+ auto new_inode = fs->create_inode(root, "blub", kapi::filesystem::file_type::regular);
REQUIRE(new_inode);
auto buffer =
@@ -162,7 +165,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture,
THEN("a symbolic link is not implemented yet")
{
- REQUIRE_THROWS_AS(fs.create_inode(*root, "blub", kapi::filesystem::file_type::symbolic_link),
+ REQUIRE_THROWS_AS(fs->create_inode(root, "blub", kapi::filesystem::file_type::symbolic_link),
kernel::tests::cpu::halt);
}
}
@@ -178,11 +181,11 @@ SCENARIO("Ext2 filesystem rejects invalid magic", "[filesystem][ext2][filesystem
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
- auto fs = kernel::filesystem::ext2::filesystem{};
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
THEN("mount fails with invalid_magic_number")
{
- REQUIRE(fs.mount(dev_inode).error() == kernel::filesystem::ext2::ext2_errc::invalid_magic_number);
+ REQUIRE(fs->mount(dev_inode).error() == kernel::filesystem::ext2::ext2_errc::invalid_magic_number);
}
}
}
@@ -200,8 +203,8 @@ SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesys
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode));
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ REQUIRE(fs->mount(dev_inode));
auto inode_data = kernel::filesystem::ext2::inode_data{};
inode_data.block[0] = 7;
@@ -225,16 +228,16 @@ SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesys
THEN("mapping resolves direct, singly, doubly and triply indirect indexes")
{
- REQUIRE(fs.map_inode_block_index_to_global_block_number(0, inode_data) == 7);
- REQUIRE(fs.map_inode_block_index_to_global_block_number(singly_start, inode_data) == 31);
- REQUIRE(fs.map_inode_block_index_to_global_block_number(doubly_start, inode_data) == 42);
- REQUIRE(fs.map_inode_block_index_to_global_block_number(triply_start, inode_data) == 53);
+ REQUIRE(fs->map_inode_block_index_to_global_block_number(0, inode_data) == 7);
+ REQUIRE(fs->map_inode_block_index_to_global_block_number(singly_start, inode_data) == 31);
+ REQUIRE(fs->map_inode_block_index_to_global_block_number(doubly_start, inode_data) == 42);
+ REQUIRE(fs->map_inode_block_index_to_global_block_number(triply_start, inode_data) == 53);
}
THEN("mapping returns error for out-of-range indexes")
{
auto const beyond_triply = triply_start + numbers_per_block * numbers_per_block * numbers_per_block;
- REQUIRE(!fs.map_inode_block_index_to_global_block_number(beyond_triply, inode_data));
+ REQUIRE(!fs->map_inode_block_index_to_global_block_number(beyond_triply, inode_data));
}
}
}
@@ -272,8 +275,8 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys
kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device, superblock, block_group_descriptor);
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode));
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ REQUIRE(fs->mount(dev_inode));
auto read_u32 = [&](kstd::bytes offset) -> uint32_t {
auto value = uint32_t{0};
@@ -295,26 +298,26 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys
constexpr auto doubly_global_block_number = 303;
constexpr auto triply_global_block_number = 404;
- REQUIRE(fs.write_global_block_number_to_inode_block_index(0, inode_data, direct_global_block_number));
+ REQUIRE(fs->write_global_block_number_to_inode_block_index(0, inode_data, direct_global_block_number));
REQUIRE(inode_data.block[0] == direct_global_block_number);
- REQUIRE(fs.write_global_block_number_to_inode_block_index(singly_start, inode_data, singly_global_block_number));
+ REQUIRE(fs->write_global_block_number_to_inode_block_index(singly_start, inode_data, singly_global_block_number));
REQUIRE(inode_data.block[12] == 16);
REQUIRE(read_u32(static_cast<kstd::bytes>(inode_data.block[12]) * block_size.value) ==
singly_global_block_number);
- REQUIRE(fs.write_global_block_number_to_inode_block_index(singly_start + 1, inode_data,
- singly_global_block_number + 1));
+ REQUIRE(fs->write_global_block_number_to_inode_block_index(singly_start + 1, inode_data,
+ singly_global_block_number + 1));
REQUIRE(read_u32(static_cast<kstd::bytes>(inode_data.block[12]) * block_size.value +
1 * kstd::size_of<uint32_t>()) == singly_global_block_number + 1);
- REQUIRE(fs.write_global_block_number_to_inode_block_index(doubly_start, inode_data, doubly_global_block_number));
+ REQUIRE(fs->write_global_block_number_to_inode_block_index(doubly_start, inode_data, doubly_global_block_number));
REQUIRE(inode_data.block[13] == 17);
auto const doubly_leaf_table = read_u32(static_cast<size_t>(inode_data.block[13]) * block_size);
REQUIRE(doubly_leaf_table == 18);
REQUIRE(read_u32(static_cast<size_t>(doubly_leaf_table) * block_size) == doubly_global_block_number);
- REQUIRE(fs.write_global_block_number_to_inode_block_index(triply_start, inode_data, triply_global_block_number));
+ REQUIRE(fs->write_global_block_number_to_inode_block_index(triply_start, inode_data, triply_global_block_number));
REQUIRE(inode_data.block[14] == 19);
auto const triply_middle_table = read_u32(static_cast<size_t>(inode_data.block[14]) * block_size);
REQUIRE(triply_middle_table == 20);
@@ -322,10 +325,10 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys
REQUIRE(triply_leaf_table == 21);
REQUIRE(read_u32(static_cast<size_t>(triply_leaf_table) * block_size) == triply_global_block_number);
- REQUIRE(fs.map_inode_block_index_to_global_block_number(0, inode_data) == direct_global_block_number);
- REQUIRE(fs.map_inode_block_index_to_global_block_number(singly_start, inode_data) == singly_global_block_number);
- REQUIRE(fs.map_inode_block_index_to_global_block_number(doubly_start, inode_data) == doubly_global_block_number);
- REQUIRE(fs.map_inode_block_index_to_global_block_number(triply_start, inode_data) == triply_global_block_number);
+ REQUIRE(fs->map_inode_block_index_to_global_block_number(0, inode_data) == direct_global_block_number);
+ REQUIRE(fs->map_inode_block_index_to_global_block_number(singly_start, inode_data) == singly_global_block_number);
+ REQUIRE(fs->map_inode_block_index_to_global_block_number(doubly_start, inode_data) == doubly_global_block_number);
+ REQUIRE(fs->map_inode_block_index_to_global_block_number(triply_start, inode_data) == triply_global_block_number);
}
}
}
diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp
index 8da80191..5e80f40b 100644
--- a/kernel/kernel/filesystem/ext2/inode.cpp
+++ b/kernel/kernel/filesystem/ext2/inode.cpp
@@ -1,12 +1,15 @@
#include <kernel/filesystem/ext2/inode.hpp>
+#include <kernel/filesystem/error.hpp>
#include <kernel/filesystem/ext2/filesystem.hpp>
#include <kernel/filesystem/inode.hpp>
+#include <kernel/filesystem/mount.hpp>
#include <kapi/filesystem.hpp>
#include <kapi/system.hpp>
#include <kstd/cstring.hpp>
+#include <kstd/memory.hpp>
#include <kstd/result.hpp>
#include <kstd/units.hpp>
@@ -20,16 +23,10 @@ using namespace kstd::units_literals;
namespace kernel::filesystem::ext2
{
- inode::inode(filesystem * fs, uint32_t inode_number, inode_data const & data)
- : m_filesystem(fs)
- , m_inode_number(inode_number)
+ inode::inode(uint32_t inode_number, inode_data const & data)
+ : m_inode_number(inode_number)
, m_data(data)
- {
- if (!m_filesystem)
- {
- kapi::system::panic("[EXT2] ext2::inode constructed with filesystem null pointer");
- }
- }
+ {}
auto inode::read(std::span<std::byte> buffer, kstd::bytes offset) const -> kstd::result<kstd::bytes>
{
@@ -43,20 +40,26 @@ namespace kernel::filesystem::ext2
return requested_size;
}
- auto block_index = offset / m_filesystem->block_size();
- auto in_block_offset = offset % m_filesystem->block_size();
+ auto filesystem = get_filesystem();
+ if (!filesystem)
+ {
+ return kstd::failure(filesystem.error());
+ }
+
+ auto block_index = offset / (*filesystem)->block_size();
+ auto in_block_offset = offset % (*filesystem)->block_size();
auto bytes_read = 0_B;
while (bytes_read < requested_size)
{
- auto const block_number = m_filesystem->map_inode_block_index_to_global_block_number(block_index, m_data);
+ auto const block_number = (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data);
if (!block_number)
{
break;
}
- auto const bytes_to_read = std::min(requested_size - bytes_read, m_filesystem->block_size() - in_block_offset);
+ auto const bytes_to_read = std::min(requested_size - bytes_read, (*filesystem)->block_size() - in_block_offset);
if (block_number == 0)
{
kstd::libc::memset(buffer.data() + bytes_read, 0, bytes_to_read.value);
@@ -64,10 +67,10 @@ namespace kernel::filesystem::ext2
}
else
{
- auto const block_start_offset = block_number.value() * m_filesystem->block_size();
+ auto const block_start_offset = block_number.value() * (*filesystem)->block_size();
auto const read_offset = block_start_offset + in_block_offset;
auto const read_result =
- m_filesystem->backing_inode()->read(buffer.subspan(bytes_read.value, bytes_to_read.value), read_offset);
+ (*filesystem)->backing_inode()->read(buffer.subspan(bytes_read.value, bytes_to_read.value), read_offset);
if (!read_result)
{
return kstd::failure(read_result.error());
@@ -95,14 +98,20 @@ namespace kernel::filesystem::ext2
auto const new_inode_size = std::max(this->size(), offset + kstd::bytes{buffer.size()});
- auto const current_block_count = m_filesystem->inode_block_count(m_data);
- auto const max_new_inode_size_without_new_blocks = current_block_count * m_filesystem->block_size();
+ auto filesystem = get_filesystem();
+ if (!filesystem)
+ {
+ return kstd::failure(filesystem.error());
+ }
+
+ auto const current_block_count = (*filesystem)->inode_block_count(m_data);
+ auto const max_new_inode_size_without_new_blocks = current_block_count * (*filesystem)->block_size();
if (new_inode_size > max_new_inode_size_without_new_blocks)
{
auto const additional_blocks_needed =
- (new_inode_size - max_new_inode_size_without_new_blocks + m_filesystem->block_size() - 1_B) /
- m_filesystem->block_size();
+ (new_inode_size - max_new_inode_size_without_new_blocks + (*filesystem)->block_size() - 1_B) /
+ (*filesystem)->block_size();
if (!append_blocks(additional_blocks_needed))
{
@@ -111,14 +120,14 @@ namespace kernel::filesystem::ext2
}
}
- auto block_index = offset / m_filesystem->block_size();
- auto in_block_offset = offset % m_filesystem->block_size();
+ auto block_index = offset / (*filesystem)->block_size();
+ auto in_block_offset = offset % (*filesystem)->block_size();
auto bytes_written = 0_B;
while (bytes_written < kstd::bytes{buffer.size()})
{
- auto const block_number = m_filesystem->map_inode_block_index_to_global_block_number(block_index, m_data);
+ auto const block_number = (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data);
// TODO BA-FS26 if blocknumber == 0 --> handle sparse file
if (!block_number)
{
@@ -126,13 +135,14 @@ namespace kernel::filesystem::ext2
}
auto const bytes_to_write =
- std::min(kstd::bytes{buffer.size()} - bytes_written, m_filesystem->block_size() - in_block_offset);
+ std::min(kstd::bytes{buffer.size()} - bytes_written, (*filesystem)->block_size() - in_block_offset);
- auto const block_start_offset = block_number.value() * m_filesystem->block_size();
+ auto const block_start_offset = block_number.value() * (*filesystem)->block_size();
auto const write_offset = block_start_offset + in_block_offset;
- auto const write_result =
- m_filesystem->backing_inode()->write(buffer.subspan(bytes_written.value, bytes_to_write.value), write_offset);
+ auto const write_result = (*filesystem)
+ ->backing_inode()
+ ->write(buffer.subspan(bytes_written.value, bytes_to_write.value), write_offset);
if (!write_result)
{
return kstd::failure(write_result.error());
@@ -145,7 +155,7 @@ namespace kernel::filesystem::ext2
}
set_size(std::max(this->size(), offset + bytes_written));
- if (auto write_result = m_filesystem->write_inode(m_inode_number, m_data); !write_result)
+ if (auto write_result = (*filesystem)->write_inode(m_inode_number, m_data); !write_result)
{
return kstd::failure(write_result.error());
}
@@ -155,7 +165,13 @@ namespace kernel::filesystem::ext2
auto inode::append_blocks(size_t count) -> bool
{
- auto new_blocks = m_filesystem->allocate_blocks(count);
+ auto filesystem = get_filesystem();
+ if (!filesystem)
+ {
+ return false;
+ }
+
+ auto new_blocks = (*filesystem)->allocate_blocks(count);
if (!new_blocks)
{
return false;
@@ -163,18 +179,18 @@ namespace kernel::filesystem::ext2
for (auto i = 0uz; i < new_blocks->size(); ++i)
{
- auto const block_index = m_filesystem->inode_block_count(m_data) + i;
+ auto const block_index = (*filesystem)->inode_block_count(m_data) + i;
auto const global_block_number = new_blocks->at(i);
if (auto write_result =
- m_filesystem->write_global_block_number_to_inode_block_index(block_index, m_data, global_block_number);
+ (*filesystem)->write_global_block_number_to_inode_block_index(block_index, m_data, global_block_number);
!write_result)
{
return false;
}
}
- m_filesystem->update_inode_block_count(m_data, count);
+ (*filesystem)->update_inode_block_count(m_data, count);
return true;
}
@@ -248,7 +264,13 @@ namespace kernel::filesystem::ext2
{
uint64_t size = m_data.size;
- if (m_filesystem->revision_level() > constants::good_old_revision && is_regular())
+ auto filesystem = get_filesystem();
+ if (!filesystem)
+ {
+ return 0_B;
+ }
+
+ if ((*filesystem)->revision_level() > constants::good_old_revision && is_regular())
{
size |= static_cast<uint64_t>(m_data.dir_acl) << 32;
}
@@ -258,7 +280,13 @@ namespace kernel::filesystem::ext2
auto inode::set_size(kstd::bytes new_size) -> void
{
- if (m_filesystem->revision_level() > constants::good_old_revision && is_regular())
+ auto filesystem = get_filesystem();
+ if (!filesystem)
+ {
+ return;
+ }
+
+ if ((*filesystem)->revision_level() > constants::good_old_revision && is_regular())
{
m_data.dir_acl = static_cast<uint32_t>(new_size.value >> 32);
}
@@ -270,4 +298,24 @@ namespace kernel::filesystem::ext2
return m_inode_number;
}
+ auto inode::get_filesystem() -> kstd::result<kstd::shared_ptr<filesystem>>
+ {
+ if (auto mount = owning_mount().lock())
+ {
+ return static_pointer_cast<filesystem>(mount->get_filesystem());
+ }
+
+ return kstd::failure(vfs_errc::not_mounted);
+ }
+
+ auto inode::get_filesystem() const -> kstd::result<kstd::shared_ptr<filesystem const>>
+ {
+ if (auto mount = owning_mount().lock())
+ {
+ return static_pointer_cast<filesystem>(mount->get_filesystem());
+ }
+
+ return kstd::failure(vfs_errc::not_mounted);
+ }
+
} // namespace kernel::filesystem::ext2
diff --git a/kernel/kernel/filesystem/ext2/inode.hpp b/kernel/kernel/filesystem/ext2/inode.hpp
index 61961f6c..41231cab 100644
--- a/kernel/kernel/filesystem/ext2/inode.hpp
+++ b/kernel/kernel/filesystem/ext2/inode.hpp
@@ -46,10 +46,9 @@ namespace kernel::filesystem::ext2
{
//! Create an ext2 inode associated with the given filesystem.
//!
- //! @param fs The ext2 filesystem that this inode belongs to.
//! @param inode_number The inode number on disk.
//! @param data The data associated with this inode, read from the disk.
- explicit inode(filesystem * fs, uint32_t inode_number, inode_data const & data);
+ explicit inode(uint32_t inode_number, inode_data const & data);
[[nodiscard]] auto read(std::span<std::byte> buffer, kstd::bytes offset) const
-> kstd::result<kstd::bytes> override;
@@ -102,8 +101,10 @@ namespace kernel::filesystem::ext2
[[nodiscard]] auto number() const -> uint32_t;
private:
- //! The filesystem this inode belongs to.
- filesystem * m_filesystem;
+ [[nodiscard]] auto get_filesystem() -> kstd::result<kstd::shared_ptr<filesystem>>;
+
+ [[nodiscard]] auto get_filesystem() const -> kstd::result<kstd::shared_ptr<filesystem const>>;
+
//! The inode number on disk.
uint32_t m_inode_number{};
//! The inode data.
diff --git a/kernel/kernel/filesystem/ext2/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp
index d110c16a..ecfc76ba 100644
--- a/kernel/kernel/filesystem/ext2/inode.tests.cpp
+++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp
@@ -6,6 +6,7 @@
#include <kernel/filesystem/ext2/filesystem.hpp>
#include <kernel/filesystem/ext2/superblock.hpp>
#include <kernel/filesystem/filesystem.hpp>
+#include <kernel/filesystem/mount.hpp>
#include <kernel/test_support/cpu.hpp>
#include <kernel/test_support/devices/block_device.hpp>
#include <kernel/test_support/filesystem/ext2.hpp>
@@ -42,7 +43,7 @@ SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]"
THEN("the inode is initialized with regular file mode in data and has the kind regular")
{
data.mode = kernel::filesystem::ext2::constants::mode_regular;
- auto inode = kernel::filesystem::ext2::inode(&fs, 42, data);
+ auto inode = kernel::filesystem::ext2::inode(42, data);
REQUIRE(inode.is_regular());
REQUIRE_FALSE(inode.is_directory());
@@ -53,7 +54,7 @@ SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]"
THEN("the inode is initialized with directory mode in data and has the kind directory")
{
data.mode = kernel::filesystem::ext2::constants::mode_directory;
- auto inode = kernel::filesystem::ext2::inode(&fs, 42, data);
+ auto inode = kernel::filesystem::ext2::inode(42, data);
REQUIRE_FALSE(inode.is_regular());
REQUIRE(inode.is_directory());
@@ -64,7 +65,7 @@ SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]"
THEN("the inode is initialized with symbolic link mode in data and has the kind symbolic link")
{
data.mode = kernel::filesystem::ext2::constants::mode_symbolic_link;
- auto inode = kernel::filesystem::ext2::inode(&fs, 42, data);
+ auto inode = kernel::filesystem::ext2::inode(42, data);
REQUIRE_FALSE(inode.is_regular());
REQUIRE_FALSE(inode.is_directory());
@@ -75,7 +76,7 @@ SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]"
THEN("the inode is initialized with zero mode in data and has no specific kind")
{
data.mode = 0;
- auto inode = kernel::filesystem::ext2::inode(&fs, 42, data);
+ auto inode = kernel::filesystem::ext2::inode(42, data);
REQUIRE_FALSE(inode.is_regular());
REQUIRE_FALSE(inode.is_directory());
@@ -83,14 +84,6 @@ SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]"
REQUIRE_FALSE(inode.is_symbolic_link());
}
}
-
- GIVEN("no filesystem (null pointer)")
- {
- THEN("constructing an inode with a null filesystem pointer panics")
- {
- REQUIRE_THROWS_AS(kernel::filesystem::ext2::inode(nullptr, 42, {}), kernel::tests::cpu::halt);
- }
- }
}
SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 inode reads from real image",
@@ -108,13 +101,14 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(boot_device);
- auto fs = kernel::filesystem::ext2::filesystem{};
- auto root = fs.mount(dev_inode);
- REQUIRE(root);
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode);
+ auto root = (*mount)->root_dentry()->get_inode();
+ REQUIRE(mount);
- auto information = fs.lookup(*root, "information");
+ auto information = fs->lookup(root, "information");
REQUIRE(information);
- auto file = fs.lookup(*information, "info_1.txt");
+ auto file = fs->lookup(*information, "info_1.txt");
REQUIRE(file);
REQUIRE(file.value()->is_regular());
@@ -151,8 +145,10 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode));
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode);
+ auto root = (*mount)->root_dentry()->get_inode();
+ REQUIRE(mount);
auto data = kernel::filesystem::ext2::inode_data{};
data.block[0] = 30;
@@ -163,7 +159,8 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste
kernel::tests::filesystem::ext2::write_bytes(*device, 30 * block_size, "Hello", 5_B);
kernel::tests::filesystem::ext2::write_bytes(*device, 31 * block_size, "World!", 6_B);
- auto inode = kernel::filesystem::ext2::inode{&fs, 42, data};
+ auto inode = kernel::filesystem::ext2::inode{42, data};
+ inode.set_owning_mount(*mount);
auto buffer = kstd::vector<std::byte>(data.size, std::byte{0xAB});
@@ -189,8 +186,10 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode));
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode);
+ auto root = (*mount)->root_dentry()->get_inode();
+ REQUIRE(mount);
auto data = kernel::filesystem::ext2::inode_data{};
data.block[0] = 30;
@@ -205,7 +204,8 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste
kernel::tests::filesystem::ext2::write_bytes(*device, 50 * block_size, "Blub", 4_B);
kernel::tests::filesystem::ext2::write_bytes(*device, 51 * block_size, "World!", 6_B);
- auto inode = kernel::filesystem::ext2::inode{&fs, 42, data};
+ auto inode = kernel::filesystem::ext2::inode{42, data};
+ inode.set_owning_mount(*mount);
auto buffer = kstd::vector<std::byte>(data.size, std::byte{0xAB});
@@ -234,14 +234,17 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode));
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode);
+ auto root = (*mount)->root_dentry()->get_inode();
+ REQUIRE(mount);
auto data = kernel::filesystem::ext2::inode_data{};
data.block[12] = 0;
data.size = block_size.value * 15;
- auto inode = kernel::filesystem::ext2::inode{&fs, 42, data};
+ auto inode = kernel::filesystem::ext2::inode{42, data};
+ inode.set_owning_mount(*mount);
auto buffer = kstd::vector<std::byte>(block_size.value * 15, std::byte{0xAB});
@@ -265,8 +268,10 @@ SCENARIO("Ext2 inode read across block boundaries", "[filesystem][ext2][inode]")
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode));
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode);
+ auto root = (*mount)->root_dentry()->get_inode();
+ REQUIRE(mount);
auto inode_data = kernel::filesystem::ext2::inode_data{};
inode_data.size = block_size.value * 2;
@@ -274,7 +279,8 @@ SCENARIO("Ext2 inode read across block boundaries", "[filesystem][ext2][inode]")
kernel::tests::filesystem::ext2::write_bytes(*device, 21 * block_size - 6_B, "Hello ", 6_B);
inode_data.block[1] = 21;
kernel::tests::filesystem::ext2::write_bytes(*device, 21 * block_size, "World!", 6_B);
- auto inode = kernel::filesystem::ext2::inode{&fs, 42, inode_data};
+ auto inode = kernel::filesystem::ext2::inode{42, inode_data};
+ inode.set_owning_mount(*mount);
auto buffer = kstd::vector<std::byte>(12, std::byte{0x00});
@@ -303,13 +309,14 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(boot_device);
- auto fs = kernel::filesystem::ext2::filesystem{};
- auto root = fs.mount(dev_inode);
- REQUIRE(root);
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode);
+ auto root = (*mount)->root_dentry()->get_inode();
+ REQUIRE(mount);
- auto information = fs.lookup(*root, "information");
+ auto information = fs->lookup(root, "information");
REQUIRE(information);
- auto file = fs.lookup(*information, "info_1.txt");
+ auto file = fs->lookup(*information, "info_1.txt");
REQUIRE(file);
REQUIRE(file.value()->is_regular());
@@ -337,8 +344,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in
{
auto inode_data = static_cast<kernel::filesystem::ext2::inode *>(file.value().get())->data();
- auto const block_size = fs.block_size();
- auto const expected_allocated_blocks = 32 * fs.inode_block_count(inode_data);
+ auto const block_size = fs->block_size();
+ auto const expected_allocated_blocks = 32 * fs->inode_block_count(inode_data);
auto write_buffer = kstd::vector<std::byte>(block_size.value * expected_allocated_blocks, std::byte{'A'});
@@ -352,7 +359,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in
auto new_inode_data = static_cast<kernel::filesystem::ext2::inode *>(file.value().get())->data();
REQUIRE(new_inode_data.size == write_buffer.size());
- REQUIRE(fs.inode_block_count(new_inode_data) == expected_allocated_blocks);
+ REQUIRE(fs->inode_block_count(new_inode_data) == expected_allocated_blocks);
}
THEN("writing to a an inode of type directory panics")
@@ -396,8 +403,10 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]"
REQUIRE(dev_inode->write(block_bitmap, block_group_descriptor.block_bitmap * block_size));
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode));
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode);
+ auto root = (*mount)->root_dentry()->get_inode();
+ REQUIRE(mount);
auto inode_data = kernel::filesystem::ext2::inode_data{};
inode_data.size = 5;
@@ -407,9 +416,11 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]"
inode_data.mode = kernel::filesystem::ext2::constants::mode_regular;
uint32_t inode_number = 3;
- auto const inode_data_offset = block_group_descriptor.inode_table * block_size + (inode_number - 1) * fs.inode_size();
+ auto const inode_data_offset =
+ block_group_descriptor.inode_table * block_size + (inode_number - 1) * fs->inode_size();
- auto inode = kernel::filesystem::ext2::inode{&fs, inode_number, inode_data};
+ auto inode = kernel::filesystem::ext2::inode{inode_number, inode_data};
+ inode.set_owning_mount(*mount);
REQUIRE(dev_inode->write(as_bytes(std::span{&inode, 1}), inode_data_offset));
auto const buffer =
@@ -421,7 +432,8 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]"
auto do_read_inode = [&]() {
auto inode_data = kernel::filesystem::ext2::inode_data{};
REQUIRE(dev_inode->read(as_writable_bytes(std::span{&inode_data, 1}), inode_data_offset));
- auto read_inode = kernel::filesystem::ext2::inode{&fs, inode_number, inode_data};
+ auto read_inode = kernel::filesystem::ext2::inode{inode_number, inode_data};
+ read_inode.set_owning_mount(*mount);
return read_inode;
};
@@ -530,8 +542,10 @@ SCENARIO("Ext2 inode get_size() and set_size() handles size correctly depending
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode));
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode);
+ auto root = (*mount)->root_dentry()->get_inode();
+ REQUIRE(mount);
auto data = kernel::filesystem::ext2::inode_data{};
data.size = 256;
@@ -541,7 +555,8 @@ SCENARIO("Ext2 inode get_size() and set_size() handles size correctly depending
uint32_t expected_dir_acl_after_set_size) {
data.mode = mode;
- auto inode = kernel::filesystem::ext2::inode{&fs, 42, data};
+ auto inode = kernel::filesystem::ext2::inode{42, data};
+ inode.set_owning_mount(*mount);
REQUIRE(inode.size() == expected_initial_size);
@@ -573,8 +588,10 @@ SCENARIO("Ext2 inode get_size() and set_size() handles size correctly depending
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode));
+ auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
+ auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode);
+ auto root = (*mount)->root_dentry()->get_inode();
+ REQUIRE(mount);
auto data = kernel::filesystem::ext2::inode_data{};
data.size = 256;
@@ -584,7 +601,8 @@ SCENARIO("Ext2 inode get_size() and set_size() handles size correctly depending
uint32_t expected_dir_acl_after_set_size) {
data.mode = mode;
- auto inode = kernel::filesystem::ext2::inode{&fs, 42, data};
+ auto inode = kernel::filesystem::ext2::inode{42, data};
+ inode.set_owning_mount(*mount);
REQUIRE(inode.size() == expected_initial_size);
@@ -617,7 +635,7 @@ SCENARIO("Ext2 inode status()", "[filesystem][ext2][inode]")
data.block[0] = (1 << 8);
data.links_count = 1;
- auto inode = kernel::filesystem::ext2::inode(&fs, 42, data);
+ auto inode = kernel::filesystem::ext2::inode(42, data);
THEN("status() reports the real inode number, link count, and decoded raw device")
{