1 #include "internal.h"
2 #include <common/kfifo.h>
3 #include <debug/bug.h>
4 
5 /**
6  * @brief 释放dentry,并视情况自动释放inode. 在调用该函数前,需要将dentry加锁。
7  *
8  * @param dentry 目标dentry
9  *
10  * @return 错误码
11  *          注意,当dentry指向文件时,如果返回值为正数,则表示在释放了该dentry后,该dentry指向的inode的引用计数。
12  */
vfs_dentry_put(struct vfs_dir_entry_t * dentry)13 int vfs_dentry_put(struct vfs_dir_entry_t *dentry)
14 {
15     int retval = 0;
16     uint64_t in_value = 0;
17     struct kfifo_t fifo = {0};
18     const struct vfs_dir_entry_t *start_dentry = dentry;
19 
20     // 引用计数大于1时,尝试释放dentry的话,抛出错误信息
21     if (unlikely(dentry->lockref.count > 1))
22     {
23         BUG_ON(1);
24         retval = -EBUSY;
25         goto out;
26     }
27 
28     if (D_ISDIR(dentry))
29     {
30 
31         // 创建一个用来存放指向dentry的指针的fifo队列
32         // 暂时假设队列大小为1024个元素
33         // todo: 实现队列的自动扩容功能
34         retval = kfifo_alloc(&fifo, 1024 * sizeof(uint64_t), 0);
35 
36         if (retval != 0)
37             goto failed;
38 
39         // 将根dentry加入队列
40         in_value = (uint64_t)dentry;
41         kfifo_in(&fifo, &in_value, sizeof(uint64_t));
42         list_del(&dentry->child_node_list); // 从父dentry中删除
43 
44         while (!kfifo_empty(&fifo))
45         {
46             // 取出队列中的下一个元素
47             kfifo_out(&fifo, &dentry, sizeof(uint64_t));
48             BUG_ON(dentry == NULL);
49             struct List *list = &dentry->subdirs_list;
50             if (!list_empty(list))
51             {
52                 // 将当前dentry下的所有dentry加入队列
53                 do
54                 {
55                     list = list_next(list);
56                     in_value = (uint64_t)container_of(list, struct vfs_dir_entry_t, child_node_list);
57                     if (in_value != NULL)
58                         kfifo_in(&fifo, &in_value, sizeof(uint64_t));
59 
60                 } while (list_next(list) != (&dentry->subdirs_list));
61             }
62             if (unlikely(dentry != start_dentry))
63                 spin_lock(&dentry->lockref.lock);
64             if (dentry->lockref.count > 1)
65             {
66                 if (unlikely(dentry != start_dentry))
67                     spin_unlock(&dentry->lockref.lock);
68                 continue;
69             }
70             // 释放inode
71             spin_lock(&dentry->dir_inode->lockref.lock);
72             retval = vfs_free_inode(dentry->dir_inode);
73             if (retval > 0) // 还有其他的dentry引用着这个inode
74             {
75                 spin_unlock(&dentry->dir_inode->lockref.lock);
76                 retval = 0;
77             }
78 
79             // 若当前dentry是否为挂载点,则umount
80             if (is_local_mountpoint(dentry))
81                 do_umount(dentry);
82             if (dentry->dir_ops->release != NULL)
83                 dentry->dir_ops->release(dentry);
84             kfree(dentry);
85         }
86         kfifo_free_alloc(&fifo);
87         retval = 0;
88         goto out;
89     }
90     else // 是文件或设备
91     {
92         kdebug("to put dentry: file: %s", dentry->name);
93         list_del(&dentry->child_node_list); // 从父dentry中删除
94         // 释放inode
95         spin_lock(&dentry->dir_inode->lockref.lock);
96         retval = vfs_free_inode(dentry->dir_inode);
97         kdebug("retval=%d", retval);
98         if (retval > 0) // 还有其他的dentry引用着这个inode
99             spin_unlock(&dentry->dir_inode->lockref.lock);
100 
101         if (dentry->dir_ops->release != NULL)
102             dentry->dir_ops->release(dentry);
103         kfree(dentry);
104         goto out;
105     }
106 failed:;
107     if (fifo.buffer != NULL)
108         kfifo_free_alloc(&fifo);
109     kerror("dentry_put failed.");
110 out:;
111     // 在这里不用释放dentry的锁,因为dentry已经被释放掉了
112     return retval;
113 }
114 
115 /**
116  * @brief 释放inode(要求已经对inode进行加锁后调用该函数)
117  *
118  * @param inode 待释放的inode
119  * @return int 错误码
120  *             当inode还有其他的使用者时,返回inode的使用者数量
121  */
vfs_free_inode(struct vfs_index_node_t * inode)122 int vfs_free_inode(struct vfs_index_node_t *inode)
123 {
124     --inode->lockref.count;
125     BUG_ON(inode->lockref.count < 0);
126     if (inode->lockref.count == 0)
127     {
128         kfree(inode->private_inode_info);
129         kfree(inode);
130         return 0;
131     }
132     else // 如果inode没有被释放
133         return inode->lockref.count;
134 }