From 59c052a72adaffa7e1b8b01a48c1a9f3f44dd9ea Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 21 Feb 2020 17:48:50 +0100 Subject: [PATCH] Ext2FS: Allow holes in block lists Linux creates holes in block lists for all-zero content. This is very reasonable and we can now handle that situation as well. Note that we're not smart enough to generate these holes ourselves yet, but now we can at least read from such files. --- Kernel/FileSystem/Ext2FileSystem.cpp | 57 +++++++++++++++++----------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/Kernel/FileSystem/Ext2FileSystem.cpp b/Kernel/FileSystem/Ext2FileSystem.cpp index 5bfb9cd4aa..5e25dde67e 100644 --- a/Kernel/FileSystem/Ext2FileSystem.cpp +++ b/Kernel/FileSystem/Ext2FileSystem.cpp @@ -395,6 +395,14 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in } Vector Ext2FS::block_list_for_inode(const ext2_inode& e2inode, bool include_block_list_blocks) const +{ + auto block_list = block_list_for_inode_impl(e2inode, include_block_list_blocks); + while (!block_list.is_empty() && block_list.last() == 0) + block_list.take_last(); + return block_list; +} + +Vector Ext2FS::block_list_for_inode_impl(const ext2_inode& e2inode, bool include_block_list_blocks) const { LOCKER(m_lock); unsigned entries_per_block = EXT2_ADDR_PER_BLOCK(&super_block()); @@ -408,6 +416,14 @@ Vector Ext2FS::block_list_for_inode(const ext2_inode& e2inod unsigned blocks_remaining = block_count; Vector list; + + auto add_block = [&](BlockIndex bi) { + if (blocks_remaining) { + list.append(bi); + --blocks_remaining; + } + }; + if (include_block_list_blocks) { // This seems like an excessive over-estimate but w/e. list.ensure_capacity(blocks_remaining * 2); @@ -418,10 +434,7 @@ Vector Ext2FS::block_list_for_inode(const ext2_inode& e2inod unsigned direct_count = min(block_count, (unsigned)EXT2_NDIR_BLOCKS); for (unsigned i = 0; i < direct_count; ++i) { auto block_index = e2inode.i_block[i]; - if (!block_index) - return list; - list.unchecked_append(block_index); - --blocks_remaining; + add_block(block_index); } if (!blocks_remaining) @@ -435,36 +448,30 @@ Vector Ext2FS::block_list_for_inode(const ext2_inode& e2inod ASSERT(array_block); auto* array = reinterpret_cast(array_block.data()); unsigned count = min(blocks_remaining, entries_per_block); - for (unsigned i = 0; i < count; ++i) { - if (!array[i]) { - blocks_remaining = 0; - return; - } + for (BlockIndex i = 0; i < count; ++i) callback(array[i]); - --blocks_remaining; - } }; - process_block_array(e2inode.i_block[EXT2_IND_BLOCK], [&](unsigned entry) { - list.unchecked_append(entry); + process_block_array(e2inode.i_block[EXT2_IND_BLOCK], [&](unsigned block_index) { + add_block(block_index); }); if (!blocks_remaining) return list; - process_block_array(e2inode.i_block[EXT2_DIND_BLOCK], [&](unsigned entry) { - process_block_array(entry, [&](unsigned entry) { - list.unchecked_append(entry); + process_block_array(e2inode.i_block[EXT2_DIND_BLOCK], [&](unsigned block_index) { + process_block_array(block_index, [&](unsigned block_index2) { + add_block(block_index2); }); }); if (!blocks_remaining) return list; - process_block_array(e2inode.i_block[EXT2_TIND_BLOCK], [&](unsigned entry) { - process_block_array(entry, [&](unsigned entry) { - process_block_array(entry, [&](unsigned entry) { - list.unchecked_append(entry); + process_block_array(e2inode.i_block[EXT2_TIND_BLOCK], [&](unsigned block_index) { + process_block_array(block_index, [&](unsigned block_index2) { + process_block_array(block_index2, [&](unsigned block_index3) { + add_block(block_index3); }); }); }); @@ -487,8 +494,10 @@ void Ext2FS::free_inode(Ext2FSInode& inode) auto block_list = block_list_for_inode(inode.m_raw_inode, true); - for (auto block_index : block_list) - set_block_allocation_state(block_index, false); + for (auto block_index : block_list) { + if (block_index) + set_block_allocation_state(block_index, false); + } set_inode_allocation_state(inode.index(), false); @@ -729,7 +738,8 @@ KResult Ext2FSInode::resize(u64 new_size) #endif while (block_list.size() != blocks_needed_after) { auto block_index = block_list.take_last(); - fs().set_block_allocation_state(block_index, false); + if (block_index) + fs().set_block_allocation_state(block_index, false); } } @@ -1304,6 +1314,7 @@ Ext2FS::CachedBitmap& Ext2FS::get_bitmap_block(BlockIndex bitmap_block_index) bool Ext2FS::set_block_allocation_state(BlockIndex block_index, bool new_state) { + ASSERT(block_index != 0); LOCKER(m_lock); #ifdef EXT2_DEBUG dbgprintf("Ext2FS: set_block_allocation_state(block=%u, state=%u)\n", block_index, new_state);