Kernel: Make ext2 inode cache thread safe
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user