Explorar el Código

feat(vfs): make vfs a interface

greatbridf hace 2 años
padre
commit
8058928329
Se han modificado 2 ficheros con 77 adiciones y 61 borrados
  1. 28 3
      include/kernel/vfs.hpp
  2. 49 58
      src/kernel/vfs.cpp

+ 28 - 3
include/kernel/vfs.hpp

@@ -1,5 +1,7 @@
 #pragma once
 
+#include <types/hash_map.hpp>
+#include <types/list.hpp>
 #include <types/stdint.h>
 #include <types/types.h>
 
@@ -70,22 +72,44 @@ struct stat {
 };
 
 class vfs {
+private:
+    // TODO: use allocator designed for small objects
+    using inode_list = types::list<inode>;
+    using inode_index_cache_list = types::hash_map<ino_t, inode*, types::linux_hasher<ino_t>>;
+
+private:
+    inode_list _inodes;
+    inode* _root_inode;
+    ino_t _last_inode_no;
+    inode_index_cache_list _idx_inodes;
+
+private:
+    ino_t _assign_inode_id(void);
+
+protected:
+    inode* cache_inode(inode_flags flags, uint32_t perm, void* impl_data);
+    inode* get_inode(ino_t ino);
+    void register_root_node(inode* root);
+
 public:
-    vfs() = default;
+    explicit vfs(void);
     vfs(const vfs&) = delete;
     vfs& operator=(const vfs&) = delete;
     vfs(vfs&&) = delete;
     vfs& operator=(vfs&&) = delete;
 
+    inode* root(void) const;
+
     virtual size_t inode_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n);
     virtual size_t inode_write(inode* file, const char* buf, size_t offset, size_t n);
     virtual int inode_readdir(inode* dir, dirent* entry, size_t i);
-    virtual inode* inode_findinode(inode* dir, const char* filename);
     virtual int inode_mkfile(inode* dir, const char* filename);
     virtual int inode_mknode(inode* dir, const char* filename, union node_t sn);
     virtual int inode_rmfile(inode* dir, const char* filename);
     virtual int inode_mkdir(inode* dir, const char* dirname);
     virtual int inode_stat(inode* dir, stat* stat, const char* dirname);
+    // requires inode_readdir to work
+    virtual inode* inode_findinode(inode* dir, const char* filename);
 };
 
 extern struct inode* fs_root;
@@ -106,8 +130,9 @@ int vfs_mknode(inode* dir, const char* filename, node_t sn);
 int vfs_rmfile(inode* dir, const char* filename);
 int vfs_mkdir(inode* dir, const char* dirname);
 
+// requires inode_findinode to work
 // @return pointer to the inode if found, nullptr if not
-struct inode* vfs_open(const char* path);
+inode* vfs_open(const char* path);
 
 // @return GB_OK if succeed, GB_FAILED if failed and set errno
 int vfs_stat(struct stat* stat, const char* path);

+ 49 - 58
src/kernel/vfs.cpp

@@ -13,7 +13,6 @@
 
 using types::allocator_traits;
 using types::kernel_allocator;
-using types::list;
 using types::string;
 using types::vector;
 
@@ -22,6 +21,37 @@ struct tmpfs_file_entry {
     char filename[128];
 };
 
+fs::vfs::vfs(void)
+    : _root_inode(nullptr)
+    , _last_inode_no(0)
+{
+}
+fs::ino_t fs::vfs::_assign_inode_id(void)
+{
+    return ++_last_inode_no;
+}
+fs::inode* fs::vfs::cache_inode(inode_flags flags, uint32_t perm, void* impl_data)
+{
+    auto iter = _inodes.emplace_back(inode { flags, perm, impl_data, _assign_inode_id(), this });
+    _idx_inodes.insert(iter->ino, iter.ptr());
+    return iter.ptr();
+}
+fs::inode* fs::vfs::get_inode(ino_t ino)
+{
+    auto iter = _idx_inodes.find(ino);
+    if (iter != iter.npos)
+        return iter->value;
+    else
+        return nullptr;
+}
+void fs::vfs::register_root_node(inode* root)
+{
+    _root_inode = root;
+}
+fs::inode* fs::vfs::root(void) const
+{
+    return _root_inode;
+}
 size_t fs::vfs::inode_read(inode*, char*, size_t, size_t, size_t)
 {
     syscall(0x03);
@@ -37,9 +67,17 @@ int fs::vfs::inode_readdir(inode*, dirent*, size_t)
     syscall(0x03);
     return GB_FAILED;
 }
-fs::inode* fs::vfs::inode_findinode(inode*, const char*)
+fs::inode* fs::vfs::inode_findinode(inode* dir, const char* filename)
 {
-    syscall(0x03);
+    fs::dirent ent {};
+    size_t i = 0;
+    // TODO: if the inode is a mount point, the ino MIGHT BE THE SAME
+    while (inode_readdir(dir, &ent, i) == GB_OK) {
+        if (strcmp(ent.name, filename) == 0) {
+            return get_inode(ent.ino);
+        }
+        ++i;
+    }
     return nullptr;
 }
 int fs::vfs::inode_mkfile(inode*, const char*)
