Kernel: Start work on proper TmpFS in Heap instead of kmalloc memory
This commit is contained in:
53
kernel/include/kernel/FS/TmpFS/Definitions.h
Normal file
53
kernel/include/kernel/FS/TmpFS/Definitions.h
Normal 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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
119
kernel/include/kernel/FS/TmpFS/FileSystem.h
Normal file
119
kernel/include/kernel/FS/TmpFS/FileSystem.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
||||
103
kernel/include/kernel/FS/TmpFS/Inode.h
Normal file
103
kernel/include/kernel/FS/TmpFS/Inode.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user