dcache.c 4.3 KB

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