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<uint32_t> reserve_free_block(uint32_t primary_bgd);
BAN::ErrorOr<void> release_block(uint32_t block); 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; } const Ext2::Superblock& superblock() const { return m_superblock; }
@@ -155,6 +156,7 @@ namespace Kernel
BAN::RefPtr<Inode> m_root_inode; BAN::RefPtr<Inode> m_root_inode;
BAN::Vector<uint32_t> m_superblock_backups; BAN::Vector<uint32_t> m_superblock_backups;
Mutex m_inode_cache_lock;
BAN::HashMap<ino_t, BAN::RefPtr<Ext2Inode>> m_inode_cache; BAN::HashMap<ino_t, BAN::RefPtr<Ext2Inode>> m_inode_cache;
BlockBufferManager m_buffer_manager; BlockBufferManager m_buffer_manager;

View File

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

View File

@@ -167,10 +167,36 @@ namespace Kernel
BAN::ErrorOr<void> Ext2FS::initialize_root_inode() 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 {}; 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) BAN::ErrorOr<uint32_t> Ext2FS::create_inode(const Ext2::Inode& ext2_inode)
{ {
auto bgd_buffer = TRY(m_buffer_manager.get_buffer()); 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; 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() Ext2Inode::~Ext2Inode()
{ {
if (m_nlink > 0) 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))); 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()) if (inode_or_error.is_error())
{ {
TRY(m_fs.delete_inode(new_ino)); 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))); 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()) if (inode_or_error.is_error())
{ {
TRY(m_fs.delete_inode(new_ino)); TRY(m_fs.delete_inode(new_ino));
@@ -814,7 +796,7 @@ needs_new_block:
} }
else if (entry_name == ".."_sv) 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--; parent->m_nlink--;
TRY(parent->sync_inode_no_lock()); TRY(parent->sync_inode_no_lock());
} }
@@ -860,7 +842,7 @@ needs_new_block:
auto& entry = block_buffer.span().slice(offset).as<Ext2::LinkedDirectoryEntry>(); auto& entry = block_buffer.span().slice(offset).as<Ext2::LinkedDirectoryEntry>();
if (entry.inode && name == BAN::StringView(entry.name, entry.name_len)) 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 (cleanup_directory && inode->mode().ifdir())
{ {
if (!TRY(inode->is_directory_empty_no_lock())) 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 // NOTE: If this was the last link to inode we must
// remove it from inode cache to trigger cleanup // remove it from inode cache to trigger cleanup
if (inode->nlink() == 0) if (inode->nlink() == 0)
{ m_fs.remove_from_cache(inode->ino());
auto& cache = m_fs.inode_cache();
if (cache.contains(inode->ino()))
cache.remove(inode->ino());
}
// FIXME: This should expand the last inode if exists // FIXME: This should expand the last inode if exists
entry.inode = 0; entry.inode = 0;
@@ -963,7 +941,7 @@ needs_new_block:
auto& entry = entry_span.as<const Ext2::LinkedDirectoryEntry>(); auto& entry = entry_span.as<const Ext2::LinkedDirectoryEntry>();
BAN::StringView entry_name(entry.name, entry.name_len); BAN::StringView entry_name(entry.name, entry.name_len);
if (entry.inode && entry_name == file_name) 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); entry_span = entry_span.slice(entry.rec_len);
} }
} }