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.
This commit is contained in:
Andreas Kling 2019-11-03 10:22:09 +01:00
parent 3d239be7b4
commit c1d3ac7108
Notes: sideshowbarker 2024-07-19 11:27:25 +09:00

View file

@ -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<Inode> 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<Ext2FSInode&>(*inode).m_block_list = move(blocks);
return inode;
}
void Ext2FSInode::populate_lookup_cache() const