From a6db2f985a4ee635fa01cf1e649a05a6188888de Mon Sep 17 00:00:00 2001 From: Brian Gianforcaro Date: Sun, 1 Aug 2021 04:33:06 -0700 Subject: [PATCH] Kernel: Handle OOM in DiskCache when mounting Ext2 filesystems Create the disk cache up front, so we can verify it succeeds. Make the KBuffer allocation fail-able, so we can properly handle failure when the user asks up to mount a Ext2 filesystem under OOM conditions. --- Kernel/FileSystem/BlockBasedFileSystem.cpp | 41 +++++++++++++++------- Kernel/FileSystem/BlockBasedFileSystem.h | 1 + Kernel/FileSystem/Ext2FileSystem.cpp | 6 ++++ 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Kernel/FileSystem/BlockBasedFileSystem.cpp b/Kernel/FileSystem/BlockBasedFileSystem.cpp index baa0b422483..0a0c29c6a19 100644 --- a/Kernel/FileSystem/BlockBasedFileSystem.cpp +++ b/Kernel/FileSystem/BlockBasedFileSystem.cpp @@ -20,13 +20,14 @@ struct CacheEntry { class DiskCache { public: - explicit DiskCache(BlockBasedFileSystem& fs) + static constexpr size_t EntryCount = 10000; + explicit DiskCache(BlockBasedFileSystem& fs, NonnullOwnPtr cached_block_data, NonnullOwnPtr entries_buffer) : m_fs(fs) - , m_cached_block_data(KBuffer::create_with_size(m_entry_count * m_fs.block_size())) - , m_entries(KBuffer::create_with_size(m_entry_count * sizeof(CacheEntry))) + , m_cached_block_data(move(cached_block_data)) + , m_entries(move(entries_buffer)) { - for (size_t i = 0; i < m_entry_count; ++i) { - entries()[i].data = m_cached_block_data.data() + i * m_fs.block_size(); + for (size_t i = 0; i < EntryCount; ++i) { + entries()[i].data = m_cached_block_data->data() + i * m_fs.block_size(); m_clean_list.append(entries()[i]); } } @@ -83,8 +84,8 @@ public: return new_entry; } - const CacheEntry* entries() const { return (const CacheEntry*)m_entries.data(); } - CacheEntry* entries() { return (CacheEntry*)m_entries.data(); } + const CacheEntry* entries() const { return (const CacheEntry*)m_entries->data(); } + CacheEntry* entries() { return (CacheEntry*)m_entries->data(); } template void for_each_dirty_entry(Callback callback) @@ -95,12 +96,11 @@ public: private: BlockBasedFileSystem& m_fs; - size_t m_entry_count { 10000 }; mutable HashMap m_hash; mutable IntrusiveList, &CacheEntry::list_node> m_clean_list; mutable IntrusiveList, &CacheEntry::list_node> m_dirty_list; - KBuffer m_cached_block_data; - KBuffer m_entries; + NonnullOwnPtr m_cached_block_data; + NonnullOwnPtr m_entries; bool m_dirty { false }; }; @@ -114,6 +114,25 @@ BlockBasedFileSystem::~BlockBasedFileSystem() { } +bool BlockBasedFileSystem::initialize() +{ + VERIFY(block_size() != 0); + auto cached_block_data = KBuffer::try_create_with_size(DiskCache::EntryCount * block_size()); + if (!cached_block_data) + return false; + + auto entries_data = KBuffer::try_create_with_size(DiskCache::EntryCount * sizeof(CacheEntry)); + if (!entries_data) + return false; + + auto disk_cache = adopt_own_if_nonnull(new (nothrow) DiskCache(*this, cached_block_data.release_nonnull(), entries_data.release_nonnull())); + if (!disk_cache) + return false; + + m_cache = move(disk_cache); + return true; +} + KResult BlockBasedFileSystem::write_block(BlockIndex index, const UserOrKernelBuffer& data, size_t count, size_t offset, bool allow_cache) { VERIFY(m_logical_block_size); @@ -293,8 +312,6 @@ void BlockBasedFileSystem::flush_writes() DiskCache& BlockBasedFileSystem::cache() const { - if (!m_cache) - m_cache = make(const_cast(*this)); return *m_cache; } diff --git a/Kernel/FileSystem/BlockBasedFileSystem.h b/Kernel/FileSystem/BlockBasedFileSystem.h index e78bdcfcce8..0e78e9ef10d 100644 --- a/Kernel/FileSystem/BlockBasedFileSystem.h +++ b/Kernel/FileSystem/BlockBasedFileSystem.h @@ -15,6 +15,7 @@ public: TYPEDEF_DISTINCT_ORDERED_ID(u64, BlockIndex); virtual ~BlockBasedFileSystem() override; + virtual bool initialize() override; u64 logical_block_size() const { return m_logical_block_size; }; diff --git a/Kernel/FileSystem/Ext2FileSystem.cpp b/Kernel/FileSystem/Ext2FileSystem.cpp index 579f5e2f290..2bd8ddb7cea 100644 --- a/Kernel/FileSystem/Ext2FileSystem.cpp +++ b/Kernel/FileSystem/Ext2FileSystem.cpp @@ -89,6 +89,7 @@ const ext2_group_desc& Ext2FS::group_descriptor(GroupIndex group_index) const bool Ext2FS::initialize() { MutexLocker locker(m_lock); + VERIFY((sizeof(ext2_super_block) % logical_block_size()) == 0); auto super_block_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&m_super_block); bool success = raw_read_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), super_block_buffer); @@ -115,6 +116,11 @@ bool Ext2FS::initialize() set_block_size(EXT2_BLOCK_SIZE(&super_block)); set_fragment_size(EXT2_FRAG_SIZE(&super_block)); + // Note: This depends on the block size being available. + auto baseclass_result = BlockBasedFileSystem::initialize(); + if (!baseclass_result) + return baseclass_result; + VERIFY(block_size() <= (int)max_block_size); m_block_group_count = ceil_div(super_block.s_blocks_count, super_block.s_blocks_per_group);