Kernel/Ext2: Check and set file system state

This is supposed to detect whether a file system was unmounted
cleanly or not.
This commit is contained in:
kleines Filmröllchen 2023-07-02 14:25:16 +02:00 committed by Jelle Raaijmakers
parent 8fb126bec6
commit 251b17085b
2 changed files with 30 additions and 3 deletions

View file

@ -65,6 +65,9 @@ ErrorOr<void> 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<void> 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<void> 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 {};
}

View file

@ -30,6 +30,7 @@ FileSystem::~FileSystem()
ErrorOr<void> FileSystem::prepare_to_unmount(Inode& mount_guest_inode)
{
return m_attach_count.with([&](auto& attach_count) -> ErrorOr<void> {
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 {};