@@ -69,15 +107,6 @@ int fs::vfs::inode_stat(inode*, stat*, const char*)
 }
 
 class tmpfs : public virtual fs::vfs {
-private:
-    using inode_list_type = list<fs::inode, kernel_allocator>;
-
-private:
-    size_t m_limit;
-    // TODO: hashtable etc.
-    inode_list_type m_inodes;
-    fs::ino_t m_last_inode_no;
-
 protected:
     inline vector<tmpfs_file_entry>* mk_fe_vector(void)
     {
@@ -89,17 +118,6 @@ protected:
         return allocator_traits<kernel_allocator<vector<char>>>::allocate_and_construct();
     }
 
-    inline fs::inode mk_inode(fs::inode_flags flags, void* data)
-    {
-        fs::inode i {};
-        i.flags.v = flags.v;
-        i.impl = data;
-        i.ino = m_last_inode_no++;
-        i.perm = 0777;
-        i.fs = this;
-        return i;
-    }
-
     void mklink(fs::inode* dir, fs::inode* inode, const char* filename)
     {
         auto* fes = static_cast<vector<struct tmpfs_file_entry>*>(dir->impl);
@@ -112,38 +130,33 @@ protected:
     }
 
 public:
-    explicit tmpfs(size_t limit)
-        : m_limit(limit)
-        , m_last_inode_no(0)
+    explicit tmpfs(void)
     {
-        auto in = mk_inode({ .v = INODE_DIR | INODE_MNT }, mk_fe_vector());
+        auto& in = *cache_inode({ INODE_DIR | INODE_MNT }, 0777, mk_fe_vector());
 
         mklink(&in, &in, ".");
         mklink(&in, &in, "..");
 
-        m_inodes.push_back(in);
+        register_root_node(&in);
     }
 
     virtual int inode_mkfile(fs::inode* dir, const char* filename) override
     {
-        auto file = mk_inode({ .v = INODE_FILE }, mk_data_vector());
-        m_inodes.push_back(file);
+        auto& file = *cache_inode({ .v = INODE_FILE }, 0777, mk_data_vector());
         mklink(dir, &file, filename);
         return GB_OK;
     }
 
     virtual int inode_mknode(fs::inode* dir, const char* filename, fs::node_t sn) override
     {
-        auto node = mk_inode({ .v = INODE_NODE }, (void*)sn.v);
-        m_inodes.push_back(node);
+        auto& node = *cache_inode({ .v = INODE_NODE }, 0777, (void*)sn.v);
         mklink(dir, &node, filename);
         return GB_OK;
     }
 
     virtual int inode_mkdir(fs::inode* dir, const char* dirname) override
     {
-        auto new_dir = mk_inode({ .v = INODE_DIR }, mk_fe_vector());
-        m_inodes.push_back(new_dir);
+        auto& new_dir = *cache_inode({ .v = INODE_DIR }, 0777, mk_fe_vector());
         mklink(&new_dir, &new_dir, ".");
 
         mklink(dir, &new_dir, dirname);
@@ -206,23 +219,6 @@ public:
         return GB_OK;
     }
 
-    virtual fs::inode* inode_findinode(fs::inode* dir, const char* filename) override
-    {
-        fs::dirent ent {};
-        size_t i = 0;
-        while (inode_readdir(dir, &ent, i) == GB_OK) {
-            if (strcmp(ent.name, filename) == 0) {
-                // TODO: if the inode is a mount point, the ino MIGHT BE THE SAME
-                // optimize: use hash table to build an index
-                for (auto iter = m_inodes.begin(); iter != m_inodes.end(); ++iter)
-                    if (iter->ino == ent.ino)
-                        return iter.ptr();
-            }
-            ++i;
-        }
-        return nullptr;
-    }
-
     virtual int inode_stat(fs::inode* dir, fs::stat* stat, const char* filename) override
     {
         // for later use
@@ -254,11 +250,6 @@ public:
 
         return GB_OK;
     }
-
-    fs::inode* root_inode(void)
-    {
-        return m_inodes.begin().ptr();
-    }
 };
 
 // 8 * 8 for now
@@ -425,8 +416,8 @@ void init_vfs(void)
     // null
     fs::register_special_block(0, 0, b_null_read, b_null_write, 0, 0);
 
-    rootfs = allocator_traits<kernel_allocator<tmpfs>>::allocate_and_construct(4096 * 1024);
-    fs::fs_root = rootfs->root_inode();
+    rootfs = allocator_traits<kernel_allocator<tmpfs>>::allocate_and_construct();
+    fs::fs_root = rootfs->root();
 
     fs::vfs_mkdir(fs::fs_root, "dev");
     fs::vfs_mkdir(fs::fs_root, "root");