瀏覽代碼

new: rootfs

fslongjin 2 年之前
父節點
當前提交
72f9c430c5

+ 2 - 1
.vscode/settings.json

@@ -137,7 +137,8 @@
         "internal.h": "c",
         "devfs.h": "c",
         "devfs-types.h": "c",
-        "chardev.h": "c"
+        "chardev.h": "c",
+        "rootfs.h": "c"
     },
     "C_Cpp.errorSquiggles": "Enabled",
     "esbonio.sphinx.confDir": ""

+ 1 - 1
kernel/filesystem/Makefile

@@ -3,7 +3,7 @@ CFLAGS += -I .
 
 
 kernel_fs_objs:= $(shell find ./*.c)
-kernel_fs_subdirs:= devfs VFS fat32
+kernel_fs_subdirs:= devfs VFS fat32 rootfs
 
 ECHO:
 	@echo "$@"

+ 14 - 24
kernel/filesystem/VFS/VFS.c

@@ -10,9 +10,7 @@
 #include <mm/slab.h>
 #include <process/ptrace.h>
 #include <process/process.h>
-
-// todo: devfs完善后,删除这个
-extern struct vfs_file_operations_t ps2_keyboard_fops;
+#include <filesystem/rootfs/rootfs.h>
 
 // 为filesystem_type_t结构体实例化一个链表头
 static struct vfs_filesystem_type_t vfs_fs = {"filesystem", 0};
@@ -30,16 +28,13 @@ struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size);
  */
 struct vfs_superblock_t *vfs_mount_fs(const char *path, char *name, struct block_device *blk)
 {
-    // todo: 选择挂载点
+
     // 判断挂载点是否存在
     struct vfs_dir_entry_t *target_dentry = NULL;
-    // 由于目前还没有rootfs,因此挂载根目录时,不需要path walk
-    if (strcmp(path, "/") != 0)
-    {
-        target_dentry = vfs_path_walk(path, 0);
-        if (target_dentry == NULL)
-            return NULL;
-    }
+
+    target_dentry = vfs_path_walk(path, 0);
+    if (target_dentry == NULL)
+        return NULL;
 
     struct vfs_filesystem_type_t *p = NULL;
     for (p = &vfs_fs; p; p = p->next)
@@ -166,7 +161,7 @@ struct vfs_dir_entry_t *vfs_path_walk(const char *path, uint64_t flags)
             tmpname[tmp_path_len] = '\0';
 
             dentry = vfs_search_dentry_list(parent, tmpname);
-            
+
             kfree(tmpname);
         }
 
@@ -282,7 +277,7 @@ int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland)
     else
         strncpy(buf, path, last_slash);
     buf[last_slash + 1] = '\0';
-    // kdebug("to walk: %s", buf);
+
     // 查找父目录
     struct vfs_dir_entry_t *parent_dir = vfs_path_walk(buf, 0);
 
@@ -368,10 +363,9 @@ uint64_t do_open(const char *filename, int flags)
     }
 
     // 为待拷贝文件路径字符串分配内存空间
-    char *path = (char *)kmalloc(path_len, 0);
+    char *path = (char *)kzalloc(path_len, 0);
     if (path == NULL)
         return -ENOMEM;
-    memset(path, 0, path_len);
 
     strncpy_from_user(path, filename, path_len);
     // 去除末尾的 '/'
@@ -384,11 +378,6 @@ uint64_t do_open(const char *filename, int flags)
     // 寻找文件
     struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0);
 
