Sfoglia il codice sorgente

new: devfs设备卸载

fslongjin 2 anni fa
parent
commit
7e0835c92f

+ 3 - 1
.vscode/settings.json

@@ -140,7 +140,9 @@
         "chardev.h": "c",
         "rootfs.h": "c",
         "tty.h": "c",
-        "kthread.h": "c"
+        "kthread.h": "c",
+        "lockref.h": "c",
+        "compiler_attributes.h": "c"
     },
     "C_Cpp.errorSquiggles": "Enabled",
     "esbonio.sphinx.confDir": ""

+ 1 - 1
kernel/driver/usb/xhci/xhci.c

@@ -207,7 +207,7 @@ static __always_inline void __xhci_write_trb(struct xhci_ep_info_t *ep_info, str
  */
 static __always_inline uint64_t xhci_get_device_context_vaddr(const int id, const int port_id)
 {
-    return phys_2_virt(__read8b(xhci_hc[id].dcbaap_vaddr + (xhci_hc[id].ports[port_id].slot_id * sizeof(uint64_t))));
+    return (uint64_t)phys_2_virt(__read8b(xhci_hc[id].dcbaap_vaddr + (xhci_hc[id].ports[port_id].slot_id * sizeof(uint64_t))));
 }
 
 /**

+ 12 - 2
kernel/filesystem/VFS/VFS.c

@@ -514,6 +514,11 @@ struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size)
     if (unlikely(dentry == NULL))
         return NULL;
     dentry->name = (char *)kzalloc(name_size, 0);
+
+    // 初始化lockref
+    spin_init(&dentry->lockref.lock);
+    dentry->lockref.count = 1;
+    // 初始化链表
     list_init(&dentry->child_node_list);
     list_init(&dentry->subdirs_list);
     return dentry;
@@ -604,6 +609,7 @@ int64_t vfs_rmdir(const char *path, bool from_userland)
     if (retval != 0)
         return retval;
     // todo: 对dentry和inode加锁
+    spin_lock(&dentry->lockref.lock);
     retval = -EBUSY;
     if (is_local_mountpoint(dentry))
         goto out;
@@ -616,8 +622,11 @@ int64_t vfs_rmdir(const char *path, bool from_userland)
     dont_mount(dentry);                          // 将当前dentry标记为不可被挂载
     detach_mounts(dentry);                       // 清理同样挂载在该路径的所有挂载点的挂载树
 
-    vfs_dentry_put(dentry); // 释放dentry
+    if (vfs_dentry_put(dentry) != 0)
+        goto out; // 释放dentry
+    return retval;
 out:;
+    spin_unlock(&dentry->lockref.lock);
     // todo: 对dentry和inode放锁
     return retval;
 }
@@ -644,7 +653,8 @@ uint64_t sys_rmdir(struct pt_regs *regs)
 struct vfs_index_node_t *vfs_alloc_inode()
 {
     struct vfs_index_node_t *inode = kzalloc(sizeof(struct vfs_index_node_t), 0);
-    inode->ref_count = 1; // 初始化引用计数为1
+    spin_init(&inode->lockref.lock);
+    inode->lockref.count = 1; // 初始化引用计数为1
     return inode;
 }
 

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

@@ -14,6 +14,7 @@
 #include <common/glib.h>
 #include <common/fcntl.h>
 #include <common/blk_types.h>
+#include <common/lockref.h>
 #include <mm/slab.h>
 
 extern struct vfs_superblock_t *vfs_root_sb;
@@ -32,7 +33,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 */
 
@@ -52,6 +53,7 @@ struct vfs_dir_entry_t
     struct List child_node_list;
     struct List subdirs_list;
 
+    struct lockref lockref; // 该lockref包含了dentry的自旋锁以及引用计数
     struct vfs_index_node_t *dir_inode;
     struct vfs_dir_entry_t *parent;
     struct vfs_dir_entry_operations_t *dir_ops;
@@ -75,7 +77,7 @@ struct vfs_index_node_t
     uint64_t file_size; // 文件大小
     uint64_t blocks;    // 占用的扇区数
     uint64_t attribute;
-    int32_t ref_count; // 引用计数
+    struct lockref lockref; // 自旋锁与引用计数
 
     struct vfs_superblock_t *sb;
     struct vfs_file_operations_t *file_ops;
@@ -267,3 +269,13 @@ int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland);
  * @return int64_t 错误码
  */
 int64_t vfs_rmdir(const char *path, bool from_userland);
