From e16699ddf8fb7004c33c4f4e8ea065553c291a6c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 26 Jul 2026 14:08:36 +0200 Subject: kernel: fail early on removed device I/O --- kernel/kernel/filesystem/device_inode.cpp | 10 ++++ .../filesystem/open_file_descriptor.tests.cpp | 60 ++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/kernel/kernel/filesystem/device_inode.cpp b/kernel/kernel/filesystem/device_inode.cpp index 4dcff4a1..4696504e 100644 --- a/kernel/kernel/filesystem/device_inode.cpp +++ b/kernel/kernel/filesystem/device_inode.cpp @@ -41,6 +41,11 @@ namespace kernel::filesystem auto device_inode::read(void * buffer, kstd::units::bytes offset, kstd::units::bytes size) const -> kstd::result { + if (m_device->state() == kapi::devices::state::removed) + { + return kstd::failure(vfs_errc::no_such_device); + } + if (auto block_device = kapi::devices::facet_registry::get().resolve(*m_device)) { @@ -53,6 +58,11 @@ namespace kernel::filesystem auto device_inode::write(void const * buffer, kstd::units::bytes offset, kstd::units::bytes size) -> kstd::result { + if (m_device->state() == kapi::devices::state::removed) + { + return kstd::failure(vfs_errc::no_such_device); + } + if (auto block_device = kapi::devices::facet_registry::get().resolve(*m_device)) { diff --git a/kernel/kernel/filesystem/open_file_descriptor.tests.cpp b/kernel/kernel/filesystem/open_file_descriptor.tests.cpp index 6653ed86..b2d8fb17 100644 --- a/kernel/kernel/filesystem/open_file_descriptor.tests.cpp +++ b/kernel/kernel/filesystem/open_file_descriptor.tests.cpp @@ -1,13 +1,19 @@ #include +#include #include +#include #include #include #include +#include #include +#include + #include #include +#include #include #include @@ -19,6 +25,8 @@ using namespace kstd::units_literals; +// NOLINTBEGIN(readability-magic-numbers) + SCENARIO("Open file descriptor construction", "[filesystem][open_file_descriptor]") { GIVEN("a dentry and an open file descriptor for that dentry") @@ -136,3 +144,55 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Ope } } } + +SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Open file descriptor handles device removal", + "[filesystem][open_file_descriptor]") +{ + GIVEN("A file descriptor open on a bound, published devices") + { + setup_modules(1); + + auto device = kernel::devices::storage::determine_boot_device(); + REQUIRE(device); + + auto weak_reference = kstd::weak_ptr{device}; + + auto device_inode = kstd::make_shared(device); + auto dentry = kstd::make_shared(nullptr, device_inode, "ram0"); + auto fd = kstd::make_shared(dentry); + + device.reset(); + REQUIRE_FALSE(weak_reference.expired()); + + WHEN("the device is removed while the descriptor is still open") + { + auto locked = weak_reference.lock(); + REQUIRE(locked); + REQUIRE(kapi::devices::remove_device(*locked)); + locked.reset(); + + THEN("the device is kept alive through the file descriptor") + { + REQUIRE_FALSE(weak_reference.expired()); + } + + THEN("reading through the file descriptor fails with 'no such device'") + { + auto buffer = kstd::vector(10); + auto bytes_read = fd->read(buffer.data(), kstd::units::bytes{buffer.size()}); + + REQUIRE(bytes_read.error() == kstd::errc::no_such_device); + } + + THEN("writing through the file descriptor fails with 'no such device'") + { + auto buffer = kstd::vector(10); + auto bytes_written = fd->write(buffer.data(), kstd::units::bytes{buffer.size()}); + + REQUIRE(bytes_written.error() == kstd::errc::no_such_device); + } + } + } +} + +// NOLINTEND(readability-magic-numbers) \ No newline at end of file -- cgit v1.2.3