diff --git a/.vscode/settings.json b/.vscode/settings.json index 9e952d3a..30a402e9 100644 --- a/.vscode/settings.json +++ b/.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": "" diff --git a/kernel/filesystem/Makefile b/kernel/filesystem/Makefile index 951b39c3..06a538f8 100644 --- a/kernel/filesystem/Makefile +++ b/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 "$@" diff --git a/kernel/filesystem/VFS/VFS.c b/kernel/filesystem/VFS/VFS.c index 78d36a03..40ada56f 100644 --- a/kernel/filesystem/VFS/VFS.c +++ b/kernel/filesystem/VFS/VFS.c @@ -10,9 +10,7 @@ #include #include #include - -// todo: devfs完善后,删除这个 -extern struct vfs_file_operations_t ps2_keyboard_fops; +#include // 为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; } \ No newline at end of file diff --git a/kernel/filesystem/VFS/VFS.h b/kernel/filesystem/VFS/VFS.h index a31c0dbb..8c427434 100644 --- a/kernel/filesystem/VFS/VFS.h +++ b/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); \ No newline at end of file +int64_t vfs_rmdir(const char *path, bool from_userland); diff --git a/kernel/filesystem/VFS/mount.c b/kernel/filesystem/VFS/mount.c index 3bf54ced..4b3f00b1 100644 --- a/kernel/filesystem/VFS/mount.c +++ b/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); } \ No newline at end of file diff --git a/kernel/filesystem/VFS/mount.h b/kernel/filesystem/VFS/mount.h index 5c0fa19a..9b1212e9 100644 --- a/kernel/filesystem/VFS/mount.h +++ b/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()函数 -} \ No newline at end of file +} + +/** + * @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); \ No newline at end of file diff --git a/kernel/filesystem/devfs/devfs.c b/kernel/filesystem/devfs/devfs.c index 0add5bd1..748761f6 100644 --- a/kernel/filesystem/devfs/devfs.c +++ b/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); + } \ No newline at end of file diff --git a/kernel/filesystem/devfs/devfs.h b/kernel/filesystem/devfs/devfs.h index b5be25c2..9d66ead1 100644 --- a/kernel/filesystem/devfs/devfs.h +++ b/kernel/filesystem/devfs/devfs.h @@ -6,4 +6,14 @@ * @brief 初始化devfs * */ -void devfs_init(); \ No newline at end of file +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); \ No newline at end of file diff --git a/kernel/filesystem/rootfs/rootfs.c b/kernel/filesystem/rootfs/rootfs.c index 977dc680..54a40f73 100644 --- a/kernel/filesystem/rootfs/rootfs.c +++ b/kernel/filesystem/rootfs/rootfs.c @@ -1,6 +1,224 @@ #include "rootfs.h" #include +#include +#include + +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); } \ No newline at end of file diff --git a/kernel/filesystem/rootfs/rootfs.h b/kernel/filesystem/rootfs/rootfs.h index 6750c595..f9cadee3 100644 --- a/kernel/filesystem/rootfs/rootfs.h +++ b/kernel/filesystem/rootfs/rootfs.h @@ -1,3 +1,9 @@ #pragma once -void rootfs_init(); \ No newline at end of file +void rootfs_init(); + +/** + * @brief 当磁盘文件系统被成功挂载后,释放rootfs所占的空间 + * + */ +void rootfs_umount(); \ No newline at end of file diff --git a/kernel/main.c b/kernel/main.c index 428d9ec0..80cab1aa 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -20,6 +20,8 @@ #include #include +#include +#include #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(); diff --git a/kernel/process/process.c b/kernel/process/process.c index 4c575619..dfd7225c 100644 --- a/kernel/process/process.c +++ b/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);