From e0deb46723cff1fb44896d495fd13c47151606ce Mon Sep 17 00:00:00 2001 From: Mart G Date: Sat, 8 May 2021 18:28:54 +0200 Subject: [PATCH] Kernel: Traverse ext2 directories blockwise. Instead of reading in the entire contents of a directory into a large buffer, we can iterate block by block. This only requires a small buffer. Because directory entries are guaranteed to never span multiple blocks we do not have to handle any edge cases related to that. --- Kernel/FileSystem/Ext2FileSystem.cpp | 34 +++++++++++++++++++--------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/Kernel/FileSystem/Ext2FileSystem.cpp b/Kernel/FileSystem/Ext2FileSystem.cpp index 9a1f182eb0..a43dbfcb2e 100644 --- a/Kernel/FileSystem/Ext2FileSystem.cpp +++ b/Kernel/FileSystem/Ext2FileSystem.cpp @@ -1071,20 +1071,32 @@ KResult Ext2FSInode::traverse_as_directory(Function(buffer.data()); + auto block_size = fs().block_size(); + bool allow_cache = true; - while (entry < buffer.end_pointer()) { - if (entry->inode != 0) { - dbgln_if(EXT2_DEBUG, "Ext2FSInode[{}]::traverse_as_directory(): inode {}, name_len: {}, rec_len: {}, file_type: {}, name: {}", identifier(), entry->inode, entry->name_len, entry->rec_len, entry->file_type, StringView(entry->name, entry->name_len)); - if (!callback({ { entry->name, entry->name_len }, { fsid(), entry->inode }, entry->file_type })) - break; + if (m_block_list.is_empty()) + m_block_list = compute_block_list(); + + // Directory entries are guaranteed not to span multiple blocks, + // so we can iterate over blocks separately. + for (auto& block_index : m_block_list) { + VERIFY(block_index.value() != 0); + if (auto result = fs().read_block(block_index, &buf, block_size, 0, allow_cache); result.is_error()) { + return result; + } + auto* entry = reinterpret_cast(buffer); + auto* entries_end = reinterpret_cast(buffer + block_size); + while (entry < entries_end) { + if (entry->inode != 0) { + dbgln_if(EXT2_DEBUG, "Ext2FSInode[{}]::traverse_as_directory(): inode {}, name_len: {}, rec_len: {}, file_type: {}, name: {}", identifier(), entry->inode, entry->name_len, entry->rec_len, entry->file_type, StringView(entry->name, entry->name_len)); + if (!callback({ { entry->name, entry->name_len }, { fsid(), entry->inode }, entry->file_type })) + return KSuccess; + } + entry = (ext2_dir_entry_2*)((char*)entry + entry->rec_len); } - entry = (ext2_dir_entry_2*)((char*)entry + entry->rec_len); } return KSuccess;