From f1089e2b8a6b286732c577c347d20bd3694ec4ed Mon Sep 17 00:00:00 2001 From: Bananymous Date: Mon, 10 Jul 2023 13:26:14 +0300 Subject: [PATCH] Kernel: start work on ram file system --- kernel/CMakeLists.txt | 2 + kernel/include/kernel/FS/RamFS/FileSystem.h | 40 +++++ kernel/include/kernel/FS/RamFS/Inode.h | 95 ++++++++++++ kernel/kernel/FS/RamFS/FileSystem.cpp | 45 ++++++ kernel/kernel/FS/RamFS/Inode.cpp | 161 ++++++++++++++++++++ kernel/kernel/FS/VirtualFileSystem.cpp | 13 +- 6 files changed, 355 insertions(+), 1 deletion(-) create mode 100644 kernel/include/kernel/FS/RamFS/FileSystem.h create mode 100644 kernel/include/kernel/FS/RamFS/Inode.h create mode 100644 kernel/kernel/FS/RamFS/FileSystem.cpp create mode 100644 kernel/kernel/FS/RamFS/Inode.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 475d3f41f..386fce495 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -21,6 +21,8 @@ set(KERNEL_SOURCES kernel/FS/Ext2.cpp kernel/FS/Inode.cpp kernel/FS/Pipe.cpp + kernel/FS/RamFS/FileSystem.cpp + kernel/FS/RamFS/Inode.cpp kernel/FS/VirtualFileSystem.cpp kernel/Input/PS2Controller.cpp kernel/Input/PS2Keyboard.cpp diff --git a/kernel/include/kernel/FS/RamFS/FileSystem.h b/kernel/include/kernel/FS/RamFS/FileSystem.h new file mode 100644 index 000000000..eb40c7ccc --- /dev/null +++ b/kernel/include/kernel/FS/RamFS/FileSystem.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include + +namespace Kernel +{ + + class RamInode; + + class RamFileSystem final : public FileSystem + { + public: + static BAN::ErrorOr create(size_t size, mode_t, uid_t, gid_t); + ~RamFileSystem() = default; + + virtual BAN::RefPtr root_inode() override { return m_inodes[m_root_inode]; } + + BAN::ErrorOr add_inode(BAN::RefPtr); + BAN::ErrorOr> get_inode(ino_t); + + blksize_t blksize() const { return m_blksize; } + ino_t next_ino() { return m_next_ino++; } + + private: + RamFileSystem() = default; + + private: + SpinLock m_lock; + size_t m_size { 0 }; + + BAN::HashMap> m_inodes; + ino_t m_root_inode; + + const blksize_t m_blksize = PAGE_SIZE; + ino_t m_next_ino { 1 }; + }; + +} \ No newline at end of file diff --git a/kernel/include/kernel/FS/RamFS/Inode.h b/kernel/include/kernel/FS/RamFS/Inode.h new file mode 100644 index 000000000..9ec183f75 --- /dev/null +++ b/kernel/include/kernel/FS/RamFS/Inode.h @@ -0,0 +1,95 @@ +#pragma once + +#include + +#include + +namespace Kernel +{ + + class RamFileSystem; + + class RamInode : public Inode + { + public: + virtual ~RamInode() = default; + + virtual ino_t ino() const override { return m_inode_info.ino; } + virtual Mode mode() const override { return { m_inode_info.mode }; } + virtual nlink_t nlink() const override { return m_inode_info.nlink; } + virtual uid_t uid() const override { return m_inode_info.uid; } + virtual gid_t gid() const override { return m_inode_info.gid; } + virtual off_t size() const override { return m_inode_info.size; } + virtual timespec atime() const override { return m_inode_info.atime; } + virtual timespec mtime() const override { return m_inode_info.mtime; } + virtual timespec ctime() const override { return m_inode_info.ctime; } + virtual blksize_t blksize() const override { return m_inode_info.blksize; } + virtual blkcnt_t blocks() const override { return m_inode_info.blocks; } + virtual dev_t dev() const override { return m_inode_info.dev; } + virtual dev_t rdev() const override { return m_inode_info.rdev; } + + virtual BAN::StringView name() const override { ASSERT_NOT_REACHED(); } + + void add_link() { m_inode_info.nlink++; } + + protected: + RamInode(RamFileSystem& fs, mode_t, uid_t, gid_t); + static BAN::ErrorOr> create(RamFileSystem&, mode_t, uid_t, gid_t); + + protected: + struct FullInodeInfo + { + ino_t ino; + mode_t mode; + nlink_t nlink; + uid_t uid; + gid_t gid; + off_t size; + timespec atime; + timespec mtime; + timespec ctime; + blksize_t blksize; + blkcnt_t blocks; + dev_t dev; + dev_t rdev; + }; + + protected: + RamFileSystem& m_fs; + FullInodeInfo m_inode_info; + + BAN::Vector m_data; + + friend class RamFileSystem; + }; + + class RamDirectoryInode final : public RamInode + { + public: + ~RamDirectoryInode() = default; + + virtual BAN::ErrorOr> directory_find_inode(BAN::StringView) override; + virtual BAN::ErrorOr directory_read_next_entries(off_t, DirectoryEntryList*, size_t) override; + virtual BAN::ErrorOr create_file(BAN::StringView, mode_t) override; + + private: + RamDirectoryInode(RamFileSystem&, ino_t parent, mode_t, uid_t, gid_t); + static BAN::ErrorOr> create(RamFileSystem&, ino_t parent, mode_t, uid_t, gid_t); + + private: + static constexpr size_t m_name_max = NAME_MAX; + struct Entry + { + char name[m_name_max + 1]; + size_t name_len = 0; + ino_t ino; + }; + + private: + BAN::Vector m_entries; + ino_t m_parent; + + friend class RamFileSystem; + }; + +} \ No newline at end of file diff --git a/kernel/kernel/FS/RamFS/FileSystem.cpp b/kernel/kernel/FS/RamFS/FileSystem.cpp new file mode 100644 index 000000000..010ea2550 --- /dev/null +++ b/kernel/kernel/FS/RamFS/FileSystem.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include + +namespace Kernel +{ + + BAN::ErrorOr RamFileSystem::create(size_t size, mode_t mode, uid_t uid, gid_t gid) + { + auto* ramfs = new RamFileSystem; + if (ramfs == nullptr) + return BAN::Error::from_errno(ENOMEM); + ramfs->m_size = size; + + BAN::ScopeGuard deleter([ramfs] { delete ramfs; }); + + auto root_inode = TRY(RamDirectoryInode::create(*ramfs, 0, mode, uid, gid)); + TRY(ramfs->add_inode(root_inode)); + ramfs->m_root_inode = root_inode->ino(); + + deleter.disable(); + + return ramfs; + } + + BAN::ErrorOr RamFileSystem::add_inode(BAN::RefPtr inode) + { + LockGuard _(m_lock); + if (m_inodes.contains(inode->ino())) + return BAN::Error::from_errno(EEXIST); + TRY(m_inodes.insert(inode->ino(), inode)); + return {}; + } + + BAN::ErrorOr> RamFileSystem::get_inode(ino_t ino) + { + LockGuard _(m_lock); + if (!m_inodes.contains(ino)) + return BAN::Error::from_errno(ENOENT); + return m_inodes[ino]; + } + +} \ No newline at end of file diff --git a/kernel/kernel/FS/RamFS/Inode.cpp b/kernel/kernel/FS/RamFS/Inode.cpp new file mode 100644 index 000000000..843766f25 --- /dev/null +++ b/kernel/kernel/FS/RamFS/Inode.cpp @@ -0,0 +1,161 @@ +#include +#include +#include + +namespace Kernel +{ + + /* + + RAM INODE + + */ + + BAN::ErrorOr> RamInode::create(RamFileSystem& fs, mode_t mode, uid_t uid, gid_t gid) + { + ASSERT(Mode{ mode }.ifreg()); + auto* ram_inode = new RamInode(fs, mode, uid, gid); + if (ram_inode == nullptr) + return BAN::Error::from_errno(ENOMEM); + return BAN::RefPtr::adopt(ram_inode); + } + + RamInode::RamInode(RamFileSystem& fs, mode_t mode, uid_t uid, gid_t gid) + : m_fs(fs) + { + uint64_t current_unix_time = BAN::to_unix_time(RTC::get_current_time()); + timespec current_timespec; + current_timespec.tv_sec = current_unix_time; + current_timespec.tv_nsec = 0; + + m_inode_info.ino = fs.next_ino(); + m_inode_info.mode = mode; + m_inode_info.nlink = 1; + m_inode_info.uid = uid; + m_inode_info.gid = gid; + m_inode_info.size = 0; + m_inode_info.atime = current_timespec; + m_inode_info.mtime = current_timespec; + m_inode_info.ctime = current_timespec; + m_inode_info.blksize = fs.blksize(); + m_inode_info.blocks = 0; + m_inode_info.dev = 0; + m_inode_info.rdev = 0; + } + + /* + + RAM DIRECTORY INODE + + */ + + BAN::ErrorOr> RamDirectoryInode::create(RamFileSystem& fs, ino_t parent, mode_t mode, uid_t uid, gid_t gid) + { + ASSERT(Mode{ mode }.ifdir()); + auto* ram_inode = new RamDirectoryInode(fs, parent, mode, uid, gid); + if (ram_inode == nullptr) + return BAN::Error::from_errno(ENOMEM); + return BAN::RefPtr::adopt(ram_inode); + } + + RamDirectoryInode::RamDirectoryInode(RamFileSystem& fs, ino_t parent, mode_t mode, uid_t uid, gid_t gid) + : RamInode(fs, mode, uid, gid) + { + // "." links to this + m_inode_info.nlink++; + + // ".." links to this, if there is no parent + if (parent == 0) + { + m_inode_info.nlink++; + m_parent = ino(); + } + else + { + MUST(fs.get_inode(parent))->add_link(); + m_parent = parent; + } + } + + BAN::ErrorOr> RamDirectoryInode::directory_find_inode(BAN::StringView name) + { + if (name == "."sv) + { + BAN::RefPtr inode = TRY(m_fs.get_inode(ino())); + return inode; + } + + if (name == ".."sv) + { + BAN::RefPtr inode = TRY(m_fs.get_inode(m_parent)); + return inode; + } + + for (const auto& entry : m_entries) + { + if (name == entry.name) + { + BAN::RefPtr inode = TRY(m_fs.get_inode(entry.ino)); + return inode; + } + } + + sizeof(Entry); + + return BAN::Error::from_errno(ENOENT); + } + + BAN::ErrorOr RamDirectoryInode::directory_read_next_entries(off_t offset, DirectoryEntryList* list, size_t list_size) + { + // TODO: don't require memory for all entries on single call + if (offset != 0) + { + list->entry_count = 0; + return {}; + } + + size_t needed_size = sizeof(DirectoryEntryList); + needed_size += sizeof(DirectoryEntry) + 2; // "." + needed_size += sizeof(DirectoryEntry) + 3; // ".." + for (auto& entry : m_entries) + needed_size += sizeof(DirectoryEntry) + entry.name_len + 1; + if (needed_size > list_size) + return BAN::Error::from_errno(EINVAL); + + DirectoryEntry* ptr = list->array; + + // "." + { + ptr->dirent.d_ino = ino(); + ptr->rec_len = sizeof(DirectoryEntry) + 2; + strcpy(ptr->dirent.d_name, "."); + ptr = ptr->next(); + } + + // ".." + { + ptr->dirent.d_ino = m_parent; + ptr->rec_len = sizeof(DirectoryEntry) + 3; + strcpy(ptr->dirent.d_name, ".."); + ptr = ptr->next(); + } + + for (auto& entry : m_entries) + { + ptr->dirent.d_ino = entry.ino; + ptr->rec_len = sizeof(DirectoryEntry) + entry.name_len + 1; + strcpy(ptr->dirent.d_name, entry.name); + ptr = ptr->next(); + } + + list->entry_count = m_entries.size() + 2; + + return {}; + } + + BAN::ErrorOr RamDirectoryInode::create_file(BAN::StringView, mode_t) + { + ASSERT_NOT_REACHED(); + } + +} \ No newline at end of file diff --git a/kernel/kernel/FS/VirtualFileSystem.cpp b/kernel/kernel/FS/VirtualFileSystem.cpp index 210a01c51..35e5a2f9f 100644 --- a/kernel/kernel/FS/VirtualFileSystem.cpp +++ b/kernel/kernel/FS/VirtualFileSystem.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include #include @@ -23,8 +25,17 @@ namespace Kernel auto partition_inode = MUST(DeviceManager::get().directory_find_inode(root)); s_instance->m_root_fs = MUST(Ext2FS::create(*(Partition*)partition_inode.ptr())); + Credentials root_creds { 0, 0, 0, 0 }; + DeviceManager::get().set_blksize(s_instance->m_root_fs->root_inode()->blksize()); - MUST(s_instance->mount({ 0, 0, 0, 0 }, &DeviceManager::get(), "/dev")); + MUST(s_instance->mount(root_creds, &DeviceManager::get(), "/dev")); + + mode_t tmpfs_mode = Inode::Mode::IFDIR + | Inode::Mode::IRUSR | Inode::Mode::IWUSR | Inode::Mode::IXUSR + | Inode::Mode::IRGRP | Inode::Mode::IWGRP | Inode::Mode::IXGRP + | Inode::Mode::IROTH | Inode::Mode::IWOTH | Inode::Mode::IXOTH; + auto* tmpfs = MUST(RamFileSystem::create(1024 * 1024, tmpfs_mode, 0, 0)); + MUST(s_instance->mount(root_creds, tmpfs, "/tmp")); } VirtualFileSystem& VirtualFileSystem::get()