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