From 33f00a7efb14fd08e5f6c5cc514eac7b8ccd6da3 Mon Sep 17 00:00:00 2001 From: Undefine Date: Tue, 16 Jan 2024 21:24:45 +0100 Subject: [PATCH] Kernel/FATFS: Cache the cluster list and don't cache the InodeMetadata Caching the cluster list allows us to fill the two fields in the InodeMetadata. While at it, don't cache the metadata as when we have write support having to keep both InodeMetadata and FATEntry correct is going to get very annoying. --- Kernel/FileSystem/FATFS/FileSystem.cpp | 17 ++++++ Kernel/FileSystem/FATFS/FileSystem.h | 5 ++ Kernel/FileSystem/FATFS/Inode.cpp | 79 +++++++++++--------------- Kernel/FileSystem/FATFS/Inode.h | 8 +-- 4 files changed, 55 insertions(+), 54 deletions(-) diff --git a/Kernel/FileSystem/FATFS/FileSystem.cpp b/Kernel/FileSystem/FATFS/FileSystem.cpp index 9580f721324..ff0617a1c3f 100644 --- a/Kernel/FileSystem/FATFS/FileSystem.cpp +++ b/Kernel/FileSystem/FATFS/FileSystem.cpp @@ -354,6 +354,23 @@ u32 FATFS::cluster_number(KBuffer const& fat_sector, u32 entry_cluster_number, u return cluster; } +u32 FATFS::end_of_chain_marker() const +{ + // Returns the end of chain entry for the given file system. + // Any FAT entry of this value or greater signifies the end + // of the chain has been reached for a given entry. + switch (m_fat_version) { + case FATVersion::FAT12: + return 0xFF8; + case FATVersion::FAT16: + return 0xFFF8; + case FATVersion::FAT32: + return 0x0FFFFFF8; + default: + VERIFY_NOT_REACHED(); + } +} + 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 fe5a0c7abbd..8c028979a0a 100644 --- a/Kernel/FileSystem/FATFS/FileSystem.h +++ b/Kernel/FileSystem/FATFS/FileSystem.h @@ -91,6 +91,11 @@ private: // Reads the cluster number located at the offset within the table. u32 cluster_number(KBuffer const& fat_sector, u32 entry_cluster_number, u32 entry_offset) const; + // Returns cluster number value that indicates the end of the chain + // has been reached. Any cluster value >= this value indicates this + // is the last cluster. + u32 end_of_chain_marker() const; + ErrorOr fat_read(u32 cluster); ErrorOr fat_write(u32 cluster, u32 value); diff --git a/Kernel/FileSystem/FATFS/Inode.cpp b/Kernel/FileSystem/FATFS/Inode.cpp index 13b505eeea9..0dd89ea2103 100644 --- a/Kernel/FileSystem/FATFS/Inode.cpp +++ b/Kernel/FileSystem/FATFS/Inode.cpp @@ -14,7 +14,13 @@ namespace Kernel { ErrorOr> FATInode::create(FATFS& fs, FATEntry entry, FATEntryLocation inode_metadata_location, Vector const& lfn_entries) { auto filename = TRY(compute_filename(entry, lfn_entries)); - return adopt_nonnull_ref_or_enomem(new (nothrow) FATInode(fs, entry, inode_metadata_location, move(filename))); + u32 entry_first_cluster = entry.first_cluster_low; + if (fs.m_fat_version == FATVersion::FAT32) + entry_first_cluster |= (static_cast(entry.first_cluster_high) << 16); + auto inode = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) FATInode(fs, entry, inode_metadata_location, move(filename)))); + MutexLocker locker(inode->m_inode_lock); + inode->m_cluster_list = TRY(inode->compute_cluster_list(fs, entry_first_cluster)); + return inode; } FATInode::FATInode(FATFS& fs, FATEntry entry, FATEntryLocation inode_metadata_location, NonnullOwnPtr filename) @@ -24,37 +30,20 @@ FATInode::FATInode(FATFS& fs, FATEntry entry, FATEntryLocation inode_metadata_lo , m_filename(move(filename)) { dbgln_if(FAT_DEBUG, "FATFS: Creating inode {} with filename \"{}\"", index(), m_filename); - - m_metadata = { - .inode = identifier(), - .size = m_entry.file_size, - .mode = static_cast((has_flag(m_entry.attributes, FATAttributes::Directory) ? S_IFDIR : S_IFREG) | 0777), - .uid = 0, - .gid = 0, - .link_count = 0, - .atime = time_from_packed_dos(m_entry.last_accessed_date, { 0 }), - .ctime = time_from_packed_dos(m_entry.creation_date, m_entry.creation_time), - .mtime = time_from_packed_dos(m_entry.modification_date, m_entry.modification_time), - .dtime = {}, - .block_count = 0, - .block_size = 0, - .major_device = 0, - .minor_device = 0, - }; } -ErrorOr> FATInode::compute_cluster_list() +ErrorOr> FATInode::compute_cluster_list(FATFS& fs, u32 first_cluster) { VERIFY(m_inode_lock.is_locked()); - dbgln_if(FAT_DEBUG, "FATFS: computing cluster list for inode {}", index()); + dbgln_if(FAT_DEBUG, "FATFS: computing block list starting with cluster {}", first_cluster); - u32 cluster = first_cluster(); + u32 cluster = first_cluster; Vector cluster_list; - while (cluster < end_of_chain_marker()) { - dbgln_if(FAT_DEBUG, "FATFS: Appending cluster {} to inode {}'s cluster chain", cluster, index()); + while (cluster < fs.end_of_chain_marker()) { + dbgln_if(FAT_DEBUG, "FATFS: Appending cluster {} to cluster chain starting with {}", cluster, first_cluster); TRY(cluster_list.try_append(cluster)); @@ -75,7 +64,7 @@ ErrorOr> FATInode::compute_cluster_list() } // Look up the next cluster to read, or read End of Chain marker from table. - cluster = TRY(fs().fat_read(cluster)); + cluster = TRY(fs.fat_read(cluster)); } return cluster_list; @@ -89,9 +78,6 @@ ErrorOr> FATInode::get_block_list() Vector block_list; - if (m_cluster_list.is_empty()) - m_cluster_list = TRY(compute_cluster_list()); - for (auto cluster : m_cluster_list) { auto span = fs().first_block_of_cluster(cluster); for (size_t i = 0; i < span.number_of_sectors; i++) { @@ -103,23 +89,6 @@ ErrorOr> FATInode::get_block_list() return block_list; } -u32 FATInode::end_of_chain_marker() const -{ - // Returns the end of chain entry for the given file system. - // Any FAT entry of this value or greater signifies the end - // of the chain has been reached for a given entry. - switch (fs().m_fat_version) { - case FATVersion::FAT12: - return 0xFF8; - case FATVersion::FAT16: - return 0xFFF8; - case FATVersion::FAT32: - return 0x0FFFFFF8; - default: - VERIFY_NOT_REACHED(); - } -} - ErrorOr> FATInode::read_block_list() { VERIFY(m_inode_lock.is_locked()); @@ -275,7 +244,7 @@ ErrorOr FATInode::read_bytes_locked(off_t offset, size_t size, UserOrKer { dbgln_if(FAT_DEBUG, "FATFS: Reading inode {}: size: {} offset: {}", identifier().index(), size, offset); VERIFY(offset >= 0); - if (offset >= m_metadata.size) + if (offset >= m_entry.file_size) return 0; // FIXME: Read only the needed blocks instead of the whole file @@ -286,7 +255,7 @@ ErrorOr FATInode::read_bytes_locked(off_t offset, size_t size, UserOrKer // 2. The file size. // 3. The number of blocks returned for reading. size_t read_size = min( - min(size, m_metadata.size - offset), + min(size, m_entry.file_size - offset), (m_cluster_list.size() * fs().m_device_block_size * fs().m_parameter_block->common_bpb()->sectors_per_cluster) - offset); TRY(buffer.write(blocks->data() + offset, read_size)); @@ -295,7 +264,23 @@ ErrorOr FATInode::read_bytes_locked(off_t offset, size_t size, UserOrKer InodeMetadata FATInode::metadata() const { - return m_metadata; + return { + .inode = identifier(), + .size = m_entry.file_size, + // FIXME: Linux also removes the write permission if the file has the read only attribute set. + .mode = static_cast((has_flag(m_entry.attributes, FATAttributes::Directory) ? S_IFDIR : S_IFREG) | 0777), + .uid = 0, + .gid = 0, + .link_count = 0, + .atime = time_from_packed_dos(m_entry.last_accessed_date, { 0 }), + .ctime = time_from_packed_dos(m_entry.creation_date, m_entry.creation_time), + .mtime = time_from_packed_dos(m_entry.modification_date, m_entry.modification_time), + .dtime = {}, + .block_count = m_cluster_list.size() * fs().m_parameter_block->common_bpb()->sectors_per_cluster, + .block_size = fs().m_device_block_size, + .major_device = 0, + .minor_device = 0, + }; } ErrorOr FATInode::traverse_as_directory(Function(FileSystem::DirectoryEntryView const&)> callback) const diff --git a/Kernel/FileSystem/FATFS/Inode.h b/Kernel/FileSystem/FATFS/Inode.h index e913fe5ee8e..335a7d3463d 100644 --- a/Kernel/FileSystem/FATFS/Inode.h +++ b/Kernel/FileSystem/FATFS/Inode.h @@ -35,11 +35,6 @@ public: private: FATInode(FATFS&, FATEntry, FATEntryLocation inode_metadata_location, NonnullOwnPtr filename); - // Returns cluster number value that indicates the end of the chain - // has been reached. Any cluster value >= this value indicates this - // is the last cluster. - u32 end_of_chain_marker() const; - static constexpr u8 end_entry_byte = 0x00; static constexpr u8 unused_entry_byte = 0xE5; @@ -52,7 +47,7 @@ private: static ErrorOr> compute_filename(FATEntry&, Vector const& = {}); static StringView byte_terminated_string(StringView, u8); - ErrorOr> compute_cluster_list(); + ErrorOr> compute_cluster_list(FATFS&, u32 first_cluster); ErrorOr> get_block_list(); ErrorOr> read_block_list(); ErrorOr> traverse(Function(RefPtr)> callback); @@ -81,7 +76,6 @@ private: FATEntry m_entry; FATEntryLocation m_inode_metadata_location; NonnullOwnPtr m_filename; - InodeMetadata m_metadata; }; }