From 391fc0c4c2440e78a1e29bfc76e8a6f2a5625c80 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 28 Aug 2025 15:52:55 +0300 Subject: [PATCH] Kernel: Don't crash if Ext2 filesystem doing too many fileops I had a hardlimit of 10 block buffers and if they ran out, the kernel would crash. this patchs increases the number of buffers to 16 and removes the crash condition when they run out :D --- kernel/include/kernel/FS/Ext2/FileSystem.h | 42 +++++++++++++--- kernel/kernel/FS/Ext2/FileSystem.cpp | 57 ++++++++++++---------- kernel/kernel/FS/Ext2/Inode.cpp | 28 +++++------ 3 files changed, 79 insertions(+), 48 deletions(-) diff --git a/kernel/include/kernel/FS/Ext2/FileSystem.h b/kernel/include/kernel/FS/Ext2/FileSystem.h index bb2244a2..2c75a2aa 100644 --- a/kernel/include/kernel/FS/Ext2/FileSystem.h +++ b/kernel/include/kernel/FS/Ext2/FileSystem.h @@ -26,18 +26,40 @@ namespace Kernel class BlockBufferWrapper { BAN_NON_COPYABLE(BlockBufferWrapper); - BAN_NON_MOVABLE(BlockBufferWrapper); public: - BlockBufferWrapper(BAN::Span buffer, bool& used) + BlockBufferWrapper(BAN::Span buffer, bool* used, Mutex* mutex, ThreadBlocker* blocker) : m_buffer(buffer) , m_used(used) + , m_mutex(mutex) + , m_blocker(blocker) { - ASSERT(m_used); + ASSERT(m_used && *m_used); } + BlockBufferWrapper(BlockBufferWrapper&& other) { *this = BAN::move(other); } ~BlockBufferWrapper() { - m_used = false; + if (m_used == nullptr) + return; + m_mutex->lock(); + *m_used = false; + m_blocker->unblock(); + m_mutex->unlock(); + } + + BlockBufferWrapper& operator=(BlockBufferWrapper&& other) + { + this->m_buffer = other.m_buffer; + this->m_used = other.m_used; + this->m_mutex = other.m_mutex; + this->m_blocker = other.m_blocker; + + other.m_buffer = {}; + other.m_used = nullptr; + other.m_mutex = nullptr; + other.m_blocker = nullptr; + + return *this; } size_t size() const { return m_buffer.size(); } @@ -53,7 +75,9 @@ namespace Kernel private: BAN::Span m_buffer; - bool& m_used; + bool* m_used; + Mutex* m_mutex; + ThreadBlocker* m_blocker; }; public: @@ -79,7 +103,7 @@ namespace Kernel BAN::ErrorOr sync_superblock(); BAN::ErrorOr sync_block(uint32_t block); - BlockBufferWrapper get_block_buffer(); + BAN::ErrorOr get_block_buffer(); BAN::ErrorOr reserve_free_block(uint32_t primary_bgd); BAN::ErrorOr release_block(uint32_t block); @@ -102,7 +126,7 @@ namespace Kernel { public: BlockBufferManager() = default; - BlockBufferWrapper get_buffer(); + BAN::ErrorOr get_buffer(); BAN::ErrorOr initialize(size_t block_size); @@ -114,7 +138,9 @@ namespace Kernel }; private: - BAN::Array m_buffers; + Mutex m_buffer_mutex; + ThreadBlocker m_buffer_blocker; + BAN::Array m_buffers; }; private: diff --git a/kernel/kernel/FS/Ext2/FileSystem.cpp b/kernel/kernel/FS/Ext2/FileSystem.cpp index 0495d496..bff8ca40 100644 --- a/kernel/kernel/FS/Ext2/FileSystem.cpp +++ b/kernel/kernel/FS/Ext2/FileSystem.cpp @@ -125,7 +125,7 @@ namespace Kernel TRY(m_buffer_manager.initialize(block_size())); { - auto block_buffer = m_buffer_manager.get_buffer(); + auto block_buffer = TRY(m_buffer_manager.get_buffer()); if (superblock().rev_level == Ext2::Enum::GOOD_OLD_REV) { @@ -170,6 +170,9 @@ namespace Kernel BAN::ErrorOr Ext2FS::create_inode(const Ext2::Inode& ext2_inode) { + auto bgd_buffer = TRY(m_buffer_manager.get_buffer()); + auto inode_bitmap = TRY(m_buffer_manager.get_buffer()); + LockGuard _(m_mutex); ASSERT(ext2_inode.size == 0); @@ -179,9 +182,6 @@ namespace Kernel const uint32_t block_size = this->block_size(); - auto bgd_buffer = m_buffer_manager.get_buffer(); - auto inode_bitmap = m_buffer_manager.get_buffer(); - uint32_t current_group = -1; BlockLocation bgd_location {}; Ext2::BlockGroupDescriptor* bgd = nullptr; @@ -248,15 +248,15 @@ namespace Kernel BAN::ErrorOr Ext2FS::delete_inode(uint32_t ino) { + auto bgd_buffer = TRY(get_block_buffer()); + auto bitmap_buffer = TRY(get_block_buffer()); + auto inode_buffer = TRY(get_block_buffer()); + LockGuard _(m_mutex); ASSERT(ino >= superblock().first_ino); ASSERT(ino <= superblock().inodes_count); - auto bgd_buffer = get_block_buffer(); - auto bitmap_buffer = get_block_buffer(); - auto inode_buffer = get_block_buffer(); - const uint32_t inode_group = (ino - 1) / superblock().inodes_per_group; const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group; @@ -334,6 +334,8 @@ namespace Kernel BAN::ErrorOr Ext2FS::sync_superblock() { + auto superblock_buffer = TRY(get_block_buffer()); + LockGuard _(m_mutex); const uint32_t sector_size = m_block_device->blksize(); @@ -347,8 +349,6 @@ namespace Kernel const uint32_t lba = 1024 / sector_size; const uint32_t sector_count = BAN::Math::div_round_up(superblock_bytes, sector_size); - auto superblock_buffer = get_block_buffer(); - TRY(m_block_device->read_blocks(lba, sector_count, superblock_buffer.span())); if (memcmp(superblock_buffer.data(), &m_superblock, superblock_bytes)) { @@ -370,22 +370,21 @@ namespace Kernel return m_block_device->sync_blocks(block * sectors_per_block, sectors_per_block); } - Ext2FS::BlockBufferWrapper Ext2FS::get_block_buffer() + BAN::ErrorOr Ext2FS::get_block_buffer() { - LockGuard _(m_mutex); return m_buffer_manager.get_buffer(); } BAN::ErrorOr Ext2FS::reserve_free_block(uint32_t primary_bgd) { + auto bgd_buffer = TRY(m_buffer_manager.get_buffer()); + auto block_bitmap = TRY(m_buffer_manager.get_buffer()); + LockGuard _(m_mutex); if (m_superblock.r_blocks_count >= m_superblock.free_blocks_count) return BAN::Error::from_errno(ENOSPC); - auto bgd_buffer = m_buffer_manager.get_buffer(); - auto block_bitmap = m_buffer_manager.get_buffer(); - auto check_block_group = [&](uint32_t block_group) -> BAN::ErrorOr { @@ -439,6 +438,9 @@ namespace Kernel BAN::ErrorOr Ext2FS::release_block(uint32_t block) { + auto bgd_buffer = TRY(get_block_buffer()); + auto bitmap_buffer = TRY(get_block_buffer()); + LockGuard _(m_mutex); ASSERT(block >= m_superblock.first_data_block); @@ -447,9 +449,6 @@ namespace Kernel const uint32_t block_group = (block - m_superblock.first_data_block) / m_superblock.blocks_per_group; const uint32_t block_offset = (block - m_superblock.first_data_block) % m_superblock.blocks_per_group; - auto bgd_buffer = get_block_buffer(); - auto bitmap_buffer = get_block_buffer(); - auto bgd_location = locate_block_group_descriptior(block_group); TRY(read_block(bgd_location.block, bgd_buffer)); @@ -480,7 +479,7 @@ namespace Kernel const uint32_t block_size = this->block_size(); - auto bgd_buffer = m_buffer_manager.get_buffer(); + auto bgd_buffer = TRY(m_buffer_manager.get_buffer()); const uint32_t inode_group = (ino - 1) / superblock().inodes_per_group; const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group; @@ -533,16 +532,22 @@ namespace Kernel }; } - Ext2FS::BlockBufferWrapper Ext2FS::BlockBufferManager::get_buffer() + BAN::ErrorOr Ext2FS::BlockBufferManager::get_buffer() { - for (auto& buffer : m_buffers) + LockGuard _(m_buffer_mutex); + + for (;;) { - if (buffer.used) - continue; - buffer.used = true; - return Ext2FS::BlockBufferWrapper(buffer.buffer.span(), buffer.used); + for (auto& buffer : m_buffers) + { + if (buffer.used) + continue; + buffer.used = true; + return Ext2FS::BlockBufferWrapper(buffer.buffer.span(), &buffer.used, &m_buffer_mutex, &m_buffer_blocker); + } + + TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker, &m_buffer_mutex)); } - ASSERT_NOT_REACHED(); } BAN::ErrorOr Ext2FS::BlockBufferManager::initialize(size_t block_size) diff --git a/kernel/kernel/FS/Ext2/Inode.cpp b/kernel/kernel/FS/Ext2/Inode.cpp index 3317c3c2..20d040fb 100644 --- a/kernel/kernel/FS/Ext2/Inode.cpp +++ b/kernel/kernel/FS/Ext2/Inode.cpp @@ -32,7 +32,7 @@ namespace Kernel auto inode_location = TRY(fs.locate_inode(inode_ino)); - auto block_buffer = fs.get_block_buffer(); + auto block_buffer = TRY(fs.get_block_buffer()); TRY(fs.read_block(inode_location.block, block_buffer)); auto& inode = block_buffer.span().slice(inode_location.offset).as(); @@ -61,7 +61,7 @@ namespace Kernel return BAN::Optional(); ASSERT(depth >= 1); - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); TRY(m_fs.read_block(block, block_buffer)); const uint32_t indices_per_block = blksize() / sizeof(uint32_t); @@ -152,7 +152,7 @@ namespace Kernel const uint32_t block_size = blksize(); - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); const uint32_t first_block = offset / block_size; const uint32_t last_block = BAN::Math::div_round_up(offset + count, block_size); @@ -192,7 +192,7 @@ namespace Kernel const uint32_t block_size = blksize(); - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); size_t written = 0; size_t to_write = buffer.size(); @@ -349,7 +349,7 @@ namespace Kernel return {}; } - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); TRY(m_fs.read_block(block, block_buffer)); const uint32_t ids_per_block = blksize() / sizeof(uint32_t); @@ -409,7 +409,7 @@ done: // FIXME: can we actually assume directories have all their blocks allocated const uint32_t block_index = TRY(fs_block_of_data_block_index(offset)).value(); - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); TRY(m_fs.read_block(block_index, block_buffer)); @@ -602,7 +602,7 @@ done: const uint32_t block_size = m_fs.block_size(); - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); auto write_inode = [&](uint32_t entry_offset, uint32_t entry_rec_len) -> BAN::ErrorOr @@ -689,7 +689,7 @@ needs_new_block: { ASSERT(mode().ifdir()); - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); // Confirm that this doesn't contain anything else than '.' or '..' for (uint32_t i = 0; i < max_used_data_block_count(); i++) @@ -726,7 +726,7 @@ needs_new_block: return BAN::Error::from_errno(ENOTSUP); } - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); for (uint32_t i = 0; i < max_used_data_block_count(); i++) { @@ -782,7 +782,7 @@ needs_new_block: return BAN::Error::from_errno(ENOTSUP); } - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); for (uint32_t i = 0; i < max_used_data_block_count(); i++) { @@ -844,7 +844,7 @@ needs_new_block: block = TRY(m_fs.reserve_free_block(block_group())); m_inode.blocks += inode_blocks_per_fs_block; - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); memset(block_buffer.data(), 0x00, block_buffer.size()); TRY(m_fs.write_block(block, block_buffer)); } @@ -852,7 +852,7 @@ needs_new_block: if (depth == 0) return block; - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); TRY(m_fs.read_block(block, block_buffer)); uint32_t divisor = 1; @@ -901,7 +901,7 @@ needs_new_block: BAN::ErrorOr Ext2Inode::sync() { auto inode_location = TRY(m_fs.locate_inode(ino())); - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); TRY(m_fs.read_block(inode_location.block, block_buffer)); if (memcmp(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode))) @@ -917,7 +917,7 @@ needs_new_block: { ASSERT(mode().ifdir()); - auto block_buffer = m_fs.get_block_buffer(); + auto block_buffer = TRY(m_fs.get_block_buffer()); for (uint32_t i = 0; i < max_used_data_block_count(); i++) {