Skip to content

Commit

Permalink
Make page_in_from_vnode 2x faster.
Browse files Browse the repository at this point in the history
...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.
  • Loading branch information
awesomekling committed Nov 13, 2018
1 parent 97c7995 commit 10c470e
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 152 deletions.
1 change: 1 addition & 0 deletions AK/RetainPtr.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class RetainPtr {
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();
Expand Down
5 changes: 3 additions & 2 deletions Kernel/MemoryManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
150 changes: 0 additions & 150 deletions Kernel/ext2fs.h

This file was deleted.

93 changes: 93 additions & 0 deletions VirtualFileSystem/Ext2FileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
31 changes: 31 additions & 0 deletions VirtualFileSystem/Ext2FileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -49,6 +72,7 @@ class Ext2FileSystem final : public DiskBackedFileSystem {
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);
Expand Down Expand Up @@ -77,5 +101,12 @@ class Ext2FileSystem final : public DiskBackedFileSystem {

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());
}
1 change: 1 addition & 0 deletions VirtualFileSystem/FileDescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class FileDescriptor : public Retainable<FileDescriptor> {
FileDescriptor(FIFO&, FIFO::Direction);

RetainPtr<VirtualFileSystem::Node> m_vnode;
RetainPtr<CoreInode> m_inode;

Unix::off_t m_currentOffset { 0 };

Expand Down
4 changes: 4 additions & 0 deletions VirtualFileSystem/FileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,7 @@ FileSystem::DirectoryEntry::DirectoryEntry(const char* n, Unix::size_t nl, Inode
memcpy(name, n, nl);
name[nl] = '\0';
}

CoreInode::~CoreInode()
{
}
32 changes: 32 additions & 0 deletions VirtualFileSystem/FileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -50,6 +75,8 @@ class FileSystem : public Retainable<FileSystem> {

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;
Expand Down Expand Up @@ -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<>
Expand Down
Loading

0 comments on commit 10c470e

Please sign in to comment.