+
+/**
+ * @brief 释放dentry,并视情况自动释放inode
+ *
+ * @param dentry 目标dentry
+ * 
+ * @return 错误码
+ *          注意,当dentry指向文件时,如果返回值为正数,则表示在释放了该dentry后,该dentry指向的inode的引用计数。
+ */
+int vfs_dentry_put(struct vfs_dir_entry_t * dentry);

+ 88 - 42
kernel/filesystem/VFS/dcache.c

@@ -3,81 +3,127 @@
 #include <debug/bug.h>
 
 /**
- * @brief 释放dentry
+ * @brief 释放dentry,并视情况自动释放inode
  *
  * @param dentry 目标dentry
+ * 
+ * @return 错误码
+ *          注意,当dentry指向文件时,如果返回值为正数,则表示在释放了该dentry后,该dentry指向的inode的引用计数。
  */
-void vfs_dentry_put(struct vfs_dir_entry_t *dentry)
+int vfs_dentry_put(struct vfs_dir_entry_t *dentry)
 {
     int retval = 0;
     uint64_t in_value = 0;
-    // todo: 加锁、放锁
+    struct kfifo_t fifo = {0};
 
-    // 创建一个用来存放指向dentry的指针的fifo队列
-    struct kfifo_t fifo;
-    // 暂时假设队列大小为1024个元素
-    // todo: 实现队列的自动扩容功能
-    retval = kfifo_alloc(&fifo, 1024 * sizeof(uint64_t), 0);
+    // 引用计数大于1时,尝试释放dentry的话,抛出错误信息
+    if (unlikely(dentry->lockref.lock_count > 1))
+    {
+        BUG_ON(1);
+        retval = -EBUSY;
+        spin_unlock(&dentry->lockref.lock);
+        goto out;
+    }
 
-    if (retval != 0)
-        goto failed;
+    if (D_ISDIR(dentry))
+    {
 
-    // 将根dentry加入队列
-    in_value = (uint64_t)dentry;
-    kfifo_in(&fifo, &in_value, sizeof(uint64_t));
-    list_del(&dentry->child_node_list); // 从父dentry中删除
+        // 创建一个用来存放指向dentry的指针的fifo队列
+        // 暂时假设队列大小为1024个元素
+        // todo: 实现队列的自动扩容功能
+        retval = kfifo_alloc(&fifo, 1024 * sizeof(uint64_t), 0);
 
-    while (!kfifo_empty(&fifo))
-    {
-        // 取出队列中的下一个元素
-        kfifo_out(&fifo, &dentry, sizeof(uint64_t));
-        BUG_ON(dentry == NULL);
-        struct List *list = &dentry->subdirs_list;
-        if (!list_empty(list))
+        if (retval != 0)
+            goto failed;
+
+        // 将根dentry加入队列
+        in_value = (uint64_t)dentry;
+        kfifo_in(&fifo, &in_value, sizeof(uint64_t));
+        list_del(&dentry->child_node_list); // 从父dentry中删除
+
+        while (!kfifo_empty(&fifo))
         {
-            // 将当前dentry下的所有dentry加入队列
-            do
+            // 取出队列中的下一个元素
+            kfifo_out(&fifo, &dentry, sizeof(uint64_t));
+            BUG_ON(dentry == NULL);
+            struct List *list = &dentry->subdirs_list;
+            if (!list_empty(list))
             {
-                list = list_next(list);
-                in_value = (uint64_t)container_of(list, struct vfs_dir_entry_t, child_node_list);
-                if (in_value != NULL)
-                    kfifo_in(&fifo, &in_value, sizeof(uint64_t));
+                // 将当前dentry下的所有dentry加入队列
+                do
+                {
+                    list = list_next(list);
+                    in_value = (uint64_t)container_of(list, struct vfs_dir_entry_t, child_node_list);
+                    if (in_value != NULL)
+                        kfifo_in(&fifo, &in_value, sizeof(uint64_t));
 
-            } while (list_next(list) != (&dentry->subdirs_list));
-        }
+                } while (list_next(list) != (&dentry->subdirs_list));
+            }
+            spin_lock(&dentry->lockref.lock);
+            if(dentry->lockref.count>1)
+            {
+                spin_unlock(&dentry->lockref.lock);
+                continue;
+            }
+            // 释放inode
+            spin_lock(&dentry->dir_inode->lockref.lock);
+            retval = vfs_free_inode(dentry->dir_inode);
+            if (retval > 0) // 还有其他的dentry引用着这个inode
+            {
+                spin_unlock(&dentry->dir_inode->lockref.lock);
+                retval = 0;
+            }
 
+            // 若当前dentry是否为挂载点,则umount
+            if (is_local_mountpoint(dentry))
+                do_umount(dentry);
+            if (dentry->dir_ops->release != NULL)
+                dentry->dir_ops->release(dentry);
+            kfree(dentry);
+        }
+        kfifo_free_alloc(&fifo);
+        retval = 0;
+        goto out;
+    }
+    else // 是文件或设备
+    {
         // 释放inode
-        vfs_free_inode(dentry->dir_inode);
-
-        // 若当前dentry是否为挂载点,则umount
-        if (is_local_mountpoint(dentry))
-            do_umount(dentry);
+        spin_lock(&dentry->dir_inode->lockref.lock);
+        retval = vfs_free_inode(dentry->dir_inode);
+        if (retval > 0) // 还有其他的dentry引用着这个inode
+            spin_unlock(&dentry->dir_inode->lockref.lock);
 
-        dentry->dir_ops->release(dentry);
+        if (dentry->dir_ops->release != NULL)
+            dentry->dir_ops->release(dentry);
         kfree(dentry);
+        goto out;
     }
