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++) {