mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 03:22:43 +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(); | ||||
|         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 | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling