mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 05:48:12 +00:00
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.
This commit is contained in:
parent
3a8b5b405c
commit
1ae9d85de9
2 changed files with 52 additions and 19 deletions
|
@ -502,6 +502,15 @@ void Ext2FS::flush_writes()
|
||||||
flush_block_group_descriptor_table();
|
flush_block_group_descriptor_table();
|
||||||
m_block_group_descriptors_dirty = false;
|
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();
|
DiskBackedFS::flush_writes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1006,11 +1015,11 @@ Ext2FS::BlockIndex Ext2FS::allocate_block(GroupIndex preferred_group_index)
|
||||||
}
|
}
|
||||||
ASSERT(found_a_group);
|
ASSERT(found_a_group);
|
||||||
auto& bgd = group_descriptor(group_index);
|
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);
|
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();
|
BlockIndex first_block_in_group = (group_index - 1) * blocks_per_group() + first_block_index();
|
||||||
int first_unset_bit_index = block_bitmap.find_first_unset();
|
int first_unset_bit_index = block_bitmap.find_first_unset();
|
||||||
ASSERT(first_unset_bit_index != -1);
|
ASSERT(first_unset_bit_index != -1);
|
||||||
|
@ -1200,29 +1209,37 @@ Ext2FS::BlockIndex Ext2FS::first_block_index() const
|
||||||
return block_size() == 1024 ? 1 : 0;
|
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)
|
bool Ext2FS::set_block_allocation_state(BlockIndex block_index, bool new_state)
|
||||||
{
|
{
|
||||||
LOCKER(m_lock);
|
LOCKER(m_lock);
|
||||||
#ifdef EXT2_DEBUG
|
#ifdef EXT2_DEBUG
|
||||||
dbgprintf("Ext2FS: set_block_allocation_state(block=%u, state=%u)\n", block_index, new_state);
|
dbgprintf("Ext2FS: set_block_allocation_state(block=%u, state=%u)\n", block_index, new_state);
|
||||||
#endif
|
#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);
|
auto& bgd = group_descriptor(group_index);
|
||||||
BlockIndex index_in_group = (block_index - first_block_index()) - ((group_index - 1) * blocks_per_group());
|
BlockIndex index_in_group = (block_index - first_block_index()) - ((group_index - 1) * blocks_per_group());
|
||||||
unsigned bit_index = index_in_group % 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
|
#ifdef EXT2_DEBUG
|
||||||
dbgprintf(" index_in_group: %u\n", index_in_group);
|
dbgprintf("Ext2FS: block %u state: %u -> %u (in bitmap block %u)\n", block_index, current_state, new_state, bgd.bg_block_bitmap);
|
||||||
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);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (current_state == new_state) {
|
if (current_state == new_state) {
|
||||||
|
@ -1230,9 +1247,8 @@ bool Ext2FS::set_block_allocation_state(BlockIndex block_index, bool new_state)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap.set(bit_index, new_state);
|
cached_bitmap.bitmap(blocks_per_group()).set(bit_index, new_state);
|
||||||
success = write_block(bgd.bg_block_bitmap, block.data());
|
cached_bitmap.dirty = true;
|
||||||
ASSERT(success);
|
|
||||||
|
|
||||||
// Update superblock
|
// Update superblock
|
||||||
#ifdef EXT2_DEBUG
|
#ifdef EXT2_DEBUG
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Bitmap.h>
|
||||||
#include <Kernel/FileSystem/DiskBackedFileSystem.h>
|
#include <Kernel/FileSystem/DiskBackedFileSystem.h>
|
||||||
#include <Kernel/FileSystem/Inode.h>
|
#include <Kernel/FileSystem/Inode.h>
|
||||||
#include <Kernel/FileSystem/ext2_fs.h>
|
#include <Kernel/FileSystem/ext2_fs.h>
|
||||||
|
@ -135,6 +136,22 @@ private:
|
||||||
|
|
||||||
bool m_super_block_dirty { false };
|
bool m_super_block_dirty { false };
|
||||||
bool m_block_group_descriptors_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()
|
inline Ext2FS& Ext2FSInode::fs()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue