瀏覽代碼

refactor: write tmpfs with c++

greatbridf 2 年之前
父節點
當前提交
60d64c224c
共有 4 個文件被更改,包括 296 次插入305 次删除
  1. 1 1
      CMakeLists.txt
  2. 8 3
      include/kernel/vfs.h
  3. 0 301
      src/kernel/vfs.c
  4. 287 0
      src/kernel/vfs.cpp

+ 1 - 1
CMakeLists.txt

@@ -46,7 +46,7 @@ set(KERNEL_MAIN_SOURCES src/kernel_main.c
                         src/kernel/tty.c
                         src/kernel/stdio.c
                         src/kernel/mem.c
-                        src/kernel/vfs.c
+                        src/kernel/vfs.cpp
                         src/kernel/vga.c
                         src/kernel/hw/keyboard.cpp
                         src/kernel/hw/serial.c

+ 8 - 3
include/kernel/vfs.h

@@ -35,12 +35,17 @@ struct inode_ops {
     inode_mkdir mkdir;
 };
 
+struct fs_info {
+    const struct inode_ops* ops;
+    void* impl;
+};
+
 struct inode {
     struct inode_flags flags;
     uint32_t perm;
-    uint32_t impl;
+    void* impl;
     uint32_t ino;
-    const struct inode_ops* ops;
+    struct fs_info* fs;
 };
 
 struct dirent {
@@ -48,7 +53,7 @@ struct dirent {
     uint32_t ino;
 };
 
-extern struct inode fs_root;
+extern struct inode* fs_root;
 
 void init_vfs(void);
 

+ 0 - 301
src/kernel/vfs.c

@@ -1,301 +0,0 @@
-#include <kernel/mem.h>
-#include <kernel/stdio.h>
-#include <kernel/tty.h>
-#include <kernel/vfs.h>
-
-struct tmpfs_file_entry {
-    size_t ino;
-    char filename[128];
-};
-
-struct tmpfs_inode {
-    uint32_t occupied : 1;
-    uint32_t file : 1;
-    uint32_t directory : 1;
-    uint32_t mount_point : 1;
-    size_t data_size;
-    size_t data_capacity;
-    char* data;
-};
-
-struct tmpfs_data {
-    size_t limit;
-    size_t inode_count;
-    size_t inode_capacity;
-    struct tmpfs_inode* inodes;
-};
-
-static inline size_t* dir_item_count(struct tmpfs_inode* dir)
-{
-    return (size_t*)dir->data;
-}
-
-static inline struct tmpfs_file_entry* dir_item_p(struct tmpfs_inode* dir)
-{
-    return (struct tmpfs_file_entry*)(dir->data + sizeof(size_t));
-}
-
-static inline struct tmpfs_inode* from_inode(struct tmpfs_data* data, struct inode* inode)
-{
-    return &data->inodes[inode->ino];
-}
-
-static inline void double_data_size(char** p, size_t* current_capacity)
-{
-    char* tmp = (char*)k_malloc(*current_capacity * 2);
-    memcpy(tmp, *p, *current_capacity);
-    k_free(*p);
-    *p = tmp;
-    *current_capacity *= 2;
-}
-
-static inline void double_inode_list_size(struct tmpfs_inode** p, size_t* current_capacity)
-{
-    struct tmpfs_inode* tmp = (struct tmpfs_inode*)k_malloc(*current_capacity * 2 * sizeof(struct tmpfs_inode));
-    memset(tmp, 0x00, *current_capacity * 2 * sizeof(struct tmpfs_inode));
-    memcpy(tmp, *p, *current_capacity * sizeof(struct tmpfs_inode));
-    k_free(*p);
-    *p = tmp;
-    *current_capacity *= 2;
-}
-
-static inline size_t _tmpfs_read(struct tmpfs_inode* inode, char* buf, size_t buf_size, size_t offset, size_t n)
-{
-    size_t fsize = inode->data_size;
-
-    if (offset + n > fsize)
-        n = fsize - offset;
-
-    if (buf_size < n) {
-        n = buf_size;
-    }
-
-    memcpy(buf, inode->data, n);
-
-    return n;
-}
-
-size_t tmpfs_read(struct inode* file, char* buf, size_t buf_size, size_t offset, size_t n)
-{
-    if (file->flags.file != 1)
-        return 0;
-
-    struct tmpfs_data* data = (struct tmpfs_data*)file->impl;
-    struct tmpfs_inode* inode = &data->inodes[file->ino];
-
-    return _tmpfs_read(inode, buf, buf_size, offset, n);
-}
-
-static inline size_t _tmpfs_write(struct tmpfs_inode* inode, const char* buf, size_t offset, size_t n)
-{
-    size_t fsize = inode->data_size;
-
-    while (offset + n > inode->data_capacity)
-        double_data_size(&inode->data, &inode->data_capacity);
-
-    memcpy(inode->data + offset, buf, n);
-
-    if (offset + n > fsize)
-        inode->data_size = offset + n;
-
-    return n;
-}
-
-size_t tmpfs_write(struct inode* file, const char* buf, size_t offset, size_t n)
-{
-    if (file->flags.file != 1)
-        return 0;
-
-    struct tmpfs_data* data = (struct tmpfs_data*)file->impl;
-    struct tmpfs_inode* inode = &data->inodes[file->ino];
-
-    return _tmpfs_write(inode, buf, offset, n);
-}
-
-// a directory is a special file containing the tmpfs_inode
-// ids and filenames of the files and directories. the first
-// 4 bytes of its data[] is the file count it contains
-int tmpfs_readdir(struct inode* dir, struct dirent* entry, size_t i)
-{
-    if (dir->flags.directory != 1)
-        return GB_FAILED;
-
-    struct tmpfs_data* data = (struct tmpfs_data*)dir->impl;
-    struct tmpfs_inode* inode = &data->inodes[dir->ino];
-
-    size_t n = *dir_item_count(inode);
-    struct tmpfs_file_entry* files = dir_item_p(inode);
-
-    if (i >= n)
-        return GB_FAILED;
-
-    entry->ino = files[i].ino;
-    snprintf(entry->name, sizeof(entry->name), files[i].filename);
-
-    return GB_OK;
-}
-
-static inline size_t _tmpfs_allocinode(struct tmpfs_data* data)
-{
-    // TODO: reclaim released inodes
-    if (data->inode_count == data->inode_capacity) {
-        double_inode_list_size(&data->inodes, &data->inode_capacity);
-    }
-    struct tmpfs_inode* inode = data->inodes + data->inode_count;
-
-    inode->data = (char*)k_malloc(128);
-    inode->data_capacity = 128;
-    inode->data_size = 0;
-    inode->occupied = 1;
-
-    return data->inode_count++;
-}
-
-static inline int _tmpfs_mklink(struct tmpfs_inode* dir, size_t ino, const char* filename)
-{
-    struct tmpfs_file_entry ent = {
-        .filename = { 0 },
-        .ino = ino,
-    };
-    snprintf(ent.filename, sizeof(ent.filename), filename);
-
-    int result = GB_OK;
-
-    if (_tmpfs_write(dir, (const char*)&ent,
-            sizeof(size_t) + sizeof(struct tmpfs_file_entry) * *dir_item_count(dir),
-            sizeof(struct tmpfs_file_entry))
-        != sizeof(struct tmpfs_file_entry)) {
-        result = GB_FAILED;
-    }
-    *dir_item_count(dir) += 1;
-    return result;
-}
-
-int tmpfs_mkfile(struct inode* dir, const char* filename)
-{
-    struct tmpfs_data* data = (struct tmpfs_data*)dir->impl;
-    size_t ino = _tmpfs_allocinode(data);
-    struct tmpfs_inode* inode = &data->inodes[ino];
-    inode->file = 1;
-
-    _tmpfs_mklink(from_inode(data, dir), ino, filename);
-
-    return GB_OK;
-}
-
-int tmpfs_mkdir(struct inode* dir, const char* dirname)
-{
-    struct tmpfs_data* data = (struct tmpfs_data*)dir->impl;
-
-    size_t ino = _tmpfs_allocinode(data);
-    struct tmpfs_inode* inode = &data->inodes[ino];
-    inode->directory = 1;
-    *dir_item_count(inode) = 0;
-
-    _tmpfs_mklink(from_inode(data, dir), ino, dirname);
-    _tmpfs_mklink(inode, ino, ".");
-    _tmpfs_mklink(inode, dir->ino, "..");
-
-    return GB_OK;
-}
-
-int mkfs_tmpfs(struct tmpfs_data* data, size_t limit)
-{
-    data->limit = limit;
-    data->inodes = (struct tmpfs_inode*)k_malloc(sizeof(struct tmpfs_inode) * 1);
-    memset(data->inodes, 0x00, sizeof(struct tmpfs_inode));
-    data->inode_capacity = 1;
-    data->inode_count = 0;
-
-    size_t root_ino = _tmpfs_allocinode(data);
-    struct tmpfs_inode* root_inode = &data->inodes[root_ino];
-
-    _tmpfs_mklink(root_inode, root_ino, ".");
-    _tmpfs_mklink(root_inode, root_ino, "..");
-
-    return GB_OK;
-}
-
-// typedef int (*inode_finddir)(struct inode* dir, struct dirent* entry, const char* filename);
-// typedef int (*inode_rmfile)(struct inode* dir, const char* filename);
-
-size_t vfs_read(struct inode* file, char* buf, size_t buf_size, size_t offset, size_t n)
-{
-    if (file->ops->read) {
-        return file->ops->read(file, buf, buf_size, offset, n);
-    } else {
-        return 0;
-    }
-}
-size_t vfs_write(struct inode* file, const char* buf, size_t offset, size_t n)
-{
-    if (file->ops->write) {
-        return file->ops->write(file, buf, offset, n);
-    } else {
-        return 0;
-    }
-}
-int vfs_readdir(struct inode* dir, struct dirent* entry, size_t i)
-{
-    if (dir->ops->readdir) {
-        return dir->ops->readdir(dir, entry, i);
-    } else {
-        return 0;
-    }
-}
-int vfs_finddir(struct inode* dir, struct dirent* entry, const char* filename)
-{
-    if (dir->ops->finddir) {
-        return dir->ops->finddir(dir, entry, filename);
-    } else {
-        return 0;
-    }
-}
-int vfs_mkfile(struct inode* dir, const char* filename)
-{
-    if (dir->ops->mkfile) {
-        return dir->ops->mkfile(dir, filename);
-    } else {
-        return 0;
-    }
-}
-int vfs_rmfile(struct inode* dir, const char* filename)
-{
-    if (dir->ops->rmfile) {
-        return dir->ops->rmfile(dir, filename);
-    } else {
-        return 0;
-    }
-}
-int vfs_mkdir(struct inode* dir, const char* dirname)
-{
-    if (dir->ops->mkdir) {
-        return dir->ops->mkdir(dir, dirname);
-    } else {
-        return 0;
-    }
-}
-
-static const struct inode_ops tmpfs_inode_ops = {
-    .read = tmpfs_read,
-    .write = tmpfs_write,
-    .readdir = tmpfs_readdir,
-    .finddir = 0,
-    .mkfile = tmpfs_mkfile,
-    .rmfile = 0,
-    .mkdir = tmpfs_mkdir,
-};
-static struct tmpfs_data rootfs_data;
-struct inode fs_root;
-
-void init_vfs(void)
-{
-    mkfs_tmpfs(&rootfs_data, 4096 * 1024);
-
-    fs_root.flags.directory = 1;
-    fs_root.flags.mount_point = 1;
-    fs_root.ino = 0;
-    fs_root.impl = (uint32_t)&rootfs_data;
-    fs_root.ops = &tmpfs_inode_ops;
-    fs_root.perm = 0777;
-}

+ 287 - 0
src/kernel/vfs.cpp

@@ -0,0 +1,287 @@
+#include <kernel/mem.h>
+#include <kernel/stdio.h>
+#include <kernel/tty.h>
+#include <kernel/vfs.h>
+#include <types/allocator.hpp>
+#include <types/list.hpp>
+#include <types/vector.hpp>
+
+using types::allocator_traits;
+using types::kernel_allocator;
+using types::list;
+using types::vector;
+
+struct tmpfs_file_entry {
+    size_t ino;
+    char filename[128];
+};
+
+class tmpfs {
+private:
+    using inode_list_type = list<struct inode, kernel_allocator>;
+
+private:
+    size_t m_limit;
+    // TODO: hashtable etc.
+    inode_list_type m_inodes;
+    struct fs_info m_fs;
+    size_t m_last_inode_no;
+
+protected:
+    inline vector<struct tmpfs_file_entry>* mk_fe_vector(void)
+    {
+        return allocator_traits<kernel_allocator<vector<struct tmpfs_file_entry>>>::allocate_and_construct();
+    }
+
+    inline vector<char>* mk_data_vector(void)
+    {
+        return allocator_traits<kernel_allocator<vector<char>>>::allocate_and_construct();
+    }
+
+    inline struct inode mk_inode(unsigned int dir, unsigned int file, unsigned int mnt, void* data)
+    {
+        struct inode i { };
+        i.flags.directory = dir;
+        i.flags.file = file;
+        i.flags.mount_point = mnt;
+        i.fs = &m_fs;
+        i.impl = data;
+        i.ino = m_last_inode_no++;
+        i.perm = 0777;
+        return i;
+    }
+
+public:
+    explicit tmpfs(size_t limit);
+    void mklink(struct inode* dir, struct inode* inode, const char* filename);
+    void mkfile(struct inode* dir, const char* filename);
+    void mkdir(struct inode* dir, const char* dirname);
+    size_t read(struct inode* file, char* buf, size_t buf_size, size_t offset, size_t n);
+    size_t write(struct inode* file, const char* buf, size_t offset, size_t n);
+    int readdir(struct inode* dir, struct dirent* entry, size_t i);
+
+    struct inode* root_inode(void)
+    {
+        return &*m_inodes.begin();
+    }
+};
+
+size_t tmpfs_read(struct inode* file, char* buf, size_t buf_size, size_t offset, size_t n)
+{
+    auto* fs = static_cast<tmpfs*>(file->fs->impl);
+    return fs->read(file, buf, buf_size, offset, n);
+}
+size_t tmpfs_write(struct inode* file, const char* buf, size_t offset, size_t n)
+{
+    auto* fs = static_cast<tmpfs*>(file->fs->impl);
+    return fs->write(file, buf, offset, n);
+}
+int tmpfs_readdir(struct inode* dir, struct dirent* entry, size_t i)
+{
+    auto* fs = static_cast<tmpfs*>(dir->fs->impl);
+    return fs->readdir(dir, entry, i);
+}
+// int tmpfs_finddir(struct inode* dir, struct dirent* entry, const char* filename)
+// {
+//     auto* fs = static_cast<tmpfs*>(dir->fs->impl);
+//     return fs->finddir(dir, entry, filename);
+// }
+int tmpfs_mkfile(struct inode* dir, const char* filename)
+{
+    auto* fs = static_cast<tmpfs*>(dir->fs->impl);
+    fs->mkfile(dir, filename);
+    return GB_OK;
+}
+// int tmpfs_rmfile(struct inode* dir, const char* filename)
+// {
+//     auto* fs = static_cast<tmpfs*>(dir->fs->impl);
+//     fs->rmfile(dir, filename);
+//     return GB_OK;
+// }
+int tmpfs_mkdir(struct inode* dir, const char* dirname)
+{
+    auto* fs = static_cast<tmpfs*>(dir->fs->impl);
+    fs->mkfile(dir, dirname);
+    return GB_OK;
+}
+
+static const struct inode_ops tmpfs_inode_ops = {
+    .read = tmpfs_read,
+    .write = tmpfs_write,
+    .readdir = tmpfs_readdir,
+    .finddir = 0,
+    .mkfile = tmpfs_mkfile,
+    .rmfile = 0,
+    .mkdir = tmpfs_mkdir,
+};
+
+tmpfs::tmpfs(size_t limit)
+    : m_limit(limit)
+    , m_fs { .ops = &tmpfs_inode_ops, .impl = this }
+    , m_last_inode_no(0)
+{
+    struct inode in = mk_inode(1, 0, 1, mk_fe_vector());
+
+    mklink(&in, &in, ".");
+    mklink(&in, &in, "..");
+
+    m_inodes.push_back(in);
+}
+
+void tmpfs::mklink(struct inode* dir, struct inode* inode, const char* filename)
+{
+    auto* fes = static_cast<vector<struct tmpfs_file_entry>*>(dir->impl);
+    struct tmpfs_file_entry ent = {
+        .ino = inode->ino,
+        .filename = { 0 },
+    };
+    snprintf(ent.filename, sizeof(ent.filename), filename);
+    fes->push_back(ent);
+}
+
+void tmpfs::mkfile(struct inode* dir, const char* filename)
+{
+    struct inode file = mk_inode(0, 1, 0, mk_data_vector());
+    m_inodes.push_back(file);
+    mklink(dir, &file, filename);
+}
+
+void tmpfs::mkdir(struct inode* dir, const char* dirname)
+{
+    struct inode new_dir = mk_inode(1, 0, 0, mk_fe_vector());
+    m_inodes.push_back(new_dir);
+    mklink(&new_dir, &new_dir, ".");
+
+    mklink(dir, &new_dir, dirname);
+    mklink(&new_dir, dir, "..");
+}
+
+size_t tmpfs::read(struct inode* file, char* buf, size_t buf_size, size_t offset, size_t n)
+{
+    if (file->flags.file != 1)
+        return 0;
+
+    auto* data = static_cast<vector<char>*>(file->impl);
+    size_t fsize = data->size();
+
+    if (offset + n > fsize)
+        n = fsize - offset;
+
+    if (buf_size < n) {
+        n = buf_size;
+    }
+
+    memcpy(buf, data->data() + offset, n);
+
+    return n;
+}
+
+size_t tmpfs::write(struct inode* file, const char* buf, size_t offset, size_t n)
+{
+    if (file->flags.file != 1)
+        return 0;
+
+    auto* data = static_cast<vector<char>*>(file->impl);
+
+    data->at(offset + n - 1) = 0x00;
+    memcpy(data->data() + offset, buf, n);
+
+    return n;
+}
+
+int tmpfs::readdir(struct inode* dir, struct dirent* entry, size_t i)
+{
+    if (dir->flags.directory != 1)
+        return GB_FAILED;
+
+    auto* fes = static_cast<vector<struct tmpfs_file_entry>*>(dir->impl);
+
+    if (i >= fes->size())
+        return GB_FAILED;
+
+    entry->ino = fes->at(i).ino;
+    snprintf(entry->name, sizeof(entry->name), fes->at(i).filename);
+
+    return GB_OK;
+}
+
+// typedef int (*inode_finddir)(struct inode* dir, struct dirent* entry, const char* filename);
+// typedef int (*inode_rmfile)(struct inode* dir, const char* filename);
+
+size_t vfs_read(struct inode* file, char* buf, size_t buf_size, size_t offset, size_t n)
+{
+    if (file->fs->ops->read) {
+        return file->fs->ops->read(file, buf, buf_size, offset, n);
+    } else {
+        return 0;
+    }
+}
+size_t vfs_write(struct inode* file, const char* buf, size_t offset, size_t n)
+{
+    if (file->fs->ops->write) {
+        return file->fs->ops->write(file, buf, offset, n);
+    } else {
+        return 0;
+    }
+}
+int vfs_readdir(struct inode* dir, struct dirent* entry, size_t i)
+{
+    if (dir->fs->ops->readdir) {
+        return dir->fs->ops->readdir(dir, entry, i);
+    } else {
+        return 0;
+    }
+}
+int vfs_finddir(struct inode* dir, struct dirent* entry, const char* filename)
+{
+    if (dir->fs->ops->finddir) {
+        return dir->fs->ops->finddir(dir, entry, filename);
+    } else {
+        return 0;
+    }
+}
+int vfs_mkfile(struct inode* dir, const char* filename)
+{
+    if (dir->fs->ops->mkfile) {
+        return dir->fs->ops->mkfile(dir, filename);
+    } else {
+        return 0;
+    }
+}
+int vfs_rmfile(struct inode* dir, const char* filename)
+{
+    if (dir->fs->ops->rmfile) {
+        return dir->fs->ops->rmfile(dir, filename);
+    } else {
+        return 0;
+    }
+}
+int vfs_mkdir(struct inode* dir, const char* dirname)
+{
+    if (dir->fs->ops->mkdir) {
+        return dir->fs->ops->mkdir(dir, dirname);
+    } else {
+        return 0;
+    }
+}
+struct inode* fs_root;
+static tmpfs* rootfs;
+
+void init_vfs(void)
+{
+    rootfs = allocator_traits<kernel_allocator<tmpfs>>::allocate_and_construct(4096 * 1024);
+    fs_root = rootfs->root_inode();
+
+    vfs_mkdir(fs_root, "dev");
+    vfs_mkdir(fs_root, "root");
+    vfs_mkfile(fs_root, "init");
+
+    struct dirent ent { };
+    int i = 0;
+    char buf[256];
+    while (vfs_readdir(fs_root, &ent, i) == GB_OK) {
+        snprintf(buf, 256, "%s: inode(%d)\n", ent.name, ent.ino);
+        tty_print(console, buf);
+        ++i;
+    }
+}