diff options
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/FileSystem/Ext2FileSystem.cpp | 21 | ||||
-rw-r--r-- | Kernel/FileSystem/Ext2FileSystem.h | 6 |
2 files changed, 24 insertions, 3 deletions
diff --git a/Kernel/FileSystem/Ext2FileSystem.cpp b/Kernel/FileSystem/Ext2FileSystem.cpp index 48aa3b4cdd..1a09ee2309 100644 --- a/Kernel/FileSystem/Ext2FileSystem.cpp +++ b/Kernel/FileSystem/Ext2FileSystem.cpp @@ -798,6 +798,19 @@ ErrorOr<NonnullLockRefPtr<Inode>> Ext2FS::get_inode(InodeIdentifier inode) const return new_inode; } +ErrorOr<void> Ext2FSInode::compute_block_list_with_exclusive_locking() +{ + // Note: We verify that the inode mutex is being held locked. Because only the read_bytes_locked() + // method uses this method and the mutex can be locked in shared mode when reading the Inode if + // it is an ext2 regular file, but also in exclusive mode, when the Inode is an ext2 directory and being + // traversed, we use another exclusive lock to ensure we always mutate the block list safely. + VERIFY(m_inode_lock.is_locked()); + MutexLocker block_list_locker(m_block_list_lock); + if (m_block_list.is_empty()) + m_block_list = TRY(compute_block_list()); + return {}; +} + ErrorOr<size_t> Ext2FSInode::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription* description) const { MutexLocker inode_locker(m_inode_lock); @@ -817,8 +830,12 @@ ErrorOr<size_t> Ext2FSInode::read_bytes(off_t offset, size_t count, UserOrKernel return nread; } - if (m_block_list.is_empty()) - m_block_list = TRY(compute_block_list()); + // Note: We bypass the const declaration of this method, but this is a strong + // requirement to be able to accomplish the read operation successfully. + // We call this special method becuase it locks a separate mutex to ensure we + // update the block list of the inode safely, as the m_inode_lock is locked in + // shared mode. + TRY(const_cast<Ext2FSInode&>(*this).compute_block_list_with_exclusive_locking()); if (m_block_list.is_empty()) { dmesgln("Ext2FSInode[{}]::read_bytes(): Empty block list", identifier()); diff --git a/Kernel/FileSystem/Ext2FileSystem.h b/Kernel/FileSystem/Ext2FileSystem.h index 8441fc70a3..8a5abff095 100644 --- a/Kernel/FileSystem/Ext2FileSystem.h +++ b/Kernel/FileSystem/Ext2FileSystem.h @@ -61,6 +61,8 @@ private: ErrorOr<void> grow_triply_indirect_block(BlockBasedFileSystem::BlockIndex, size_t, Span<BlockBasedFileSystem::BlockIndex>, Vector<BlockBasedFileSystem::BlockIndex>&, unsigned&); ErrorOr<void> shrink_triply_indirect_block(BlockBasedFileSystem::BlockIndex, size_t, size_t, unsigned&); ErrorOr<void> flush_block_list(); + + ErrorOr<void> compute_block_list_with_exclusive_locking(); ErrorOr<Vector<BlockBasedFileSystem::BlockIndex>> compute_block_list() const; ErrorOr<Vector<BlockBasedFileSystem::BlockIndex>> compute_block_list_with_meta_blocks() const; ErrorOr<Vector<BlockBasedFileSystem::BlockIndex>> compute_block_list_impl(bool include_block_list_blocks) const; @@ -70,9 +72,11 @@ private: Ext2FS const& fs() const; Ext2FSInode(Ext2FS&, InodeIndex); - mutable Vector<BlockBasedFileSystem::BlockIndex> m_block_list; + Vector<BlockBasedFileSystem::BlockIndex> m_block_list; HashMap<NonnullOwnPtr<KString>, InodeIndex> m_lookup_cache; ext2_inode m_raw_inode {}; + + Mutex m_block_list_lock { "BlockList"sv }; }; class Ext2FS final : public BlockBasedFileSystem { |