Преглед на файлове

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.
Andreas Kling преди 5 години
родител
ревизия
59c052a72a
променени са 1 файла, в които са добавени 34 реда и са изтрити 23 реда
  1. 34 23
      Kernel/FileSystem/Ext2FileSystem.cpp

+ 34 - 23
Kernel/FileSystem/Ext2FileSystem.cpp

@@ -395,6 +395,14 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in
 }
 
 Vector<Ext2FS::BlockIndex> 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::BlockIndex> 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::BlockIndex> Ext2FS::block_list_for_inode(const ext2_inode& e2inod
 
     unsigned blocks_remaining = block_count;
     Vector<BlockIndex> 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::BlockIndex> 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::BlockIndex> Ext2FS::block_list_for_inode(const ext2_inode& e2inod
         ASSERT(array_block);
         auto* array = reinterpret_cast<const __u32*>(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);