2022-10-06 14:48:44 +08:00

129 lines
4.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "internal.h"
#include <common/kfifo.h>
#include <debug/bug.h>
/**
* @brief 释放dentry并视情况自动释放inode
*
* @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};
// 引用计数大于1时尝试释放dentry的话抛出错误信息
if (unlikely(dentry->lockref.lock_count > 1))
{
BUG_ON(1);
retval = -EBUSY;
spin_unlock(&dentry->lockref.lock);
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));
}
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
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);
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;
}