From 5f4c802880fa66650d1f48503f6148dba6dd91b7 Mon Sep 17 00:00:00 2001 From: DaJiYuQia <88259094+DaJiYuQia@users.noreply.github.com> Date: Thu, 13 Oct 2022 14:34:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9mkdir=E4=BB=A5=E5=8F=8Ado=5Fopen?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=8A=A0=E9=94=81=20(#55)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 对mkdir加锁 * 给mkdir和do_open的dentry加锁 * 对加锁进行了修改 * modified * bugfix: 修复一些死锁及空指针的错误 Co-authored-by: longjin --- kernel/filesystem/VFS/VFS.c | 120 +++++++++++++++++++++++--------- kernel/filesystem/VFS/VFS.h | 22 +++--- kernel/filesystem/VFS/dcache.c | 3 +- kernel/filesystem/fat32/fat32.c | 4 +- 4 files changed, 99 insertions(+), 50 deletions(-) diff --git a/kernel/filesystem/VFS/VFS.c b/kernel/filesystem/VFS/VFS.c index c378c70a..24e2a9e6 100644 --- a/kernel/filesystem/VFS/VFS.c +++ b/kernel/filesystem/VFS/VFS.c @@ -1,16 +1,16 @@ #include "VFS.h" -#include "mount.h" #include "internal.h" -#include -#include +#include "mount.h" #include -#include #include +#include +#include +#include +#include #include #include -#include #include -#include +#include // 为filesystem_type_t结构体实例化一个链表头 static struct vfs_filesystem_type_t vfs_fs = {"filesystem", 0}; @@ -77,12 +77,12 @@ uint64_t vfs_register_filesystem(struct vfs_filesystem_type_t *fs) for (p = &vfs_fs; p; p = p->next) { if (!strcmp(p->name, fs->name)) // 已经注册相同名称的文件系统 - return VFS_E_FS_EXISTED; + return -EEXIST; } fs->next = vfs_fs.next; vfs_fs.next = fs; - return VFS_SUCCESS; + return 0; } uint64_t vfs_unregister_filesystem(struct vfs_filesystem_type_t *fs) @@ -94,12 +94,12 @@ uint64_t vfs_unregister_filesystem(struct vfs_filesystem_type_t *fs) { p->next = p->next->next; fs->next = NULL; - return VFS_SUCCESS; + return 0; } else p = p->next; } - return VFS_E_FS_NOT_EXIST; + return -EINVAL; } /** @@ -245,6 +245,7 @@ int vfs_fill_dirent(void *buf, ino_t d_ino, char *name, int namelen, unsigned ch int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland) { uint32_t pathlen; + int retval = 0; if (from_userland) pathlen = strnlen_user(path, PAGE_4K_SIZE - 1); else @@ -296,30 +297,57 @@ int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland) kwarn("Dir '%s' aleardy exists.", path); return -EEXIST; } - + spin_lock(&parent_dir->lockref.lock); struct vfs_dir_entry_t *subdir_dentry = vfs_alloc_dentry(pathlen - last_slash); if (path[pathlen - 1] == '/') subdir_dentry->name_length = pathlen - last_slash - 2; else subdir_dentry->name_length = pathlen - last_slash - 1; - memset((void *)subdir_dentry->name, 0, subdir_dentry->name_length + 1); for (int i = last_slash + 1, cnt = 0; i < pathlen && cnt < subdir_dentry->name_length; ++i, ++cnt) { subdir_dentry->name[cnt] = path[i]; } - ++subdir_dentry->name_length; - // kdebug("last_slash=%d", last_slash); // kdebug("name=%s", path + last_slash + 1); subdir_dentry->parent = parent_dir; + // kdebug("to mkdir, parent name=%s", parent_dir->name); - int retval = parent_dir->dir_inode->inode_ops->mkdir(parent_dir->dir_inode, subdir_dentry, 0); - list_append(&parent_dir->subdirs_list, &subdir_dentry->child_node_list); - // kdebug("retval = %d", retval); - return 0; + spin_lock(&parent_dir->dir_inode->lockref.lock); + retval = parent_dir->dir_inode->inode_ops->mkdir(parent_dir->dir_inode, subdir_dentry, 0); + spin_unlock(&parent_dir->dir_inode->lockref.lock); + + if (retval != 0) + { + if (vfs_dentry_put(parent_dir) != 0) // 释放dentry + spin_unlock(&parent_dir->lockref.lock); + return retval; + } + + // 获取append前一个dentry并加锁 + struct List *target_list = &parent_dir->subdirs_list; + // kdebug("target_list=%#018lx target_list->prev=%#018lx",target_list,target_list->prev); + if (list_empty(target_list) == false) + { + struct vfs_dir_entry_t *prev_dentry = list_entry(target_list->prev, struct vfs_dir_entry_t, child_node_list); + // kdebug("prev_dentry%#018lx",prev_dentry); + spin_lock(&prev_dentry->lockref.lock); + list_append(&parent_dir->subdirs_list, &subdir_dentry->child_node_list); + // kdebug("retval = %d", retval); + spin_unlock(&prev_dentry->lockref.lock); + } + else + { + list_append(&parent_dir->subdirs_list, &subdir_dentry->child_node_list); + goto out; + } + +out:; + spin_unlock(&parent_dir->lockref.lock); + return retval; } + /** * @brief 创建文件夹 * @@ -351,13 +379,9 @@ uint64_t do_open(const char *filename, int flags) long path_len = strnlen_user(filename, PAGE_4K_SIZE) + 1; if (path_len <= 0) // 地址空间错误 - { return -EFAULT; - } else if (path_len >= PAGE_4K_SIZE) // 名称过长 - { return -ENAMETOOLONG; - } // 为待拷贝文件路径字符串分配内存空间 char *path = (char *)kzalloc(path_len, 0); @@ -394,17 +418,17 @@ uint64_t do_open(const char *filename, int flags) { path[tmp_index] = '\0'; - dentry = vfs_path_walk(path, 0); - if (dentry == NULL) + parent_dentry = vfs_path_walk(path, 0); + if (parent_dentry == NULL) { kfree(path); return -ENOENT; } - parent_dentry = dentry; } else + { parent_dentry = vfs_root_sb->root; - + } // 创建新的文件 dentry = vfs_alloc_dentry(path_len - tmp_index); @@ -412,28 +436,53 @@ uint64_t do_open(const char *filename, int flags) 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; + + // 对父目录项加锁 + spin_lock(&parent_dentry->lockref.lock); + spin_lock(&parent_dentry->dir_inode->lockref.lock); + // 创建子目录项 uint64_t retval = parent_dentry->dir_inode->inode_ops->create(parent_dentry->dir_inode, dentry, 0); + spin_unlock(&parent_dentry->dir_inode->lockref.lock); // 解锁inode + if (retval != 0) { - kfree(dentry->name); - kfree(dentry); + if (vfs_dentry_put(dentry) != 0) // 释放dentry + BUG_ON(1); + BUG_ON(1); kfree(path); + spin_unlock(&parent_dentry->lockref.lock); return retval; } - list_init(&dentry->child_node_list); - list_init(&dentry->subdirs_list); + // ==== 将子目录项添加到链表 ==== + struct vfs_dir_entry_t *next_dentry = NULL; + // 若list非空,则对前一个dentry加锁 + if (!list_empty(&parent_dentry->subdirs_list)) + { + next_dentry = list_entry(list_next(&parent_dentry->subdirs_list), struct vfs_dir_entry_t, child_node_list); + spin_lock(&next_dentry->lockref.lock); + } list_add(&parent_dentry->subdirs_list, &dentry->child_node_list); + if (next_dentry != NULL) + spin_unlock(&next_dentry->lockref.lock); + + // 新建文件结束,对父目录项解锁 + spin_unlock(&parent_dentry->lockref.lock); // kdebug("created."); } + kfree(path); if (dentry == NULL) + { return -ENOENT; - + } + spin_lock(&dentry->lockref.lock); // 要求打开文件夹而目标不是文件夹 if ((flags & O_DIRECTORY) && (dentry->dir_inode->attribute != VFS_IF_DIR)) + { + spin_unlock(&dentry->lockref.lock); return -ENOTDIR; - + } // 创建文件描述符 struct vfs_file_t *file_ptr = (struct vfs_file_t *)kzalloc(sizeof(struct vfs_file_t), 0); @@ -448,9 +497,10 @@ uint64_t do_open(const char *filename, int flags) if (file_ptr->file_ops && file_ptr->file_ops->open) errcode = file_ptr->file_ops->open(dentry->dir_inode, file_ptr); - if (errcode != VFS_SUCCESS) + if (errcode != 0) { kfree(file_ptr); + spin_unlock(&dentry->lockref.lock); return -EFAULT; } @@ -481,10 +531,12 @@ uint64_t do_open(const char *filename, int flags) if (fd_num == -1) { kfree(file_ptr); - return -EMFILE; + spin_unlock(&dentry->lockref.lock); + return -ENFILE; } // 保存文件描述符 f[fd_num] = file_ptr; + spin_unlock(&dentry->lockref.lock); return fd_num; } diff --git a/kernel/filesystem/VFS/VFS.h b/kernel/filesystem/VFS/VFS.h index f82e7cf5..7c88f944 100644 --- a/kernel/filesystem/VFS/VFS.h +++ b/kernel/filesystem/VFS/VFS.h @@ -11,9 +11,9 @@ #pragma once -#include -#include #include +#include +#include #include #include @@ -22,10 +22,6 @@ extern struct vfs_superblock_t *vfs_root_sb; #define VFS_DPT_MBR 0 // MBR分区表 #define VFS_DPT_GPT 1 // GPT分区表 -#define VFS_SUCCESS 0 -#define VFS_E_FS_EXISTED 1 // 错误:文件系统已存在 -#define VFS_E_FS_NOT_EXIST 2 // 错误:文件系统不存在 - #define VFS_MAX_PATHLEN 1024 /** @@ -33,7 +29,7 @@ extern struct vfs_superblock_t *vfs_root_sb; * */ #define VFS_IF_FILE (1UL << 0) -#define VFS_IF_DIR (1UL << 1) // 文件夹 +#define VFS_IF_DIR (1UL << 1) // 文件夹 #define VFS_IF_DEVICE (1UL << 2) #define VFS_IF_DEAD (1UL << 3) /* removed, but still open directory */ @@ -116,7 +112,8 @@ struct vfs_filesystem_type_t { char *name; int fs_flags; - struct vfs_superblock_t *(*read_superblock)(struct block_device *blk); // 解析文件系统引导扇区的函数,为文件系统创建超级块结构。 + struct vfs_superblock_t *(*read_superblock)( + struct block_device *blk); // 解析文件系统引导扇区的函数,为文件系统创建超级块结构。 struct vfs_filesystem_type_t *next; }; @@ -155,7 +152,8 @@ struct vfs_inode_operations_t */ long (*mkdir)(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry, int mode); long (*rmdir)(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry); - long (*rename)(struct vfs_index_node_t *old_inode, struct vfs_dir_entry_t *old_dEntry, struct vfs_index_node_t *new_inode, struct vfs_dir_entry_t *new_dEntry); + long (*rename)(struct vfs_index_node_t *old_inode, struct vfs_dir_entry_t *old_dEntry, + struct vfs_index_node_t *new_inode, struct vfs_dir_entry_t *new_dEntry); long (*getAttr)(struct vfs_dir_entry_t *dEntry, uint64_t *attr); long (*setAttr)(struct vfs_dir_entry_t *dEntry, uint64_t *attr); }; @@ -271,11 +269,11 @@ int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland); int64_t vfs_rmdir(const char *path, bool from_userland); /** - * @brief 释放dentry,并视情况自动释放inode + * @brief 释放dentry,并视情况自动释放inode。 在调用该函数前,需要将dentry加锁。 * * @param dentry 目标dentry - * + * * @return 错误码 * 注意,当dentry指向文件时,如果返回值为正数,则表示在释放了该dentry后,该dentry指向的inode的引用计数。 */ -int vfs_dentry_put(struct vfs_dir_entry_t * dentry); \ No newline at end of file +int vfs_dentry_put(struct vfs_dir_entry_t *dentry); \ No newline at end of file diff --git a/kernel/filesystem/VFS/dcache.c b/kernel/filesystem/VFS/dcache.c index e2f4b046..13ad3032 100644 --- a/kernel/filesystem/VFS/dcache.c +++ b/kernel/filesystem/VFS/dcache.c @@ -3,7 +3,7 @@ #include /** - * @brief 释放dentry,并视情况自动释放inode + * @brief 释放dentry,并视情况自动释放inode. 在调用该函数前,需要将dentry加锁。 * * @param dentry 目标dentry * @@ -21,7 +21,6 @@ int vfs_dentry_put(struct vfs_dir_entry_t *dentry) { BUG_ON(1); retval = -EBUSY; - spin_unlock(&dentry->lockref.lock); goto out; } diff --git a/kernel/filesystem/fat32/fat32.c b/kernel/filesystem/fat32/fat32.c index ef8495ce..207d2de0 100644 --- a/kernel/filesystem/fat32/fat32.c +++ b/kernel/filesystem/fat32/fat32.c @@ -502,13 +502,13 @@ struct vfs_dir_entry_operations_t fat32_dEntry_ops = // todo: open long fat32_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) { - return VFS_SUCCESS; + return 0; } // todo: close long fat32_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) { - return VFS_SUCCESS; + return 0; } /**