Browse Source

对mkdir以及do_open进行加锁 (#55)

* 对mkdir加锁

* 给mkdir和do_open的dentry加锁

* 对加锁进行了修改

* modified

* bugfix: 修复一些死锁及空指针的错误

Co-authored-by: longjin <longjin@RinGoTek.cn>
DaJiYuQia 2 years ago
parent
commit
5f4c802880

+ 86 - 34
kernel/filesystem/VFS/VFS.c

@@ -1,16 +1,16 @@
 #include "VFS.h"
-#include "mount.h"
 #include "internal.h"
-#include <common/kprint.h>
-#include <debug/bug.h>
+#include "mount.h"
 #include <common/dirent.h>
-#include <common/string.h>
 #include <common/errno.h>
+#include <common/kprint.h>
+#include <common/string.h>
+#include <debug/bug.h>
+#include <filesystem/rootfs/rootfs.h>
 #include <mm/mm.h>
 #include <mm/slab.h>
-#include <process/ptrace.h>
 #include <process/process.h>
-#include <filesystem/rootfs/rootfs.h>
+#include <process/ptrace.h>
 
 // 为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;
 }
 

+ 10 - 12
kernel/filesystem/VFS/VFS.h

@@ -11,9 +11,9 @@
 
 #pragma once
 
-#include <common/glib.h>
-#include <common/fcntl.h>
 #include <common/blk_types.h>
+#include <common/fcntl.h>
+#include <common/glib.h>
 #include <common/lockref.h>
 #include <mm/slab.h>
 
@@ -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);
+int vfs_dentry_put(struct vfs_dir_entry_t *dentry);

+ 1 - 2
kernel/filesystem/VFS/dcache.c

@@ -3,7 +3,7 @@
 #include <debug/bug.h>
 
 /**
- * @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;
     }
 

+ 2 - 2
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;
 }
 
 /**