-    // if (dentry != NULL)
-    //     printk_color(ORANGE, BLACK, "Found %s\nDIR_FstClus:%#018lx\tDIR_FileSize:%#018lx\n", path, ((struct fat32_inode_info_t *)(dentry->dir_inode->private_inode_info))->first_clus, dentry->dir_inode->file_size);
-    // else
-    //     printk_color(ORANGE, BLACK, "Can`t find file\n");
-    // kdebug("flags=%#018lx", flags);
     if (dentry == NULL && flags & O_CREAT)
     {
         // 先找到倒数第二级目录
@@ -420,12 +409,10 @@ uint64_t do_open(const char *filename, int flags)
             parent_dentry = vfs_root_sb->root;
 
         // 创建新的文件
-        dentry = (struct vfs_dir_entry_t *)kmalloc(sizeof(struct vfs_dir_entry_t), 0);
-        memset(dentry, 0, sizeof(struct vfs_dir_entry_t));
+        dentry = (struct vfs_dir_entry_t *)kzalloc(sizeof(struct vfs_dir_entry_t), 0);
 
         dentry->name_length = path_len - tmp_index - 1;
-        dentry->name = (char *)kmalloc(dentry->name_length, 0);
-        memset(dentry->name, 0, dentry->name_length);
+        dentry->name = (char *)kzalloc(dentry->name_length + 1, 0);
         strncpy(dentry->name, path + tmp_index + 1, dentry->name_length);
         // kdebug("to create new file:%s   namelen=%d", dentry->name, dentry->name_length)
         dentry->parent = parent_dentry;
@@ -524,6 +511,8 @@ struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size)
     if (unlikely(name_size > VFS_MAX_PATHLEN))
         return NULL;
     struct vfs_dir_entry_t *dentry = (struct vfs_dir_entry_t *)kzalloc(sizeof(struct vfs_dir_entry_t), 0);
+    if (unlikely(dentry == NULL))
+        return NULL;
     dentry->name = (char *)kzalloc(name_size, 0);
     list_init(&dentry->child_node_list);
     list_init(&dentry->subdirs_list);
@@ -667,5 +656,6 @@ struct vfs_index_node_t *vfs_alloc_inode()
 int vfs_init()
 {
     mount_init();
+    rootfs_init();
     return 0;
 }

+ 2 - 2
kernel/filesystem/VFS/VFS.h

@@ -47,7 +47,7 @@ struct vfs_dir_entry_operations_t;
 struct vfs_dir_entry_t
 {
     char *name;
-    int name_length;
+    int name_length;  // 名字的长度(不包含字符串末尾的'\0')
     uint32_t d_flags; // dentry标志位
     struct List child_node_list;
     struct List subdirs_list;
@@ -266,4 +266,4 @@ int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland);
  * @param from_userland 请求是否来自用户态
  * @return int64_t 错误码
  */
-int64_t vfs_rmdir(const char *path, bool from_userland);
+int64_t vfs_rmdir(const char *path, bool from_userland);

+ 38 - 2
kernel/filesystem/VFS/mount.c

@@ -30,12 +30,12 @@ int do_mount(struct vfs_dir_entry_t *old_dentry, struct vfs_dir_entry_t *new_den
     mp->dentry = old_dentry;
     mp->parent_dentry = old_dentry->parent;
 
-    // kdebug("&new_dentry->name=%#018lx, &old_dentry->name=%#018lx", &new_dentry->name, &old_dentry->name);
     // 拷贝名称
     strncpy(new_dentry->name, old_dentry->name, old_dentry->name_length);
+    kdebug("new_dentry->name=%s, old_dentry->name=%s, old_dentry->name_length=%d", new_dentry->name, old_dentry->name, old_dentry->name_length);
 
     new_dentry->d_flags |= VFS_DF_MOUNTED; // 标记新的dentry是一个挂载点
-    
+
     list_init(&new_dentry->child_node_list);
     list_init(&new_dentry->subdirs_list);
     new_dentry->parent = old_dentry->parent;
@@ -60,4 +60,40 @@ int do_umount(struct vfs_dir_entry_t *dentry)
     // todo: 实现umount(主要是结点的恢复问题)
 
     return 0;
+}
+
+/**
+ * @brief 根据mountpoint的父目录dentry查找第一个符合条件的mountpoint结构体
+ *
+ * @param dentry 父dentry
+ * @return struct mountpoint* 第一个符合条件的mountpoint结构体的指针
+ */
+struct mountpoint *mount_find_mnt_list_by_parent(struct vfs_dir_entry_t *dentry)
+{
+    struct List *list = &mnt_list_head;
+    struct mountpoint *ret = NULL;
+    if (list_empty(list))
+        return NULL;
+
+    while (list_next(list) != &mnt_list_head)
+    {
+        list = list_next(list);
+        struct mountpoint *tmp = container_of(list, struct mountpoint, mnt_list);
+        if (dentry == tmp->parent_dentry)
+            return tmp;
+    }
+
+    return NULL;
+}
+
+/**
+ * @brief 将挂载点结构体从链表中删除并释放
+ *
+ * @param mp mountpoint结构体
+ * @return int 错误码
+ */
+int mount_release_mountpoint(struct mountpoint *mp)
+{
+    list_del(&mp->mnt_list);
+    return kfree(mp);
 }

