From 32692f032c2d09b2793856271b2a6669f21d0209 Mon Sep 17 00:00:00 2001 From: implicitfield <114500360+implicitfield@users.noreply.github.com> Date: Mon, 8 Apr 2024 20:56:09 +0300 Subject: [PATCH] Kernel/FATFS: Keep the FSInfo sector's free cluster count in sync --- Kernel/FileSystem/FATFS/FileSystem.cpp | 23 +++++++++++++++++++++++ Kernel/FileSystem/FATFS/FileSystem.h | 3 +++ Kernel/FileSystem/FATFS/Inode.cpp | 1 + 3 files changed, 27 insertions(+) diff --git a/Kernel/FileSystem/FATFS/FileSystem.cpp b/Kernel/FileSystem/FATFS/FileSystem.cpp index 974166b2c85..80d2abfef68 100644 --- a/Kernel/FileSystem/FATFS/FileSystem.cpp +++ b/Kernel/FileSystem/FATFS/FileSystem.cpp @@ -371,6 +371,17 @@ u32 FATFS::end_of_chain_marker() const } } +ErrorOr FATFS::set_free_cluster_count(u32 value) +{ + VERIFY(m_fat_version == FATVersion::FAT32); + + m_fs_info.last_known_free_cluster_count = value; + auto fs_info_buffer = UserOrKernelBuffer::for_kernel_buffer(bit_cast(&m_fs_info)); + TRY(write_block(m_parameter_block->dos7_bpb()->fs_info_sector, fs_info_buffer, sizeof(m_fs_info))); + + return {}; +} + ErrorOr FATFS::allocate_cluster() { u32 start_cluster; @@ -393,6 +404,10 @@ ErrorOr FATFS::allocate_cluster() for (u32 i = start_cluster; i < m_parameter_block->sector_count() / m_parameter_block->common_bpb()->sectors_per_cluster; i++) { if (TRY(fat_read(i)) == 0) { dbgln_if(FAT_DEBUG, "FATFS: Allocating cluster {}", i); + + if (m_fat_version == FATVersion::FAT32 && m_fs_info.last_known_free_cluster_count != fs_info_data_unknown) + TRY(set_free_cluster_count(m_fs_info.last_known_free_cluster_count - 1)); + TRY(fat_write(i, end_of_chain_marker())); return i; } @@ -401,6 +416,14 @@ ErrorOr FATFS::allocate_cluster() return Error::from_errno(ENOSPC); } +ErrorOr FATFS::notify_cluster_freed() +{ + if (m_fat_version == FATVersion::FAT32 && m_fs_info.last_known_free_cluster_count != fs_info_data_unknown) + TRY(set_free_cluster_count(m_fs_info.last_known_free_cluster_count + 1)); + + return {}; +} + ErrorOr FATFS::fat_read(u32 cluster) { dbgln_if(FAT_DEBUG, "FATFS: Reading FAT entry for cluster {}", cluster); diff --git a/Kernel/FileSystem/FATFS/FileSystem.h b/Kernel/FileSystem/FATFS/FileSystem.h index 736ca4f3726..fa211fbdd3d 100644 --- a/Kernel/FileSystem/FATFS/FileSystem.h +++ b/Kernel/FileSystem/FATFS/FileSystem.h @@ -87,7 +87,10 @@ private: static constexpr u32 first_data_cluster = 2; FatBlockSpan first_block_of_cluster(u32 cluster) const; + + ErrorOr set_free_cluster_count(u32); ErrorOr allocate_cluster(); + ErrorOr notify_cluster_freed(); size_t fat_offset_for_cluster(u32 cluster) const; diff --git a/Kernel/FileSystem/FATFS/Inode.cpp b/Kernel/FileSystem/FATFS/Inode.cpp index 260617161e0..10bd9bd7856 100644 --- a/Kernel/FileSystem/FATFS/Inode.cpp +++ b/Kernel/FileSystem/FATFS/Inode.cpp @@ -346,6 +346,7 @@ ErrorOr FATInode::remove_last_cluster_from_chain() dbgln_if(FAT_DEBUG, "FATInode[{}]::remove_last_cluster_from_chain(): freeing cluster {}", identifier(), last_cluster); + TRY(fs().notify_cluster_freed()); m_cluster_list.remove(m_cluster_list.size() - 1); if (m_cluster_list.is_empty() || (m_cluster_list.size() == 1 && first_cluster() <= 1)) {