mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 13:28:11 +00: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
12 changed files with 177 additions and 152 deletions
|
@ -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…
Add table
Add a link
Reference in a new issue