diff --git a/AK/RetainPtr.h b/AK/RetainPtr.h index b5c7c370a2..582cf358d7 100644 --- a/AK/RetainPtr.h +++ b/AK/RetainPtr.h @@ -33,6 +33,7 @@ public: RetainPtr(RetainPtr&& other) : m_ptr(other.leakRef()) { } template RetainPtr(RetainPtr&& other) : m_ptr(static_cast(other.leakRef())) { } RetainPtr(const RetainPtr& other) : m_ptr(const_cast(other).copyRef().leakRef()) { } + template RetainPtr(const RetainPtr& other) : m_ptr(const_cast&>(other).copyRef().leakRef()) { } ~RetainPtr() { clear(); diff --git a/Kernel/MemoryManager.cpp b/Kernel/MemoryManager.cpp index 37db9902df..c5ec1dc603 100644 --- a/Kernel/MemoryManager.cpp +++ b/Kernel/MemoryManager.cpp @@ -293,9 +293,10 @@ bool MemoryManager::page_in_from_vnode(PageDirectory& page_directory, Region& re dbgprintf("MM: page_in_from_vnode ready to read from vnode, will write to L%x!\n", dest_ptr); #endif sti(); // Oh god here we go... - auto nread = vnode.fileSystem()->readInodeBytes(vnode.inode, vmo.vnode_offset() + ((region.first_page_index() + page_index_in_region) * PAGE_SIZE), PAGE_SIZE, dest_ptr, nullptr); + ASSERT(vnode.core_inode()); + auto nread = vnode.core_inode()->read_bytes(vmo.vnode_offset() + ((region.first_page_index() + page_index_in_region) * PAGE_SIZE), PAGE_SIZE, dest_ptr, nullptr); if (nread < 0) { - kprintf("MM: page_in_form_vnode had error (%d) while reading!\n", nread); + kprintf("MM: page_in_from_vnode had error (%d) while reading!\n", nread); return false; } if (nread < PAGE_SIZE) { diff --git a/Kernel/ext2fs.h b/Kernel/ext2fs.h deleted file mode 100644 index 638c4002d4..0000000000 --- a/Kernel/ext2fs.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef __ext2fs_h__ -#define __ext2fs_h__ - -#include "types.h" - -#define EXT2_MAGIC 0xef53 -#define EXT2_NDIR_BLOCKS 12 -#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS -#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) -#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) -#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) -#define EXT2_NAME_LEN 255 - -#define EXT2_FT_UNKNOWN 0 -#define EXT2_FT_REG_FILE 1 -#define EXT2_FT_DIR 2 -#define EXT2_FT_CHRDEV 3 -#define EXT2_FT_BLKDEV 4 -#define EXT2_FT_FIFO 5 -#define EXT2_FT_SOCK 6 -#define EXT2_FT_SYMLINK 7 - -typedef struct -{ - __u32 s_inodes_count; /* Inodes count */ - __u32 s_blocks_count; /* Blocks count */ - __u32 s_r_blocks_count; /* Reserved blocks count */ - __u32 s_free_blocks_count; /* Free blocks count */ - __u32 s_free_inodes_count; /* Free inodes count */ - __u32 s_first_data_block; /* First Data Block */ - __u32 s_log_block_size; /* Block size */ - __s32 s_log_frag_size; /* Fragment size */ - __u32 s_blocks_per_group; /* # Blocks per group */ - __u32 s_frags_per_group; /* # Fragments per group */ - __u32 s_inodes_per_group; /* # Inodes per group */ - __u32 s_mtime; /* Mount time */ - __u32 s_wtime; /* Write time */ - __u16 s_mnt_count; /* Mount count */ - __s16 s_max_mnt_count; /* Maximal mount count */ - __u16 s_magic; /* Magic signature */ - __u16 s_state; /* File system state */ - __u16 s_errors; /* Behaviour when detecting errors */ - __u16 s_pad; - __u32 s_lastcheck; /* time of last check */ - __u32 s_checkinterval; /* max. time between checks */ - __u32 s_creator_os; /* OS */ - __u32 s_rev_level; /* Revision level */ - __u16 s_def_resuid; /* Default uid for reserved blocks */ - __u16 s_def_resgid; /* Default gid for reserved blocks */ - __u32 s_first_ino; // First non-reserved inode - __u16 s_inode_size; // inode size - __u16 s_block_group_nr; // Index of block group hosting this superblock - __u32 s_feature_compat; - __u32 s_feature_incompat; - __u32 s_feature_ro_compat; - __u8 s_uuid[16]; - __u32 s_reserved[226]; /* Padding to the end of the block */ -} PACKED ext2_super_block; - -typedef struct -{ - __u32 bg_block_bitmap; - __u32 bg_inode_bitmap; - __u32 bg_inode_table; - __u16 bg_free_blocks_count; - __u16 bg_free_inodes_count; - __u16 bg_used_dirs_count; - __u16 bg_pad; - __u32 bg_reserved; -} PACKED ext2_group_descriptor; - -typedef struct -{ - __u16 i_mode; /* File mode */ - __u16 i_uid; /* Owner Uid */ - __u32 i_size; /* 4: Size in bytes */ - __u32 i_atime; /* Access time */ - __u32 i_ctime; /* 12: Creation time */ - __u32 i_mtime; /* Modification time */ - __u32 i_dtime; /* 20: Deletion Time */ - __u16 i_gid; /* Group Id */ - __u16 i_links_count; /* 24: Links count */ - __u32 i_blocks; /* Blocks count */ - __u32 i_flags; /* 32: File flags */ - union - { - struct - { - __u32 l_i_reserved1; - } - linux1; - struct - { - __u32 h_i_translator; - } - hurd1; - struct - { - __u32 m_i_reserved1; - } - masix1; - } - osd1; /* OS dependent 1 */ - __u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */ - __u32 i_version; /* File version (for NFS) */ - __u32 i_file_acl; /* File ACL */ - __u32 i_dir_acl; /* Directory ACL */ - __u32 i_faddr; /* Fragment address */ - union - { - struct - { - __u8 l_i_frag; /* Fragment number */ - __u8 l_i_fsize; /* Fragment size */ - __u16 i_pad1; - __u32 l_i_reserved2[2]; - } - linux2; - struct - { - __u8 h_i_frag; /* Fragment number */ - __u8 h_i_fsize; /* Fragment size */ - __u16 h_i_mode_high; - __u16 h_i_uid_high; - __u16 h_i_gid_high; - __u32 h_i_author; - } - hurd2; - struct - { - __u8 m_i_frag; /* Fragment number */ - __u8 m_i_fsize; /* Fragment size */ - __u16 m_pad1; - __u32 m_i_reserved2[2]; - } - masix2; - } - osd2; /* OS dependent 2 */ -} PACKED ext2_inode; - -typedef struct -{ - __u32 d_inode; - __u16 d_rec_len; - __u8 d_name_len; - __u8 d_file_type; - char d_name[EXT2_NAME_LEN]; -} PACKED ext2_dir_entry; - -#endif diff --git a/VirtualFileSystem/Ext2FileSystem.cpp b/VirtualFileSystem/Ext2FileSystem.cpp index 36053d54d5..1f2fd37c52 100644 --- a/VirtualFileSystem/Ext2FileSystem.cpp +++ b/VirtualFileSystem/Ext2FileSystem.cpp @@ -310,6 +310,99 @@ Vector Ext2FileSystem::blockListForInode(const ext2_inode& e2inode) co return list; } +Ext2Inode::Ext2Inode(Ext2FileSystem& fs, unsigned index, const ext2_inode& raw_inode) + : CoreInode(fs, index) + , m_raw_inode(raw_inode) +{ +} + +Ext2Inode::~Ext2Inode() +{ +} + +RetainPtr Ext2FileSystem::get_inode(InodeIdentifier inode) +{ + ASSERT(inode.fileSystemID() == id()); + { + LOCKER(m_inode_cache_lock); + auto it = m_inode_cache.find(inode.index()); + if (it != m_inode_cache.end()) + return (*it).value; + } + auto raw_inode = lookupExt2Inode(inode.index()); + if (!raw_inode) + return nullptr; + LOCKER(m_inode_cache_lock); + auto it = m_inode_cache.find(inode.index()); + if (it != m_inode_cache.end()) + return (*it).value; + auto new_inode = adopt(*new Ext2Inode(*this, inode.index(), *raw_inode)); + m_inode_cache.set(inode.index(), new_inode.copyRef()); + return new_inode; +} + +Unix::ssize_t Ext2Inode::read_bytes(Unix::off_t offset, Unix::size_t count, byte* buffer, FileDescriptor*) +{ + ASSERT(offset >= 0); + if (m_raw_inode.i_size == 0) + return 0; + + // Symbolic links shorter than 60 characters are store inline inside the i_block array. + // This avoids wasting an entire block on short links. (Most links are short.) + static const unsigned max_inline_symlink_length = 60; + if (is_symlink() && size() < max_inline_symlink_length) { + Unix::ssize_t nread = min((Unix::off_t)size() - offset, static_cast(count)); + memcpy(buffer, m_raw_inode.i_block + offset, nread); + return nread; + } + + if (m_block_list.isEmpty()) { + auto block_list = fs().blockListForInode(m_raw_inode); + LOCKER(m_lock); + if (m_block_list.size() != block_list.size()) + m_block_list = move(block_list); + } + + if (m_block_list.isEmpty()) { + kprintf("ext2fs: read_bytes: empty block list for inode %u\n", index()); + return -EIO; + } + + const size_t block_size = fs().blockSize(); + + dword first_block_logical_index = offset / block_size; + dword last_block_logical_index = (offset + count) / block_size; + if (last_block_logical_index >= m_block_list.size()) + last_block_logical_index = m_block_list.size() - 1; + + dword offset_into_first_block = offset % block_size; + + Unix::ssize_t nread = 0; + Unix::size_t remaining_count = min((Unix::off_t)count, (Unix::off_t)size() - offset); + byte* out = buffer; + +#ifdef EXT2_DEBUG + kprintf("ok let's do it, read(%llu, %u) -> blocks %u thru %u, oifb: %u\n", offset, count, firstBlockLogicalIndex, lastBlockLogicalIndex, offsetIntoFirstBlock); +#endif + + for (dword bi = first_block_logical_index; remaining_count && bi <= last_block_logical_index; ++bi) { + auto block = fs().readBlock(m_block_list[bi]); + if (!block) { + kprintf("ext2fs: read_bytes: readBlock(%u) failed (lbi: %u)\n", m_block_list[bi], bi); + return -EIO; + } + + dword offset_into_block = (bi == first_block_logical_index) ? offset_into_first_block : 0; + dword num_bytes_to_copy = min(block_size - offset_into_block, remaining_count); + memcpy(out, block.pointer() + offset_into_block, num_bytes_to_copy); + remaining_count -= num_bytes_to_copy; + nread += num_bytes_to_copy; + out += num_bytes_to_copy; + } + + return nread; +} + Unix::ssize_t Ext2FileSystem::readInodeBytes(InodeIdentifier inode, Unix::off_t offset, Unix::size_t count, byte* buffer, FileDescriptor*) const { ASSERT(offset >= 0); diff --git a/VirtualFileSystem/Ext2FileSystem.h b/VirtualFileSystem/Ext2FileSystem.h index f9ec97922e..da1ae1a12c 100644 --- a/VirtualFileSystem/Ext2FileSystem.h +++ b/VirtualFileSystem/Ext2FileSystem.h @@ -4,12 +4,35 @@ #include "UnixTypes.h" #include #include +#include "ext2_fs.h" struct ext2_group_desc; struct ext2_inode; struct ext2_super_block; +class Ext2FileSystem; + +class Ext2Inode final : public CoreInode { + friend class Ext2FileSystem; +public: + virtual ~Ext2Inode() override; + + virtual Unix::ssize_t read_bytes(Unix::off_t, Unix::size_t, byte* buffer, FileDescriptor*) override; + + size_t size() const { return m_raw_inode.i_size; } + bool is_symlink() const { return isSymbolicLink(m_raw_inode.i_mode); } + +private: + Ext2FileSystem& fs(); + Ext2Inode(Ext2FileSystem&, unsigned index, const ext2_inode&); + + SpinLock m_lock; + Vector m_block_list; + ext2_inode m_raw_inode; +}; + class Ext2FileSystem final : public DiskBackedFileSystem { + friend class Ext2Inode; public: static RetainPtr create(RetainPtr&&); virtual ~Ext2FileSystem() override; @@ -49,6 +72,7 @@ private: virtual Unix::ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer, FileDescriptor*) const override; virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override; virtual InodeIdentifier findParentOfInode(InodeIdentifier) const override; + virtual RetainPtr get_inode(InodeIdentifier) override; bool isDirectoryInode(unsigned) const; unsigned allocateInode(unsigned preferredGroup, unsigned expectedSize); @@ -77,5 +101,12 @@ private: mutable SpinLock m_inodeCacheLock; mutable HashMap> m_inodeCache; + + mutable SpinLock m_inode_cache_lock; + mutable HashMap> m_inode_cache; }; +inline Ext2FileSystem& Ext2Inode::fs() +{ + return static_cast(CoreInode::fs()); +} diff --git a/VirtualFileSystem/FileDescriptor.h b/VirtualFileSystem/FileDescriptor.h index 6e41729d8f..66ebb9f15b 100644 --- a/VirtualFileSystem/FileDescriptor.h +++ b/VirtualFileSystem/FileDescriptor.h @@ -67,6 +67,7 @@ private: FileDescriptor(FIFO&, FIFO::Direction); RetainPtr m_vnode; + RetainPtr m_inode; Unix::off_t m_currentOffset { 0 }; diff --git a/VirtualFileSystem/FileSystem.cpp b/VirtualFileSystem/FileSystem.cpp index 4747e1e25c..a5aed9be0b 100644 --- a/VirtualFileSystem/FileSystem.cpp +++ b/VirtualFileSystem/FileSystem.cpp @@ -118,3 +118,7 @@ FileSystem::DirectoryEntry::DirectoryEntry(const char* n, Unix::size_t nl, Inode memcpy(name, n, nl); name[nl] = '\0'; } + +CoreInode::~CoreInode() +{ +} diff --git a/VirtualFileSystem/FileSystem.h b/VirtualFileSystem/FileSystem.h index 6c203b93e7..518a713de8 100644 --- a/VirtualFileSystem/FileSystem.h +++ b/VirtualFileSystem/FileSystem.h @@ -17,6 +17,31 @@ static const dword mepoch = 476763780; class FileDescriptor; +class FileSystem; + +class CoreInode : public Retainable { +public: + virtual ~CoreInode(); + + FileSystem& fs() const { return m_fs; } + unsigned fsid() const; + unsigned index() const { return m_index; } + + InodeIdentifier identifier() const { return { fsid(), index() }; } + + virtual Unix::ssize_t read_bytes(Unix::off_t, Unix::size_t, byte* buffer, FileDescriptor*) = 0; + +protected: + CoreInode(FileSystem& fs, unsigned index) + : m_fs(fs) + , m_index(index) + { + } + +private: + FileSystem& m_fs; + unsigned m_index { 0 }; +}; class FileSystem : public Retainable { public: @@ -50,6 +75,8 @@ public: virtual InodeIdentifier findParentOfInode(InodeIdentifier) const = 0; + virtual RetainPtr get_inode(InodeIdentifier) = 0; + InodeIdentifier childOfDirectoryInodeWithName(InodeIdentifier, const String& name) const; ByteBuffer readEntireInode(InodeIdentifier, FileDescriptor* = nullptr) const; String nameOfChildInDirectory(InodeIdentifier parent, InodeIdentifier child) const; @@ -83,6 +110,11 @@ inline bool InodeIdentifier::isRootInode() const return (*this) == fileSystem()->rootInode(); } +inline unsigned CoreInode::fsid() const +{ + return m_fs.id(); +} + namespace AK { template<> diff --git a/VirtualFileSystem/SyntheticFileSystem.cpp b/VirtualFileSystem/SyntheticFileSystem.cpp index 676aff6b80..8343ffb438 100644 --- a/VirtualFileSystem/SyntheticFileSystem.cpp +++ b/VirtualFileSystem/SyntheticFileSystem.cpp @@ -249,3 +249,8 @@ InodeIdentifier SyntheticFileSystem::findParentOfInode(InodeIdentifier inode) co return { }; return (*it).value->parent; } + +RetainPtr SyntheticFileSystem::get_inode(InodeIdentifier) +{ + return nullptr; +} diff --git a/VirtualFileSystem/SyntheticFileSystem.h b/VirtualFileSystem/SyntheticFileSystem.h index 2c931f2ed8..acfe6eefb3 100644 --- a/VirtualFileSystem/SyntheticFileSystem.h +++ b/VirtualFileSystem/SyntheticFileSystem.h @@ -20,6 +20,7 @@ public: virtual Unix::ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer, FileDescriptor*) const override; virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override; virtual InodeIdentifier findParentOfInode(InodeIdentifier) const override; + virtual RetainPtr get_inode(InodeIdentifier) override; protected: typedef unsigned InodeIndex; diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp index d6f9301cad..01f9959aaa 100644 --- a/VirtualFileSystem/VirtualFileSystem.cpp +++ b/VirtualFileSystem/VirtualFileSystem.cpp @@ -54,6 +54,8 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr if (!metadata.isValid()) return nullptr; + auto core_inode = inode.fileSystem()->get_inode(inode); + InterruptDisabler disabler; CharacterDevice* characterDevice = nullptr; @@ -74,6 +76,7 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr fileSystem->retain(); vnode->inode = inode; + vnode->m_core_inode = move(core_inode); vnode->m_cachedMetadata = { }; #ifdef VFS_DEBUG diff --git a/VirtualFileSystem/VirtualFileSystem.h b/VirtualFileSystem/VirtualFileSystem.h index 782c24b271..ebc7c3e779 100644 --- a/VirtualFileSystem/VirtualFileSystem.h +++ b/VirtualFileSystem/VirtualFileSystem.h @@ -78,6 +78,8 @@ public: unsigned retain_count() const { return retainCount; } + CoreInode* core_inode() { return m_core_inode.ptr(); } + private: friend class VirtualFileSystem; VirtualFileSystem* m_vfs { nullptr }; @@ -85,6 +87,7 @@ public: CharacterDevice* m_characterDevice { nullptr }; mutable InodeMetadata m_cachedMetadata; void* m_vmo { nullptr }; + RetainPtr m_core_inode; }; static VirtualFileSystem& the() PURE;