From 44673c4f3b092f03ed8607b743903cf03d46b3f2 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 25 Apr 2019 22:05:53 +0200 Subject: [PATCH] Kernel: Add a write cache to DiskBackedFS. This way you can spam small write()s on a file without the kernel writing to disk every single time. Flushes are included in the FS::sync() operation and will get triggered regularly by syncd. :^) --- AK/ByteBuffer.h | 7 ++++ Kernel/FileSystem/DiskBackedFileSystem.cpp | 37 +++++++++++++++------- Kernel/FileSystem/DiskBackedFileSystem.h | 4 +++ Kernel/FileSystem/FileSystem.cpp | 12 ++++++- Kernel/FileSystem/FileSystem.h | 2 ++ 5 files changed, 49 insertions(+), 13 deletions(-) diff --git a/AK/ByteBuffer.h b/AK/ByteBuffer.h index f263c1c13b..45b213713d 100644 --- a/AK/ByteBuffer.h +++ b/AK/ByteBuffer.h @@ -118,6 +118,13 @@ public: void* end_pointer() { return m_impl ? m_impl->end_pointer() : nullptr; } const void* end_pointer() const { return m_impl ? m_impl->end_pointer() : nullptr; } + ByteBuffer isolated_copy() const + { + if (!m_impl) + return { }; + return copy(m_impl->pointer(), m_impl->size()); + } + // NOTE: trim() does not reallocate. void trim(ssize_t size) { diff --git a/Kernel/FileSystem/DiskBackedFileSystem.cpp b/Kernel/FileSystem/DiskBackedFileSystem.cpp index f6214bb8b3..4d45aabc01 100644 --- a/Kernel/FileSystem/DiskBackedFileSystem.cpp +++ b/Kernel/FileSystem/DiskBackedFileSystem.cpp @@ -66,8 +66,10 @@ bool DiskBackedFS::write_block(unsigned index, const ByteBuffer& data) if (auto* cached_block = block_cache().resource().get({ fsid(), index })) cached_block->m_buffer = data; } - DiskOffset base_offset = static_cast(index) * static_cast(block_size()); - return device().write(base_offset, block_size(), data.pointer()); + + LOCKER(m_lock); + m_write_cache.set(index, data.isolated_copy()); + return true; } bool DiskBackedFS::write_blocks(unsigned index, unsigned count, const ByteBuffer& data) @@ -75,16 +77,9 @@ bool DiskBackedFS::write_blocks(unsigned index, unsigned count, const ByteBuffer #ifdef DBFS_DEBUG kprintf("DiskBackedFileSystem::write_blocks %u x%u\n", index, count); #endif - // FIXME: Maybe reorder this so we send out the write commands before updating cache? - { - LOCKER(block_cache().lock()); - for (unsigned i = 0; i < count; ++i) { - if (auto* cached_block = block_cache().resource().get({ fsid(), index + i })) - cached_block->m_buffer = data.slice(i * block_size(), block_size()); - } - } - DiskOffset base_offset = static_cast(index) * static_cast(block_size()); - return device().write(base_offset, count * block_size(), data.pointer()); + for (unsigned i = 0; i < count; ++i) + write_block(index + i, data.slice(i * block_size(), block_size())); + return true; } ByteBuffer DiskBackedFS::read_block(unsigned index) const @@ -92,6 +87,13 @@ ByteBuffer DiskBackedFS::read_block(unsigned index) const #ifdef DBFS_DEBUG kprintf("DiskBackedFileSystem::read_block %u\n", index); #endif + + { + LOCKER(m_lock); + if (auto it = m_write_cache.find(index); it != m_write_cache.end()) + return it->value; + } + { LOCKER(block_cache().lock()); if (auto* cached_block = block_cache().resource().get({ fsid(), index })) @@ -105,6 +107,7 @@ ByteBuffer DiskBackedFS::read_block(unsigned index) const bool success = device().read(base_offset, block_size(), buffer_pointer); ASSERT(success); ASSERT(buffer.size() == block_size()); + { LOCKER(block_cache().lock()); block_cache().resource().put({ fsid(), index }, CachedBlock({ fsid(), index }, buffer)); @@ -138,3 +141,13 @@ void DiskBackedFS::set_block_size(unsigned block_size) return; m_block_size = block_size; } + +void DiskBackedFS::flush_writes() +{ + LOCKER(m_lock); + for (auto& it : m_write_cache) { + DiskOffset base_offset = static_cast(it.key) * static_cast(block_size()); + device().write(base_offset, block_size(), it.value.data()); + } + m_write_cache.clear(); +} diff --git a/Kernel/FileSystem/DiskBackedFileSystem.h b/Kernel/FileSystem/DiskBackedFileSystem.h index 75d3f8f8fc..b115eb6d12 100644 --- a/Kernel/FileSystem/DiskBackedFileSystem.h +++ b/Kernel/FileSystem/DiskBackedFileSystem.h @@ -12,6 +12,8 @@ public: int block_size() const { return m_block_size; } + virtual void flush_writes() override; + protected: explicit DiskBackedFS(Retained&&); @@ -26,4 +28,6 @@ protected: private: int m_block_size { 0 }; Retained m_device; + + HashMap m_write_cache; }; diff --git a/Kernel/FileSystem/FileSystem.cpp b/Kernel/FileSystem/FileSystem.cpp index b3ec211785..c05884a0dc 100644 --- a/Kernel/FileSystem/FileSystem.cpp +++ b/Kernel/FileSystem/FileSystem.cpp @@ -144,7 +144,7 @@ int Inode::decrement_link_count() void FS::sync() { - Vector> inodes; + Vector, 32> inodes; { InterruptDisabler disabler; for (auto* inode : all_inodes()) { @@ -157,6 +157,16 @@ void FS::sync() ASSERT(inode->is_metadata_dirty()); inode->flush_metadata(); } + + Vector, 32> fses; + { + InterruptDisabler disabler; + for (auto& it : all_fses()) + fses.append(*it.value); + } + + for (auto fs : fses) + fs->flush_writes(); } void Inode::set_vmo(VMObject& vmo) diff --git a/Kernel/FileSystem/FileSystem.h b/Kernel/FileSystem/FileSystem.h index 847c2280c3..abe31cdd11 100644 --- a/Kernel/FileSystem/FileSystem.h +++ b/Kernel/FileSystem/FileSystem.h @@ -57,6 +57,8 @@ public: virtual RetainPtr get_inode(InodeIdentifier) const = 0; + virtual void flush_writes() { } + protected: FS();