+ 17 - 1
kernel/filesystem/VFS/mount.h

@@ -57,4 +57,20 @@ static inline void detach_mounts(struct vfs_dir_entry_t *dentry)
 
     // todo:如果当前文件夹是一个挂载点,则对同样挂载在当前文件夹下的dentry进行清理。以免造成内存泄露
     // 可参考 linux5.17或以上的detach_mounts()函数
-}
+}
+
+/**
+ * @brief 根据mountpoint的父目录dentry查找第一个符合条件的mountpoint结构体
+ * 
+ * @param dentry 父dentry
+ * @return struct mountpoint* 第一个符合条件的mountpoint结构体的指针
+ */
+struct mountpoint *mount_find_mnt_list_by_parent(struct vfs_dir_entry_t *dentry);
+
+/**
+ * @brief 释放挂载点结构体
+ * 
+ * @param mp mountpoint结构体
+ * @return int 错误码
+ */
+int mount_release_mountpoint(struct mountpoint* mp);

+ 5 - 8
kernel/filesystem/devfs/devfs.c

@@ -13,7 +13,6 @@ struct vfs_inode_operations_t devfs_inode_ops;
 struct vfs_dir_entry_t *devfs_root_dentry; // 根结点的dentry
 struct vfs_superblock_t devfs_sb = {0};
 const char __devfs_mount_path[] = "/dev";
-extern struct vfs_file_operations_t ps2_keyboard_fops;
 
 /**
  * @brief 创建devfs的super block
@@ -206,11 +205,10 @@ static __always_inline void __devfs_init_root_dentry()
 /**
  * @brief 在devfs中注册设备
  *
- * @param name
- * @param device_type
- * @param sub_type
- * @param file_ops
- * @return int
+ * @param device_type 设备主类型
+ * @param sub_type 设备子类型
+ * @param file_ops 设备的文件操作接口
+ * @return int 错误码
  */
 int devfs_register_device(uint16_t device_type, uint16_t sub_type, struct vfs_file_operations_t *file_ops)
 {
@@ -254,6 +252,5 @@ void devfs_init()
 
     __devfs_chardev_init();
 
-    // todo: 当rootfs实现后,将ps/2键盘的注册改为在驱动程序中进行(目前没有rootfs,因此还不能在不依赖fat32的情况下,挂载设备)
-    devfs_register_device(DEV_TYPE_CHAR, CHAR_DEV_STYPE_PS2_KEYBOARD, &ps2_keyboard_fops);
+    
 }

+ 11 - 1
kernel/filesystem/devfs/devfs.h

@@ -6,4 +6,14 @@
  * @brief 初始化devfs
  * 
  */
-void devfs_init();
+void devfs_init();
+
+/**
+ * @brief 在devfs中注册设备
+ *
+ * @param device_type 设备主类型
+ * @param sub_type 设备子类型
+ * @param file_ops 设备的文件操作接口
+ * @return int 错误码
+ */
+int devfs_register_device(uint16_t device_type, uint16_t sub_type, struct vfs_file_operations_t *file_ops);

+ 218 - 0
kernel/filesystem/rootfs/rootfs.c

@@ -1,6 +1,224 @@
 #include "rootfs.h"
 #include <filesystem/VFS/VFS.h>
