Kernel: Add directory entry cache for ext2 inodes
This commit is contained in:
@@ -71,6 +71,10 @@ namespace Kernel
|
|||||||
private:
|
private:
|
||||||
Ext2Inode(Ext2FS& fs, Ext2::Inode inode, uint32_t ino);
|
Ext2Inode(Ext2FS& fs, Ext2::Inode inode, uint32_t ino);
|
||||||
|
|
||||||
|
BAN::RefPtr<Inode> dir_cache_find(BAN::StringView) const;
|
||||||
|
void dir_cache_remove(BAN::StringView);
|
||||||
|
void dir_cache_add(BAN::StringView, BAN::RefPtr<Inode>);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct ScopedSync
|
struct ScopedSync
|
||||||
{
|
{
|
||||||
@@ -105,6 +109,17 @@ namespace Kernel
|
|||||||
const uint32_t m_og_faddr;
|
const uint32_t m_og_faddr;
|
||||||
const Ext2::Osd2 m_og_osd2;
|
const Ext2::Osd2 m_og_osd2;
|
||||||
|
|
||||||
|
struct DirCacheEntry
|
||||||
|
{
|
||||||
|
mutable size_t freq { 0 };
|
||||||
|
BAN::RefPtr<Inode> inode;
|
||||||
|
size_t name_len { 0 };
|
||||||
|
char name[256];
|
||||||
|
};
|
||||||
|
static constexpr size_t dir_cache_size = 32;
|
||||||
|
mutable RWLock m_dir_cache_lock;
|
||||||
|
BAN::Vector<DirCacheEntry> m_dir_cache;
|
||||||
|
|
||||||
friend class Ext2FS;
|
friend class Ext2FS;
|
||||||
friend class BAN::RefPtr<Ext2Inode>;
|
friend class BAN::RefPtr<Ext2Inode>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -870,6 +870,8 @@ needs_new_block:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dir_cache_remove(name);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -926,6 +928,9 @@ needs_new_block:
|
|||||||
{
|
{
|
||||||
ASSERT(mode().ifdir());
|
ASSERT(mode().ifdir());
|
||||||
|
|
||||||
|
if (auto cached = dir_cache_find(file_name))
|
||||||
|
return cached;
|
||||||
|
|
||||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||||
|
|
||||||
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
|
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
|
||||||
@@ -941,11 +946,74 @@ 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(m_fs.open_inode(entry.inode)));
|
{
|
||||||
|
auto inode = BAN::RefPtr<Inode>(TRY(m_fs.open_inode(entry.inode)));
|
||||||
|
dir_cache_add(file_name, inode);
|
||||||
|
return inode;
|
||||||
|
}
|
||||||
entry_span = entry_span.slice(entry.rec_len);
|
entry_span = entry_span.slice(entry.rec_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return BAN::Error::from_errno(ENOENT);
|
return BAN::Error::from_errno(ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<Inode> Ext2Inode::dir_cache_find(BAN::StringView name) const
|
||||||
|
{
|
||||||
|
RWLockRDGuard _(m_dir_cache_lock);
|
||||||
|
for (const auto& cache : m_dir_cache)
|
||||||
|
{
|
||||||
|
if (!cache.inode || name != BAN::StringView(cache.name, cache.name_len))
|
||||||
|
continue;
|
||||||
|
BAN::atomic_add_fetch(cache.freq, 1);
|
||||||
|
return cache.inode;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ext2Inode::dir_cache_remove(BAN::StringView name)
|
||||||
|
{
|
||||||
|
RWLockWRGuard _(m_dir_cache_lock);
|
||||||
|
for (auto& cache : m_dir_cache)
|
||||||
|
{
|
||||||
|
if (!cache.inode || name != BAN::StringView(cache.name, cache.name_len))
|
||||||
|
continue;
|
||||||
|
cache.freq = 0;
|
||||||
|
cache.inode = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ext2Inode::dir_cache_add(BAN::StringView name, BAN::RefPtr<Inode> inode)
|
||||||
|
{
|
||||||
|
RWLockWRGuard _(m_dir_cache_lock);
|
||||||
|
|
||||||
|
if (m_dir_cache.empty() && m_dir_cache.resize(dir_cache_size).is_error())
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t min_freq = BAN::numeric_limits<size_t>::max();
|
||||||
|
size_t min_index = 0;
|
||||||
|
for (size_t i = 0; i < m_dir_cache.size(); i++)
|
||||||
|
{
|
||||||
|
const auto& cache = m_dir_cache[i];
|
||||||
|
if (cache.inode && name == BAN::StringView(cache.name, cache.name_len))
|
||||||
|
{
|
||||||
|
ASSERT(cache.inode == inode);
|
||||||
|
cache.freq++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cache.freq < min_freq)
|
||||||
|
{
|
||||||
|
min_freq = cache.freq;
|
||||||
|
min_index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& cache = m_dir_cache[min_index];
|
||||||
|
cache.freq = 1;
|
||||||
|
cache.inode = inode;
|
||||||
|
cache.name_len = name.size();
|
||||||
|
memcpy(cache.name, name.data(), name.size());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user