From c1d3ac7108e2530b928f93d0dffe4d7a902f1f85 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 3 Nov 2019 10:22:09 +0100 Subject: [PATCH] Ext2FS: Fix unpopulated block list cache after mkdir() When creating a new directory, we set the initial size to 1 block. This meant that we were allocating a block up front, but the Inode's internal block list cache was not populated with this block. This broke write_bytes() on a new directory, since it assumed that the block list cache would be up to date if the call to write_bytes() would not change the directory's size. This patch fixes the issue in two ways: First, we cache the initial block list created for new directories. Second, we now repopulate the block list cache in write_bytes() if it is empty when we get there. This is basically just a safety fallback to avoid having this kind of bug in the future. --- Kernel/FileSystem/Ext2FileSystem.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Kernel/FileSystem/Ext2FileSystem.cpp b/Kernel/FileSystem/Ext2FileSystem.cpp index a1b4593480..5dd74d109c 100644 --- a/Kernel/FileSystem/Ext2FileSystem.cpp +++ b/Kernel/FileSystem/Ext2FileSystem.cpp @@ -607,11 +607,8 @@ ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes Locker fs_locker(fs().m_lock); - if (m_block_list.is_empty()) { - auto block_list = fs().block_list_for_inode(m_raw_inode); - if (m_block_list.size() != block_list.size()) - m_block_list = move(block_list); - } + if (m_block_list.is_empty()) + m_block_list = fs().block_list_for_inode(m_raw_inode); if (m_block_list.is_empty()) { kprintf("ext2fs: read_bytes: empty block list for inode %u\n", index()); @@ -735,6 +732,14 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, Fi if (resize_result.is_error()) return resize_result; + if (m_block_list.is_empty()) + m_block_list = fs().block_list_for_inode(m_raw_inode); + + if (m_block_list.is_empty()) { + dbg() << "Ext2FSInode::write_bytes(): empty block list for inode " << index(); + return -EIO; + } + int first_block_logical_index = offset / block_size; int last_block_logical_index = (offset + count) / block_size; if (last_block_logical_index >= m_block_list.size()) @@ -1391,7 +1396,10 @@ RefPtr Ext2FS::create_inode(InodeIdentifier parent_id, const String& name // We might have cached the fact that this inode didn't exist. Wipe the slate. m_inode_cache.remove(inode_id); - return get_inode({ fsid(), inode_id }); + auto inode = get_inode({ fsid(), inode_id }); + // If we've already computed a block list, no sense in throwing it away. + static_cast(*inode).m_block_list = move(blocks); + return inode; } void Ext2FSInode::populate_lookup_cache() const