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 }