Kernel: Start work on proper TmpFS in Heap instead of kmalloc memory

This commit is contained in:
2023-11-04 18:13:52 +02:00
parent 8b4e129fc1
commit 99d7b0917d
6 changed files with 848 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
#pragma once
#include <BAN/Array.h>
#include <kernel/Memory/Types.h>
#include <sys/types.h>
#include <time.h>
namespace Kernel
{
struct TmpInodeInfo
{
mode_t mode { 0 };
uid_t uid { 0 };
gid_t gid { 0 };
timespec atime { 0 };
timespec ctime { 0 };
timespec mtime { 0 };
nlink_t nlink { 0 };
size_t size { 0 };
blkcnt_t blocks { 0 };
// 2x direct blocks
// 1x singly indirect
// 1x doubly indirect
// 1x triply indirect
BAN::Array<paddr_t, 5> block;
static constexpr size_t direct_block_count = 2;
static constexpr size_t max_size =
direct_block_count * PAGE_SIZE +
(PAGE_SIZE / sizeof(paddr_t)) * PAGE_SIZE +
(PAGE_SIZE / sizeof(paddr_t)) * (PAGE_SIZE / sizeof(paddr_t)) * PAGE_SIZE +
(PAGE_SIZE / sizeof(paddr_t)) * (PAGE_SIZE / sizeof(paddr_t)) * (PAGE_SIZE / sizeof(paddr_t)) * PAGE_SIZE;
};
static_assert(sizeof(TmpInodeInfo) == 128);
struct TmpDirectoryEntry
{
ino_t ino;
uint8_t type;
size_t name_len;
size_t rec_len;
char name[];
BAN::StringView name_sv() const
{
ASSERT(type != DT_UNKNOWN);
return BAN::StringView(name, name_len);
}
};
}

View File

@@ -0,0 +1,119 @@
#pragma once
#include <BAN/HashMap.h>
#include <BAN/Iteration.h>
#include <kernel/FS/FileSystem.h>
#include <kernel/FS/TmpFS/Inode.h>
#include <kernel/SpinLock.h>
namespace Kernel
{
template<typename F>
concept for_each_indirect_paddr_allocating_callback = requires(F func, paddr_t paddr, bool was_allocated)
{
requires BAN::is_same_v<decltype(func(paddr, was_allocated)), BAN::Iteration>;
};
class TmpFileSystem : public FileSystem
{
public:
static constexpr size_t no_page_limit = SIZE_MAX;
public:
static BAN::ErrorOr<TmpFileSystem*> create(size_t max_pages, mode_t, uid_t, gid_t);
~TmpFileSystem();
virtual BAN::RefPtr<Inode> root_inode() override { return m_root_inode; }
BAN::ErrorOr<BAN::RefPtr<TmpInode>> open_inode(ino_t ino);
void read_inode(ino_t ino, TmpInodeInfo& out);
void write_inode(ino_t ino, const TmpInodeInfo&);
void delete_inode(ino_t ino);
BAN::ErrorOr<ino_t> allocate_inode(const TmpInodeInfo&);
void read_block(size_t index, BAN::ByteSpan buffer);
void write_block(size_t index, BAN::ConstByteSpan buffer);
void free_block(size_t index);
BAN::ErrorOr<size_t> allocate_block();
private:
struct PageInfo
{
enum Flags : paddr_t
{
Present = 1 << 0,
};
// 12 bottom bits of paddr can be used as flags, since
// paddr will always be page aligned.
static constexpr size_t flag_bits = 12;
static constexpr paddr_t flags_mask = (1 << flag_bits) - 1;
static constexpr paddr_t paddr_mask = ~flags_mask;
static_assert((1 << flag_bits) <= PAGE_SIZE);
paddr_t paddr() const { return raw & paddr_mask; }
paddr_t flags() const { return raw & flags_mask; }
void set_paddr(paddr_t paddr) { raw = (raw & flags_mask) | (paddr & paddr_mask); }
void set_flags(paddr_t flags) { raw = (raw & paddr_mask) | (flags & flags_mask); }
paddr_t raw { 0 };
};
struct InodeLocation
{
paddr_t paddr;
size_t index;
};
private:
TmpFileSystem(size_t max_pages);
BAN::ErrorOr<void> initialize(mode_t, uid_t, gid_t);
InodeLocation find_inode(ino_t ino);
paddr_t find_block(size_t index);
template<for_each_indirect_paddr_allocating_callback F>
BAN::ErrorOr<void> for_each_indirect_paddr_allocating(PageInfo page_info, F callback, size_t depth);
template<for_each_indirect_paddr_allocating_callback F>
BAN::ErrorOr<BAN::Iteration> for_each_indirect_paddr_allocating_internal(PageInfo page_info, F callback, size_t depth);
paddr_t find_indirect(PageInfo root, size_t index, size_t depth);
private:
RecursiveSpinLock m_lock;
BAN::HashMap<ino_t, BAN::RefPtr<TmpInode>> m_inode_cache;
BAN::RefPtr<TmpDirectoryInode> m_root_inode;
// We store pages with triple indirection.
// With 64-bit pointers we can store 512^3 pages of data (512 GiB)
// which should be enough for now.
// In future this should be dynamically calculated based on maximum
// number of pages for this file system.
PageInfo m_data_pages {};
static constexpr size_t first_data_page = 1;
static constexpr size_t max_data_pages =
(PAGE_SIZE / sizeof(PageInfo)) *
(PAGE_SIZE / sizeof(PageInfo)) *
(PAGE_SIZE / sizeof(PageInfo));
// We store inodes in pages with double indirection.
// With 64-bit pointers we can store 512^2 pages of inodes
// which should be enough for now.
// In future this should be dynamically calculated based on maximum
// number of pages for this file system.
PageInfo m_inode_pages;
static constexpr size_t first_inode = 1;
static constexpr size_t max_inodes =
(PAGE_SIZE / sizeof(PageInfo)) *
(PAGE_SIZE / sizeof(PageInfo)) *
(PAGE_SIZE / sizeof(TmpInodeInfo));
const size_t m_max_pages;
};
}