+#include <common/string.h>
+#include <filesystem/VFS/mount.h>
+
+static struct vfs_superblock_t rootfs_sb = {0};
+extern struct vfs_superblock_t *vfs_root_sb;
+
+/**
+ * @brief 释放dentry本身所占的内存
+ *
+ * @param dentry
+ */
+static inline void __release_dentry(struct vfs_dir_entry_t *dentry)
+{
+    kfree(dentry->name);
+    kfree(dentry);
+}
+
+struct vfs_super_block_operations_t rootfs_sb_ops = {
+    .put_superblock = NULL,
+    .write_inode = NULL,
+    .write_superblock = NULL,
+};
+
+static struct vfs_dir_entry_t *rootfs_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry)
+{
+    return NULL;
+}
+struct vfs_inode_operations_t rootfs_inode_ops = {
+    .create = NULL,
+    .getAttr = NULL,
+    .lookup = NULL,
+    .lookup = &rootfs_lookup,
+    .mkdir = NULL,
+    .rename = NULL,
+    .rmdir = NULL,
+    .setAttr = NULL,
+};
+
+static long rootfs_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr)
+{
+    return 0;
+}
+static long rootfs_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) { return 0; }
+static long rootfs_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) { return 0; }
+static long rootfs_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) { return 0; }
+static long rootfs_lseek(struct vfs_file_t *file_ptr, long offset, long origin) { return 0; }
+static long rootfs_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg) { return 0; }
+
+static long rootfs_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler)
+{
+    // 循环读取目录下的目录项
+    struct vfs_dir_entry_t *dentry = file_ptr->dEntry;
+    struct List *list = &dentry->subdirs_list;
+    // 先切换到position处
+    for (int i = 0; i <= file_ptr->position; ++i)
+    {
+        list = list_next(list);
+        if (list == &dentry->subdirs_list) // 找完了
+            goto failed;
+    }
+
+    // 存在目录项
+    // 增加偏移量
+    ++file_ptr->position;
+    // 获取目标dentry(由于是子目录项,因此是child_node_list)
+    struct vfs_dir_entry_t *target_dent = container_of(list, struct vfs_dir_entry_t, child_node_list);
+    // kdebug("target name=%s, namelen=%d", target_dent->name, target_dent->name_length);
+
+    char *name = (char *)kzalloc(target_dent->name_length + 1, 0);
+    strncpy(name, target_dent->name, target_dent->name_length);
+
+    uint32_t dentry_type = target_dent->dir_inode->attribute;
+
+    return filler(dirent, file_ptr->position - 1, name, target_dent->name_length, dentry_type, file_ptr->position - 1);
+failed:;
+    return 0;
+}
+
+static long rootfs_compare(struct vfs_dir_entry_t *parent_dEntry, char *source_filename, char *dest_filename) { return 0; }
+
+static long rootfs_hash(struct vfs_dir_entry_t *dEntry, char *filename) { return 0; }
+
+static long rootfs_release(struct vfs_dir_entry_t *dEntry) { return 0; }
+
+static long rootfs_iput(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode) { return 0; }
+
+struct vfs_dir_entry_operations_t rootfs_dentry_ops =
+    {
+        .compare = &rootfs_compare,
+        .hash = &rootfs_hash,
+        .release = &rootfs_release,
+        .iput = &rootfs_iput,
+};
+
+struct vfs_file_operations_t rootfs_file_ops = {
+    .open = &rootfs_open,
+    .close = &rootfs_close,
+    .read = &rootfs_read,
+    .write = &rootfs_write,
+    .lseek = &rootfs_lseek,
+    .ioctl = &rootfs_ioctl,
+    .readdir = &rootfs_readdir,
+};
+
+/**
+ * @brief 为在rootfs下创建目录(仅仅是形式上的目录,为了支持文件系统挂载)
+ *
+ * @param name 目录名称
+ * @return int
+ */
+static int rootfs_add_dir(const char *name)
+{
+    {
+        // 检查名称重复
+        struct List *list = &rootfs_sb.root->subdirs_list;
+        while (list_next(list) != &rootfs_sb.root->subdirs_list)
+        {
+            list = list_next(list);
+            struct vfs_dir_entry_t *tmp = container_of(list, struct vfs_dir_entry_t, child_node_list);
+            if (strcmp(tmp->name, name) == 0)
+                return -EEXIST;
+        }
+    }
+
+    struct vfs_dir_entry_t *dentry = vfs_alloc_dentry(strlen(name) + 1);
+    strcpy(dentry->name, name);
+    dentry->name_length = strlen(name);
+    dentry->parent = rootfs_sb.root;
+    list_append(&rootfs_sb.root->subdirs_list, &dentry->child_node_list);
+    return 0;
+}
 
 void rootfs_init()
 {
+    // 初始化超级块
+    rootfs_sb.blk_device = NULL;
+    rootfs_sb.private_sb_info = NULL;
+    rootfs_sb.sb_ops = &rootfs_sb_ops;
+    rootfs_sb.dir_ops = &rootfs_dentry_ops;
+
+    // 初始化dentry
+    rootfs_sb.root = vfs_alloc_dentry(sizeof("/"));
+    struct vfs_dir_entry_t *dentry = rootfs_sb.root;
+    strncpy(dentry->name, "/", 2);
+    dentry->name_length = 1;
+    dentry->parent = dentry;
+
+    // 初始化root inode
+    dentry->dir_inode = vfs_alloc_inode();
+    dentry->dir_inode->sb = &rootfs_sb;
+    dentry->dir_inode->inode_ops = &rootfs_inode_ops;
+    dentry->dir_inode->file_ops = &rootfs_file_ops;
+    dentry->dir_inode->attribute = VFS_IF_DIR;
+
+    // 直接将vfs的根superblock设置为rootfs的超级块
+    vfs_root_sb = &rootfs_sb;
+
+    // 创建/dev等目录的dentry(以便文件系统的mount)
+    if (rootfs_add_dir("dev") != 0)
+        kerror("create dir 'dev' in rootfs failed");
+}
+
+/**
+ * @brief 当新的根文件系统被挂载后,将原有的挂载在rootfs下的文件系统,迁移到新的根文件系统上
+ *
+ */
+static void rootfs_migrate()
+{
+    kdebug("Migrating rootfs's dentries...");
+    struct List *list = &rootfs_sb.root->subdirs_list;
+    if (unlikely(list_empty(list)))
+        return;
+    list = list_next(list);
+    while (list != &rootfs_sb.root->subdirs_list)
+    {
+
+        struct vfs_dir_entry_t *tmp = container_of(list, struct vfs_dir_entry_t, child_node_list);
+        if (tmp->dir_inode != NULL)
+        {
+            list = list_next(list); // 获取下一个列表结点(不然的话下面的几行代码就覆盖掉了正确的值了)
+
+            tmp->parent = vfs_root_sb->root;
+            list_init(&tmp->child_node_list);
+            list_append(&vfs_root_sb->root->subdirs_list, &tmp->child_node_list);
+        }
+        else
+        {
+            list = list_next(list); // 不迁移空的dentry,直接释放他们
+            list_del(&tmp->child_node_list);
+            __release_dentry(tmp);
+        }
+    }
+}
+
+/**
+ * @brief 当磁盘文件系统被成功挂载后,释放rootfs所占的空间
+ *
+ */
+void rootfs_umount()
+{
+    // 将原有的“dev”文件夹等进行迁移
+    rootfs_migrate();
+    kinfo("Umounting rootfs...");
+
+    // 遍历mount链表,删除所有父目录是rootfs的dentry
+    struct mountpoint *mp = NULL;
+    while (1)
+    {
+        mp = mount_find_mnt_list_by_parent(rootfs_sb.root);
+        if (mp == NULL)
+            break;
+
+        // 释放dentry(由于没有创建inode,因此不需要释放)
+        __release_dentry(mp->dentry);
+        // 释放mountpoint结构体
+        mount_release_mountpoint(mp);
+    }
+
+    // 释放root dentry及其inode
+    kfree(rootfs_sb.root->dir_inode);
+    __release_dentry(rootfs_sb.root);
 }