-    kfifo_free_alloc(&fifo);
-    return;
 failed:;
     if (fifo.buffer != NULL)
         kfifo_free_alloc(&fifo);
     kerror("dentry_put failed.");
+out:;
+    // 在这里不用释放dentry的锁,因为dentry已经被释放掉了
+    return retval;
 }
 
 /**
- * @brief 释放inode
+ * @brief 释放inode(要求已经对inode进行加锁后调用该函数)
  *
  * @param inode 待释放的inode
  * @return int 错误码
+ *             当inode还有其他的使用者时,返回inode的使用者数量
  */
 int vfs_free_inode(struct vfs_index_node_t *inode)
 {
-    --inode->ref_count;
-    BUG_ON(inode->ref_count < 0);
-    if (inode->ref_count == 0)
+    --inode->lockref.count;
+    BUG_ON(inode->lockref.count < 0);
+    if (inode->lockref.count == 0)
     {
         kfree(inode->private_inode_info);
         kfree(inode);
+        return 0;
     }
-    return 0;
+    else // 如果inode没有被释放
+        return inode->lockref.count;
 }

+ 4 - 8
kernel/filesystem/VFS/internal.h

@@ -33,17 +33,13 @@ static inline bool is_local_mountpoint(struct vfs_dir_entry_t *dentry)
         return false;
 }
 
-/**
- * @brief 释放dentry
- * 
- * @param dentry 目标dentry
- */
-void vfs_dentry_put(struct vfs_dir_entry_t * dentry);
+
 
 /**
- * @brief 释放inode
- * 
+ * @brief 释放inode(要求已经对inode进行加锁后调用该函数)
+ *
  * @param inode 待释放的inode
  * @return int 错误码
+ *             当inode还有其他的使用者时,返回inode的使用者数量
  */
 int vfs_free_inode(struct vfs_index_node_t * inode);

+ 1 - 0
kernel/filesystem/devfs/devfs-types.h

@@ -43,4 +43,5 @@ struct devfs_private_inode_info_t
     uint16_t sub_type; // 设备子类型
     struct vfs_file_operations_t *f_ops;
     uint64_t uuid;
