From 6a58c716bd29f4ad4515c25359b53274518bca16 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 21 May 2026 01:56:32 +0300 Subject: [PATCH] Kernel: Make ext2 inode cache thread safe --- kernel/include/kernel/FS/Ext2/FileSystem.h | 4 ++- kernel/include/kernel/FS/Ext2/Inode.h | 2 -- kernel/kernel/FS/Ext2/FileSystem.cpp | 28 +++++++++++++++++- kernel/kernel/FS/Ext2/Inode.cpp | 34 ++++------------------ 4 files changed, 36 insertions(+), 32 deletions(-) diff --git a/kernel/include/kernel/FS/Ext2/FileSystem.h b/kernel/include/kernel/FS/Ext2/FileSystem.h index 2f59d514..f0719f69 100644 --- a/kernel/include/kernel/FS/Ext2/FileSystem.h +++ b/kernel/include/kernel/FS/Ext2/FileSystem.h @@ -99,7 +99,8 @@ namespace Kernel BAN::ErrorOr reserve_free_block(uint32_t primary_bgd); BAN::ErrorOr release_block(uint32_t block); - BAN::HashMap>& inode_cache() { return m_inode_cache; } + BAN::ErrorOr> open_inode(ino_t); + void remove_from_cache(ino_t); const Ext2::Superblock& superblock() const { return m_superblock; } @@ -155,6 +156,7 @@ namespace Kernel BAN::RefPtr m_root_inode; BAN::Vector m_superblock_backups; + Mutex m_inode_cache_lock; BAN::HashMap> m_inode_cache; BlockBufferManager m_buffer_manager; diff --git a/kernel/include/kernel/FS/Ext2/Inode.h b/kernel/include/kernel/FS/Ext2/Inode.h index a0d941d5..e45795e7 100644 --- a/kernel/include/kernel/FS/Ext2/Inode.h +++ b/kernel/include/kernel/FS/Ext2/Inode.h @@ -71,8 +71,6 @@ namespace Kernel private: Ext2Inode(Ext2FS& fs, Ext2::Inode inode, uint32_t ino); - static BAN::ErrorOr> create(Ext2FS&, uint32_t); - private: struct ScopedSync { diff --git a/kernel/kernel/FS/Ext2/FileSystem.cpp b/kernel/kernel/FS/Ext2/FileSystem.cpp index 866feb63..920cfc75 100644 --- a/kernel/kernel/FS/Ext2/FileSystem.cpp +++ b/kernel/kernel/FS/Ext2/FileSystem.cpp @@ -167,10 +167,36 @@ namespace Kernel BAN::ErrorOr Ext2FS::initialize_root_inode() { - m_root_inode = TRY(Ext2Inode::create(*this, Ext2::Enum::ROOT_INO)); + m_root_inode = TRY(open_inode(Ext2::Enum::ROOT_INO)); return {}; } + BAN::ErrorOr> Ext2FS::open_inode(ino_t ino) + { + LockGuard _(m_inode_cache_lock); + + auto it = m_inode_cache.find(ino); + if (it != m_inode_cache.end()) + return it->value; + + auto inode_location = TRY(locate_inode(ino)); + + auto block_buffer = TRY(get_block_buffer()); + TRY(read_block(inode_location.block, block_buffer)); + + auto& inode = block_buffer.span().slice(inode_location.offset).as(); + + auto result = TRY(BAN::RefPtr::create(*this, inode, ino)); + TRY(m_inode_cache.insert(ino, result)); + return result; + } + + void Ext2FS::remove_from_cache(ino_t ino) + { + LockGuard _(m_inode_cache_lock); + m_inode_cache.remove(ino); + } + BAN::ErrorOr Ext2FS::create_inode(const Ext2::Inode& ext2_inode) { auto bgd_buffer = TRY(m_buffer_manager.get_buffer()); diff --git a/kernel/kernel/FS/Ext2/Inode.cpp b/kernel/kernel/FS/Ext2/Inode.cpp index a295f56b..a900f5c0 100644 --- a/kernel/kernel/FS/Ext2/Inode.cpp +++ b/kernel/kernel/FS/Ext2/Inode.cpp @@ -42,24 +42,6 @@ namespace Kernel return (m_ino - 1) / m_fs.superblock().blocks_per_group; } - BAN::ErrorOr> Ext2Inode::create(Ext2FS& fs, uint32_t inode_ino) - { - auto it = fs.inode_cache().find(inode_ino); - if (it != fs.inode_cache().end()) - return it->value; - - auto inode_location = TRY(fs.locate_inode(inode_ino)); - - auto block_buffer = TRY(fs.get_block_buffer()); - TRY(fs.read_block(inode_location.block, block_buffer)); - - auto& inode = block_buffer.span().slice(inode_location.offset).as(); - - auto result = TRY(BAN::RefPtr::create(fs, inode, inode_ino)); - TRY(fs.inode_cache().insert(inode_ino, result)); - return result; - } - Ext2Inode::~Ext2Inode() { if (m_nlink > 0) @@ -542,7 +524,7 @@ done: const uint32_t new_ino = TRY(m_fs.create_inode(initialize_new_inode_info(mode, uid, gid))); - auto inode_or_error = Ext2Inode::create(m_fs, new_ino); + auto inode_or_error = m_fs.open_inode(new_ino); if (inode_or_error.is_error()) { TRY(m_fs.delete_inode(new_ino)); @@ -568,7 +550,7 @@ done: const uint32_t new_ino = TRY(m_fs.create_inode(initialize_new_inode_info(mode, uid, gid))); - auto inode_or_error = Ext2Inode::create(m_fs, new_ino); + auto inode_or_error = m_fs.open_inode(new_ino); if (inode_or_error.is_error()) { TRY(m_fs.delete_inode(new_ino)); @@ -814,7 +796,7 @@ needs_new_block: } else if (entry_name == ".."_sv) { - auto parent = TRY(Ext2Inode::create(m_fs, entry.inode)); + auto parent = TRY(m_fs.open_inode(entry.inode)); parent->m_nlink--; TRY(parent->sync_inode_no_lock()); } @@ -860,7 +842,7 @@ needs_new_block: auto& entry = block_buffer.span().slice(offset).as(); if (entry.inode && name == BAN::StringView(entry.name, entry.name_len)) { - auto inode = TRY(Ext2Inode::create(m_fs, entry.inode)); + auto inode = TRY(m_fs.open_inode(entry.inode)); if (cleanup_directory && inode->mode().ifdir()) { if (!TRY(inode->is_directory_empty_no_lock())) @@ -878,11 +860,7 @@ needs_new_block: // NOTE: If this was the last link to inode we must // remove it from inode cache to trigger cleanup if (inode->nlink() == 0) - { - auto& cache = m_fs.inode_cache(); - if (cache.contains(inode->ino())) - cache.remove(inode->ino()); - } + m_fs.remove_from_cache(inode->ino()); // FIXME: This should expand the last inode if exists entry.inode = 0; @@ -963,7 +941,7 @@ needs_new_block: auto& entry = entry_span.as(); BAN::StringView entry_name(entry.name, entry.name_len); if (entry.inode && entry_name == file_name) - return BAN::RefPtr(TRY(Ext2Inode::create(m_fs, entry.inode))); + return BAN::RefPtr(TRY(m_fs.open_inode(entry.inode))); entry_span = entry_span.slice(entry.rec_len); } }