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<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;
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user