From 251b17085b4390c00a979f7abd1cb5c0f7cc18d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Sun, 2 Jul 2023 14:25:16 +0200 Subject: [PATCH] Kernel/Ext2: Check and set file system state This is supposed to detect whether a file system was unmounted cleanly or not. --- Kernel/FileSystem/Ext2FS/FileSystem.cpp | 32 ++++++++++++++++++++++--- Kernel/FileSystem/FileSystem.cpp | 1 + 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Kernel/FileSystem/Ext2FS/FileSystem.cpp b/Kernel/FileSystem/Ext2FS/FileSystem.cpp index 359e1a1213..597aaa17a0 100644 --- a/Kernel/FileSystem/Ext2FS/FileSystem.cpp +++ b/Kernel/FileSystem/Ext2FS/FileSystem.cpp @@ -65,6 +65,9 @@ ErrorOr Ext2FS::initialize_while_locked() return EINVAL; } + if (super_block.s_state == EXT2_ERROR_FS) + dmesgln("Ext2FS: Was not unmounted cleanly, file system may be erroneous!"); + if constexpr (EXT2_DEBUG) { dmesgln("Ext2FS: {} inodes, {} blocks", super_block.s_inodes_count, super_block.s_blocks_count); dmesgln("Ext2FS: Block size: {}", EXT2_BLOCK_SIZE(&super_block)); @@ -105,6 +108,12 @@ ErrorOr Ext2FS::initialize_while_locked() } m_root_inode = TRY(build_root_inode()); + + // Set filesystem to "error" state until we unmount cleanly. + dmesgln("Ext2FS: Mount successful, setting superblock to error state."); + m_super_block.s_state = EXT2_ERROR_FS; + TRY(flush_super_block()); + return {}; } @@ -534,16 +543,33 @@ unsigned Ext2FS::free_inode_count() const ErrorOr Ext2FS::prepare_to_clear_last_mount(Inode& mount_guest_inode) { - (void)mount_guest_inode; MutexLocker locker(m_lock); + bool any_inode_busy = false; for (auto& it : m_inode_cache) { - if (it.value->ref_count() > 1) - return EBUSY; + // We hold the last reference to the root inode, and the VFS Mount object holds the last reference to the mount_guest_inode, + // so they are allowed to have one more reference. + if ((it.value == m_root_inode || it.value->identifier() == mount_guest_inode.identifier()) && it.value->ref_count() > 2) { + dbgln_if(EXT2_DEBUG, "Ext2FS: Ignoring root or mount point inode's last reference"); + continue; + } + // The Inode::all_instances list always holds one reference to all inodes, which we disregard. + if (it.value->ref_count() > 1) { + dbgln_if(EXT2_DEBUG, "Ext2FS: Busy inode {} ({} refs)", it.value->index(), it.value->ref_count()); + any_inode_busy = true; + } } + if (any_inode_busy) + return EBUSY; BlockBasedFileSystem::remove_disk_cache_before_last_unmount(); m_inode_cache.clear(); m_root_inode = nullptr; + + // Mark filesystem as valid before unmount. + dmesgln("Ext2FS: Clean unmount, setting superblock to valid state"); + m_super_block.s_state = EXT2_VALID_FS; + TRY(flush_super_block()); + return {}; } diff --git a/Kernel/FileSystem/FileSystem.cpp b/Kernel/FileSystem/FileSystem.cpp index fa1a363470..42c1f9c8c8 100644 --- a/Kernel/FileSystem/FileSystem.cpp +++ b/Kernel/FileSystem/FileSystem.cpp @@ -30,6 +30,7 @@ FileSystem::~FileSystem() ErrorOr FileSystem::prepare_to_unmount(Inode& mount_guest_inode) { return m_attach_count.with([&](auto& attach_count) -> ErrorOr { + dbgln_if(VFS_DEBUG, "VFS: File system {} (id {}) is attached {} time(s)", class_name(), m_fsid.value(), attach_count); if (attach_count == 1) return prepare_to_clear_last_mount(mount_guest_inode); return {};