Kernel: Make ext2 inode cache thread safe

This commit is contained in:
2026-05-21 01:56:32 +03:00
parent c295af9bd5
commit 6a58c716bd
4 changed files with 36 additions and 32 deletions

View File

@@ -99,7 +99,8 @@ namespace Kernel
BAN::ErrorOr<uint32_t> reserve_free_block(uint32_t primary_bgd);
BAN::ErrorOr<void> release_block(uint32_t block);
BAN::HashMap<ino_t, BAN::RefPtr<Ext2Inode>>& inode_cache() { return m_inode_cache; }
BAN::ErrorOr<BAN::RefPtr<Ext2Inode>> 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<Inode> m_root_inode;
BAN::Vector<uint32_t> m_superblock_backups;
Mutex m_inode_cache_lock;
BAN::HashMap<ino_t, BAN::RefPtr<Ext2Inode>> m_inode_cache;
BlockBufferManager m_buffer_manager;

View File

@@ -71,8 +71,6 @@ namespace Kernel
private:
Ext2Inode(Ext2FS& fs, Ext2::Inode inode, uint32_t ino);
static BAN::ErrorOr<BAN::RefPtr<Ext2Inode>> create(Ext2FS&, uint32_t);
private:
struct ScopedSync
{

View File

@@ -167,10 +167,36 @@ namespace Kernel
BAN::ErrorOr<void> 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<BAN::RefPtr<Ext2Inode>> 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<Ext2::Inode>();
auto result = TRY(BAN::RefPtr<Ext2Inode>::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<uint32_t> Ext2FS::create_inode(const Ext2::Inode& ext2_inode)
{
auto bgd_buffer = TRY(m_buffer_manager.get_buffer());

View File

@@ -42,24 +42,6 @@ namespace Kernel
return (m_ino - 1) / m_fs.superblock().blocks_per_group;
}
BAN::ErrorOr<BAN::RefPtr<Ext2Inode>> 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<Ext2::Inode>();
auto result = TRY(BAN::RefPtr<Ext2Inode>::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<Ext2::LinkedDirectoryEntry>();
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<const Ext2::LinkedDirectoryEntry>();
BAN::StringView entry_name(entry.name, entry.name_len);
if (entry.inode && entry_name == file_name)
return BAN::RefPtr<Inode>(TRY(Ext2Inode::create(m_fs, entry.inode)));
return BAN::RefPtr<Inode>(TRY(m_fs.open_inode(entry.inode)));
entry_span = entry_span.slice(entry.rec_len);
}
}