mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 21:52:45 +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
	
	 Andreas Kling
						Andreas Kling