mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 11:12:45 +00:00 
			
		
		
		
	Kernel: Implement O_DIRECT open() flag to bypass disk caches
Files opened with O_DIRECT will now bypass the disk cache in read/write operations (though metadata operations will still hit the disk cache.) This will allow us to test actual disk performance instead of testing disk *cache* performance, if that's what we want. :^) There's room for improvment here, we're very aggressively flushing any dirty cache entries for the specific block before reading/writing that block. This is done by walking the entire cache, which may be slow.
This commit is contained in:
		
							parent
							
								
									3de3daf765
								
							
						
					
					
						commit
						59ed235c85
					
				
					 7 changed files with 59 additions and 18 deletions
				
			
		|  | @ -1,5 +1,6 @@ | |||
| #include <Kernel/Arch/i386/CPU.h> | ||||
| #include <Kernel/FileSystem/DiskBackedFileSystem.h> | ||||
| #include <Kernel/FileSystem/FileDescription.h> | ||||
| #include <Kernel/KBuffer.h> | ||||
| #include <Kernel/Process.h> | ||||
| 
 | ||||
|  | @ -92,11 +93,21 @@ DiskBackedFS::~DiskBackedFS() | |||
| { | ||||
| } | ||||
| 
 | ||||
| bool DiskBackedFS::write_block(unsigned index, const u8* data) | ||||
| bool DiskBackedFS::write_block(unsigned index, const u8* data, FileDescription* description) | ||||
| { | ||||
| #ifdef DBFS_DEBUG | ||||
|     kprintf("DiskBackedFileSystem::write_block %u, size=%u\n", index, data.size()); | ||||
| #endif | ||||
| 
 | ||||
|     bool allow_cache = !description || !description->is_direct(); | ||||
| 
 | ||||
|     if (!allow_cache) { | ||||
|         flush_specific_block_if_needed(index); | ||||
|         DiskOffset base_offset = static_cast<DiskOffset>(index) * static_cast<DiskOffset>(block_size()); | ||||
|         device().write(base_offset, block_size(), data); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     auto& entry = cache().get(index); | ||||
|     memcpy(entry.data, data, block_size()); | ||||
|     entry.is_dirty = true; | ||||
|  | @ -106,22 +117,32 @@ bool DiskBackedFS::write_block(unsigned index, const u8* data) | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool DiskBackedFS::write_blocks(unsigned index, unsigned count, const u8* data) | ||||
| bool DiskBackedFS::write_blocks(unsigned index, unsigned count, const u8* data, FileDescription* description) | ||||
| { | ||||
| #ifdef DBFS_DEBUG | ||||
|     kprintf("DiskBackedFileSystem::write_blocks %u x%u\n", index, count); | ||||
| #endif | ||||
|     for (unsigned i = 0; i < count; ++i) | ||||
|         write_block(index + i, data + i * block_size()); | ||||
|         write_block(index + i, data + i * block_size(), description); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool DiskBackedFS::read_block(unsigned index, u8* buffer) const | ||||
| bool DiskBackedFS::read_block(unsigned index, u8* buffer, FileDescription* description) const | ||||
| { | ||||
| #ifdef DBFS_DEBUG | ||||
|     kprintf("DiskBackedFileSystem::read_block %u\n", index); | ||||
| #endif | ||||
| 
 | ||||
|     bool allow_cache = !description || !description->is_direct(); | ||||
| 
 | ||||
|     if (!allow_cache) { | ||||
|         const_cast<DiskBackedFS*>(this)->flush_specific_block_if_needed(index); | ||||
|         DiskOffset base_offset = static_cast<DiskOffset>(index) * static_cast<DiskOffset>(block_size()); | ||||
|         bool success = device().read(base_offset, block_size(), buffer); | ||||
|         ASSERT(success); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     auto& entry = cache().get(index); | ||||
|     if (!entry.has_data) { | ||||
|         DiskOffset base_offset = static_cast<DiskOffset>(index) * static_cast<DiskOffset>(block_size()); | ||||
|  | @ -133,16 +154,16 @@ bool DiskBackedFS::read_block(unsigned index, u8* buffer) const | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool DiskBackedFS::read_blocks(unsigned index, unsigned count, u8* buffer) const | ||||
| bool DiskBackedFS::read_blocks(unsigned index, unsigned count, u8* buffer, FileDescription* description) const | ||||
| { | ||||
|     if (!count) | ||||
|         return false; | ||||
|     if (count == 1) | ||||
|         return read_block(index, buffer); | ||||
|         return read_block(index, buffer, description); | ||||
|     u8* out = buffer; | ||||
| 
 | ||||
|     for (unsigned i = 0; i < count; ++i) { | ||||
|         if (!read_block(index + i, out)) | ||||
|         if (!read_block(index + i, out, description)) | ||||
|             return false; | ||||
|         out += block_size(); | ||||
|     } | ||||
|  | @ -150,6 +171,20 @@ bool DiskBackedFS::read_blocks(unsigned index, unsigned count, u8* buffer) const | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void DiskBackedFS::flush_specific_block_if_needed(unsigned index) | ||||
| { | ||||
|     LOCKER(m_lock); | ||||
|     if (!cache().is_dirty()) | ||||
|         return; | ||||
|     cache().for_each_entry([&](CacheEntry& entry) { | ||||
|         if (entry.is_dirty && entry.block_index == index) { | ||||
|             DiskOffset base_offset = static_cast<DiskOffset>(entry.block_index) * static_cast<DiskOffset>(block_size()); | ||||
|             device().write(base_offset, block_size(), entry.data); | ||||
|             entry.is_dirty = false; | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| void DiskBackedFS::flush_writes_impl() | ||||
| { | ||||
|     LOCKER(m_lock); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling