浏览代码

Ext2FS: Cache block bitmaps instead of always reading/writing disk

Add a simple cache to Ext2FS where we keep block bitmaps along with a
dirty bit. This allows us to coalesce bitmap flushes, giving us a nice
~3x improvement in disk_benchmark write speeds.
Andreas Kling 5 年之前
父节点
当前提交
1ae9d85de9
共有 2 个文件被更改,包括 52 次插入19 次删除
  1. 35 19
      Kernel/FileSystem/Ext2FileSystem.cpp
  2. 17 0
      Kernel/FileSystem/Ext2FileSystem.h

+ 35 - 19
Kernel/FileSystem/Ext2FileSystem.cpp

@@ -502,6 +502,15 @@ void Ext2FS::flush_writes()
         flush_block_group_descriptor_table();
         m_block_group_descriptors_dirty = false;
     }
+    for (auto& cached_bitmap : m_cached_bitmaps) {
+        if (cached_bitmap->dirty) {
+            write_block(cached_bitmap->bitmap_block_index, cached_bitmap->buffer.data());
+            cached_bitmap->dirty = false;
+#ifdef EXT2_DEBUG
+            dbg() << "Flushed bitmap block " << cached_bitmap->bitmap_block_index;
+#endif
+        }
+    }
     DiskBackedFS::flush_writes();
 }
 
@@ -1006,11 +1015,11 @@ Ext2FS::BlockIndex Ext2FS::allocate_block(GroupIndex preferred_group_index)
     }
     ASSERT(found_a_group);
     auto& bgd = group_descriptor(group_index);
+    auto& cached_bitmap = get_block_bitmap(bgd.bg_block_bitmap);
 
-    auto bitmap_block = ByteBuffer::create_uninitialized(block_size());
-    read_block(bgd.bg_block_bitmap, bitmap_block.data());
     int blocks_in_group = min(blocks_per_group(), super_block().s_blocks_count);
-    auto block_bitmap = Bitmap::wrap(bitmap_block.data(), blocks_in_group);
+    auto block_bitmap = Bitmap::wrap(cached_bitmap.buffer.data(), blocks_in_group);
+
     BlockIndex first_block_in_group = (group_index - 1) * blocks_per_group() + first_block_index();
     int first_unset_bit_index = block_bitmap.find_first_unset();
     ASSERT(first_unset_bit_index != -1);
@@ -1200,29 +1209,37 @@ Ext2FS::BlockIndex Ext2FS::first_block_index() const
     return block_size() == 1024 ? 1 : 0;
 }
 
+Ext2FS::CachedBitmap& Ext2FS::get_block_bitmap(BlockIndex bitmap_block_index)
+{
+    for (auto& cached_bitmap : m_cached_bitmaps) {
+        if (cached_bitmap->bitmap_block_index == bitmap_block_index)
+            return *cached_bitmap;
+    }
+
+    auto block = ByteBuffer::create_uninitialized(block_size());
+    bool success = read_block(bitmap_block_index, block.data());
+    ASSERT(success);
+    m_cached_bitmaps.append(make<CachedBitmap>(bitmap_block_index, move(block)));
+    return *m_cached_bitmaps.last();
+}
+
 bool Ext2FS::set_block_allocation_state(BlockIndex block_index, bool new_state)
 {
     LOCKER(m_lock);
 #ifdef EXT2_DEBUG
     dbgprintf("Ext2FS: set_block_allocation_state(block=%u, state=%u)\n", block_index, new_state);
 #endif
-    unsigned group_index = group_index_from_block_index(block_index);
+
+    GroupIndex group_index = group_index_from_block_index(block_index);
     auto& bgd = group_descriptor(group_index);
     BlockIndex index_in_group = (block_index - first_block_index()) - ((group_index - 1) * blocks_per_group());
     unsigned bit_index = index_in_group % blocks_per_group();
+
+    auto& cached_bitmap = get_block_bitmap(bgd.bg_block_bitmap);
+
+    bool current_state = cached_bitmap.bitmap(blocks_per_group()).get(bit_index);
 #ifdef EXT2_DEBUG
-    dbgprintf("  index_in_group: %u\n", index_in_group);
-    dbgprintf("  blocks_per_group: %u\n", blocks_per_group());
-    dbgprintf("  bit_index: %u\n", bit_index);
-    dbgprintf("  read_block(%u)\n", bgd.bg_block_bitmap);
-#endif
-    auto block = ByteBuffer::create_uninitialized(block_size());
-    bool success = read_block(bgd.bg_block_bitmap, block.data());
-    ASSERT(success);
-    auto bitmap = Bitmap::wrap(block.data(), blocks_per_group());
-    bool current_state = bitmap.get(bit_index);
-#ifdef EXT2_DEBUG
-    dbgprintf("Ext2FS: block %u state: %u -> %u\n", block_index, current_state, new_state);
+    dbgprintf("Ext2FS: block %u state: %u -> %u (in bitmap block %u)\n", block_index, current_state, new_state, bgd.bg_block_bitmap);
 #endif
 
     if (current_state == new_state) {
@@ -1230,9 +1247,8 @@ bool Ext2FS::set_block_allocation_state(BlockIndex block_index, bool new_state)
         return true;
     }
 
-    bitmap.set(bit_index, new_state);
-    success = write_block(bgd.bg_block_bitmap, block.data());
-    ASSERT(success);
+    cached_bitmap.bitmap(blocks_per_group()).set(bit_index, new_state);
+    cached_bitmap.dirty = true;
 
     // Update superblock
 #ifdef EXT2_DEBUG

+ 17 - 0
Kernel/FileSystem/Ext2FileSystem.h

@@ -1,5 +1,6 @@
 #pragma once
 
+#include <AK/Bitmap.h>
 #include <Kernel/FileSystem/DiskBackedFileSystem.h>
 #include <Kernel/FileSystem/Inode.h>
 #include <Kernel/FileSystem/ext2_fs.h>
@@ -135,6 +136,22 @@ private:
 
     bool m_super_block_dirty { false };
     bool m_block_group_descriptors_dirty { false };
+
+    struct CachedBitmap {
+        CachedBitmap(BlockIndex bi, ByteBuffer&& buf)
+            : bitmap_block_index(bi)
+            , buffer(buf)
+        {}
+        BlockIndex bitmap_block_index { 0 };
+        bool dirty { false };
+        ByteBuffer buffer;
+        Bitmap bitmap(u32 blocks_per_group) { return Bitmap::wrap(buffer.data(), blocks_per_group); }
+    };
+
+    CachedBitmap& get_block_bitmap(BlockIndex bitmap_block_index);
+    CachedBitmap& get_inode_bitmap(InodeIndex bitmap_block_index);
+
+    Vector<OwnPtr<CachedBitmap>> m_cached_bitmaps;
 };
 
 inline Ext2FS& Ext2FSInode::fs()