+ 7 - 1
kernel/filesystem/rootfs/rootfs.h

@@ -1,3 +1,9 @@
 #pragma once
 
-void rootfs_init();
+void rootfs_init();
+
+/**
+ * @brief 当磁盘文件系统被成功挂载后,释放rootfs所占的空间
+ * 
+ */
+void rootfs_umount();

+ 4 - 0
kernel/main.c

@@ -20,6 +20,8 @@
 #include <sched/sched.h>
 
 #include <filesystem/fat32/fat32.h>
+#include <filesystem/VFS/VFS.h>
+#include <filesystem/devfs/devfs.h>
 
 #include "driver/multiboot2/multiboot2.h"
 #include "driver/acpi/acpi.h"
@@ -139,6 +141,8 @@ void system_initialize()
     smp_init();
     io_mfence();
 
+    vfs_init();
+    devfs_init();
     cpu_init();
     ps2_keyboard_init();
     // ps2_mouse_init();

+ 3 - 2
kernel/process/process.c

@@ -464,10 +464,11 @@ exec_failed:;
 ul initial_kernel_thread(ul arg)
 {
     // kinfo("initial proc running...\targ:%#018lx", arg);
+    
     ahci_init();
-    vfs_init();
     fat32_init();
-    devfs_init();
+    rootfs_umount();
+
     // 使用单独的内核线程来初始化usb驱动程序
     int usb_pid = kernel_thread(usb_init, 0, 0);