+    struct vfs_index_node_t * inode;    // 当前私有信息所绑定的inode
 };

+ 65 - 0
kernel/filesystem/devfs/devfs.c

@@ -5,6 +5,7 @@
 #include <common/string.h>
 #include <mm/slab.h>
 #include <common/spinlock.h>
+#include <debug/bug.h>
 
 struct vfs_super_block_operations_t devfs_sb_ops;
 struct vfs_dir_entry_operations_t devfs_dentry_ops;
@@ -257,6 +258,70 @@ failed:;
     return retval;
 }
 
+/**
+ * @brief 卸载设备
+ *
+ * @param private_inode_info 待卸载的设备的inode私有信息
+ * @param put_private_info 设备被卸载后,执行的函数
+ * @return int 错误码
+ */
+int devfs_unregister_device(struct devfs_private_inode_info_t *private_inode_info)
+{
+    int retval = 0;
+    spin_lock(&devfs_global_lock);
+    struct vfs_dir_entry_t *base_dentry = NULL;
+    struct vfs_dir_entry_t *target_dentry = NULL;
+
+    // 找到父目录的dentry
+    {
+
+        char base_path[64] = {0};
+        switch (private_inode_info->type)
+        {
+        case DEV_TYPE_CHAR:
+            strcpy(base_path, "/dev/char");
+            break;
+        default:
+            retval = -ENOTSUP;
+            goto out;
+            break;
+        }
+
+        base_dentry = vfs_path_walk(base_path, 0);
+        // bug
+        if (unlikely(base_dentry == NULL))
+        {
+            BUG_ON(1);
+            retval = -ENODEV;
+            goto out;
+        }
+    }
+
+    // 遍历子目录,寻找拥有指定inode的dentry(暂时不支持一个inode对应多个dentry的情况)
+    // todo: 支持链接文件的卸载
+    struct List *tmp_list = NULL, *target_list = NULL;
+    list_for_each_safe(target_list, tmp_list, &base_dentry->subdirs_list)
+    {
+        target_dentry = list_entry(target_list, struct vfs_dir_entry_t, child_node_list);
+        if (target_dentry->dir_inode == private_inode_info->inode)
+        {
+            spin_lock(&target_dentry->lockref.lock);
+            retval = vfs_dentry_put(target_dentry);
+            if (retval < 0)
+            {
+                kerror("Error when try to unregister device");
+                spin_unlock(&target_dentry->lockref.lock);
+            }
+            else if (retval == 0) // 该设备的所有dentry均被卸载完成,不必继续迭代
+                break;
+        }
+    }
+    retval = 0;
+out:;
+    spin_unlock(&devfs_global_lock);
+    return retval;
+}
+
 /**
  * @brief 初始化devfs
  *

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

@@ -17,4 +17,13 @@ void devfs_init();
  * @param ret_private_inode_info_ptr 返回的指向inode私有信息结构体的指针
  * @return int 错误码
  */
-int devfs_register_device(uint16_t device_type, uint16_t sub_type, struct vfs_file_operations_t *file_ops, struct devfs_private_inode_info_t **ret_private_inode_info_ptr);
+int devfs_register_device(uint16_t device_type, uint16_t sub_type, struct vfs_file_operations_t *file_ops, struct devfs_private_inode_info_t **ret_private_inode_info_ptr);
+
+/**
+ * @brief 卸载设备
+ * 
+ * @param private_inode_info 待卸载的设备的inode私有信息
+ * @param put_private_info 设备被卸载后,执行的函数
+ * @return int 错误码
+ */
+int devfs_unregister_device(struct devfs_private_inode_info_t * private_inode_info);

+ 2 - 0
kernel/filesystem/devfs/internal.h

@@ -78,6 +78,8 @@ static inline void __devfs_fill_inode(struct vfs_dir_entry_t *dentry, struct vfs
     dentry->dir_inode->private_inode_info = private_inode_data;
     dentry->dir_inode->sb = &devfs_sb;
     dentry->dir_inode->attribute = inode_attr;
+    // 反向绑定inode
+    private_inode_data->inode = dentry->dir_inode;
 }
 
 /**