View File

@@ -0,0 +1,103 @@
#pragma once
#include <BAN/Iteration.h>
#include <kernel/FS/Inode.h>
#include <kernel/FS/TmpFS/Definitions.h>
namespace Kernel
{
class TmpFileSystem;
class TmpInode : public Inode
{
public:
virtual ino_t ino() const override final { return m_ino; }
virtual Mode mode() const override final { return Mode(m_inode_info.mode); }
virtual nlink_t nlink() const override final { return m_inode_info.nlink; }
virtual uid_t uid() const override final { return m_inode_info.uid; }
virtual gid_t gid() const override final { return m_inode_info.gid; }
virtual off_t size() const override final { return m_inode_info.size; }
virtual timespec atime() const override final { return m_inode_info.atime; }
virtual timespec mtime() const override final { return m_inode_info.mtime; }
virtual timespec ctime() const override final { return m_inode_info.ctime; }
virtual blksize_t blksize() const override final { return PAGE_SIZE; }
virtual blkcnt_t blocks() const override final { return m_inode_info.blocks; }
virtual dev_t dev() const override final { return 0; } // TODO
virtual dev_t rdev() const override final { return 0; } // TODO
public:
static BAN::ErrorOr<BAN::RefPtr<TmpInode>> create_from_existing(TmpFileSystem&, ino_t, const TmpInodeInfo&);
protected:
TmpInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
void sync();
void free_all_blocks();
size_t block_index(size_t data_block_index);
BAN::ErrorOr<size_t> block_index_with_allocation(size_t data_block_index);
protected:
TmpFileSystem& m_fs;
TmpInodeInfo m_inode_info;
const ino_t m_ino;
// has to be able to increase link count
friend class TmpDirectoryInode;
};
class TmpFileInode : public TmpInode
{
public:
static BAN::ErrorOr<BAN::RefPtr<TmpFileInode>> create(TmpFileSystem&, mode_t, uid_t, gid_t);
~TmpFileInode();
private:
TmpFileInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
friend class TmpInode;
};
class TmpSymlinkInode : public TmpInode
{
public:
~TmpSymlinkInode();
private:
TmpSymlinkInode(TmpFileSystem&, ino_t, const TmpInodeInfo&, BAN::StringView target);
};
template<typename F>
concept for_each_entry_callback = requires(F func, const TmpDirectoryEntry& entry)
{
requires BAN::is_same_v<decltype(func(entry)), BAN::Iteration>;
};
class TmpDirectoryInode : public TmpInode
{
public:
static BAN::ErrorOr<BAN::RefPtr<TmpDirectoryInode>> create_root(TmpFileSystem&, mode_t, uid_t, gid_t);
static BAN::ErrorOr<BAN::RefPtr<TmpDirectoryInode>> create_new(TmpFileSystem&, mode_t, uid_t, gid_t, TmpInode& parent);
~TmpDirectoryInode();
protected:
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override final;
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override final;
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override final;
private:
TmpDirectoryInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
BAN::ErrorOr<void> link_inode(TmpInode&, BAN::StringView);
template<for_each_entry_callback F>
void for_each_entry(F callback);
friend class TmpInode;
};
}