mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-08 20:32:56 +03:00
Make page_in_from_vnode 2x faster.
...by adding a new class called Ext2Inode that inherits CoreInode. The idea is that a vnode will wrap a CoreInode rather than InodeIdentifier. Each CoreInode subclass can keep whatever caches they like. Right now, Ext2Inode caches the list of block indices since it can be very expensive to retrieve.
This commit is contained in:
parent
97c799576a
commit
10c470e95f
Notes:
sideshowbarker
2024-07-19 16:10:46 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/10c470e95f1
@ -33,6 +33,7 @@ public:
|
||||
RetainPtr(RetainPtr&& other) : m_ptr(other.leakRef()) { }
|
||||
template<typename U> RetainPtr(RetainPtr<U>&& other) : m_ptr(static_cast<T*>(other.leakRef())) { }
|
||||
RetainPtr(const RetainPtr& other) : m_ptr(const_cast<RetainPtr&>(other).copyRef().leakRef()) { }
|
||||
template<typename U> RetainPtr(const RetainPtr<U>& other) : m_ptr(const_cast<RetainPtr<U>&>(other).copyRef().leakRef()) { }
|
||||
~RetainPtr()
|
||||
{
|
||||
clear();
|
||||
|
@ -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) {
|
||||
|
150
Kernel/ext2fs.h
150
Kernel/ext2fs.h
@ -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
|
@ -310,6 +310,99 @@ Vector<unsigned> 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<CoreInode> 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<Unix::off_t>(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);
|
||||
|
@ -4,12 +4,35 @@
|
||||
#include "UnixTypes.h"
|
||||
#include <AK/Buffer.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#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<unsigned> m_block_list;
|
||||
ext2_inode m_raw_inode;
|
||||
};
|
||||
|
||||
class Ext2FileSystem final : public DiskBackedFileSystem {
|
||||
friend class Ext2Inode;
|
||||
public:
|
||||
static RetainPtr<Ext2FileSystem> create(RetainPtr<DiskDevice>&&);
|
||||
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<CoreInode> 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<unsigned, RetainPtr<CachedExt2InodeImpl>> m_inodeCache;
|
||||
|
||||
mutable SpinLock m_inode_cache_lock;
|
||||
mutable HashMap<BlockIndex, RetainPtr<Ext2Inode>> m_inode_cache;
|
||||
};
|
||||
|
||||
inline Ext2FileSystem& Ext2Inode::fs()
|
||||
{
|
||||
return static_cast<Ext2FileSystem&>(CoreInode::fs());
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ private:
|
||||
FileDescriptor(FIFO&, FIFO::Direction);
|
||||
|
||||
RetainPtr<VirtualFileSystem::Node> m_vnode;
|
||||
RetainPtr<CoreInode> m_inode;
|
||||
|
||||
Unix::off_t m_currentOffset { 0 };
|
||||
|
||||
|
@ -118,3 +118,7 @@ FileSystem::DirectoryEntry::DirectoryEntry(const char* n, Unix::size_t nl, Inode
|
||||
memcpy(name, n, nl);
|
||||
name[nl] = '\0';
|
||||
}
|
||||
|
||||
CoreInode::~CoreInode()
|
||||
{
|
||||
}
|
||||
|
@ -17,6 +17,31 @@
|
||||
static const dword mepoch = 476763780;
|
||||
|
||||
class FileDescriptor;
|
||||
class FileSystem;
|
||||
|
||||
class CoreInode : public Retainable<CoreInode> {
|
||||
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<FileSystem> {
|
||||
public:
|
||||
@ -50,6 +75,8 @@ public:
|
||||
|
||||
virtual InodeIdentifier findParentOfInode(InodeIdentifier) const = 0;
|
||||
|
||||
virtual RetainPtr<CoreInode> 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<>
|
||||
|
@ -249,3 +249,8 @@ InodeIdentifier SyntheticFileSystem::findParentOfInode(InodeIdentifier inode) co
|
||||
return { };
|
||||
return (*it).value->parent;
|
||||
}
|
||||
|
||||
RetainPtr<CoreInode> SyntheticFileSystem::get_inode(InodeIdentifier)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -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<CoreInode> get_inode(InodeIdentifier) override;
|
||||
|
||||
protected:
|
||||
typedef unsigned InodeIndex;
|
||||
|
@ -54,6 +54,8 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node>
|
||||
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<Node>
|
||||
fileSystem->retain();
|
||||
|
||||
vnode->inode = inode;
|
||||
vnode->m_core_inode = move(core_inode);
|
||||
vnode->m_cachedMetadata = { };
|
||||
|
||||
#ifdef VFS_DEBUG
|
||||
|
@ -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<CoreInode> m_core_inode;
|
||||
};
|
||||
|
||||
static VirtualFileSystem& the() PURE;
|
||||
|
Loading…
Reference in New Issue
Block a user