1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 09:48:11 +00:00

Kernel/Ext2FS: Don't hog inode lock in traverse_as_directory()

Reimplement directory traversal in terms of read_bytes() instead of
doing direct block access. This lets us avoid taking the inode lock
while iterating over the directory contents.
This commit is contained in:
Andreas Kling 2021-07-16 02:39:41 +02:00
parent abbd237ec1
commit 41c0009f6d

View file

@ -1079,25 +1079,21 @@ Ext2FS::FeaturesReadOnly Ext2FS::get_features_readonly() const
KResult Ext2FSInode::traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)> callback) const KResult Ext2FSInode::traverse_as_directory(Function<bool(FileSystem::DirectoryEntryView const&)> callback) const
{ {
Locker locker(m_lock);
VERIFY(is_directory()); VERIFY(is_directory());
u8 buffer[max_block_size]; u8 buffer[max_block_size];
auto buf = UserOrKernelBuffer::for_kernel_buffer(buffer); auto buf = UserOrKernelBuffer::for_kernel_buffer(buffer);
auto block_size = fs().block_size(); auto block_size = fs().block_size();
bool allow_cache = true; auto file_size = size();
if (m_block_list.is_empty())
m_block_list = compute_block_list();
// Directory entries are guaranteed not to span multiple blocks, // Directory entries are guaranteed not to span multiple blocks,
// so we can iterate over blocks separately. // so we can iterate over blocks separately.
for (auto& block_index : m_block_list) {
VERIFY(block_index.value() != 0); for (u64 offset = 0; offset < file_size; offset += block_size) {
if (auto result = fs().read_block(block_index, &buf, block_size, 0, allow_cache); result.is_error()) { if (auto result = read_bytes(offset, block_size, buf, nullptr); result.is_error())
return result; return result.error();
}
auto* entry = reinterpret_cast<ext2_dir_entry_2*>(buffer); auto* entry = reinterpret_cast<ext2_dir_entry_2*>(buffer);
auto* entries_end = reinterpret_cast<ext2_dir_entry_2*>(buffer + block_size); auto* entries_end = reinterpret_cast<ext2_dir_entry_2*>(buffer + block_size);
while (entry < entries_end) { while (entry < entries_end) {