dcache.rs 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. use super::{Dentry, Inode};
  2. use crate::kernel::constants::ENOENT;
  3. use crate::rcu::RCUPointer;
  4. use crate::{
  5. kernel::vfs::{s_isdir, s_islnk},
  6. prelude::*,
  7. rcu::{RCUIterator, RCUList},
  8. };
  9. use alloc::sync::Arc;
  10. use core::sync::atomic::Ordering;
  11. use eonix_runtime::task::Task;
  12. use eonix_sync::Mutex;
  13. const DCACHE_HASH_BITS: u32 = 8;
  14. static DCACHE: [RCUList<Dentry>; 1 << DCACHE_HASH_BITS] =
  15. [const { RCUList::new() }; 1 << DCACHE_HASH_BITS];
  16. static D_EXCHANGE_LOCK: Mutex<()> = Mutex::new(());
  17. pub fn d_hinted(dentry: &Dentry) -> &'static RCUList<Dentry> {
  18. let hash = dentry.hash.load(Ordering::Relaxed) as usize & ((1 << DCACHE_HASH_BITS) - 1);
  19. &DCACHE[hash]
  20. }
  21. pub fn d_iter_for(dentry: &Dentry) -> RCUIterator<'static, Dentry> {
  22. d_hinted(dentry).iter()
  23. }
  24. /// Add the dentry to the dcache
  25. pub fn d_add(dentry: Arc<Dentry>) {
  26. d_hinted(&dentry).insert(dentry);
  27. }
  28. pub fn d_find_fast(dentry: &Dentry) -> Option<Arc<Dentry>> {
  29. d_iter_for(dentry)
  30. .find(|cur| cur.hash_eq(dentry))
  31. .map(|dentry| dentry.clone())
  32. }
  33. /// Call `lookup()` on the parent inode to try find if the dentry points to a valid inode
  34. ///
  35. /// Silently fail without any side effects
  36. pub fn d_try_revalidate(dentry: &Arc<Dentry>) {
  37. let _lock = Task::block_on(D_EXCHANGE_LOCK.lock());
  38. (|| -> KResult<()> {
  39. let parent = dentry.parent().get_inode()?;
  40. let inode = parent.lookup(dentry)?.ok_or(ENOENT)?;
  41. d_save(dentry, inode)
  42. })()
  43. .unwrap_or_default();
  44. }
  45. /// Save the inode to the dentry.
  46. ///
  47. /// Dentry flags will be determined by the inode's mode.
  48. pub fn d_save(dentry: &Arc<Dentry>, inode: Arc<dyn Inode>) -> KResult<()> {
  49. match inode.mode.load(Ordering::Acquire) {
  50. mode if s_isdir(mode) => dentry.save_dir(inode),
  51. mode if s_islnk(mode) => dentry.save_symlink(inode),
  52. _ => dentry.save_reg(inode),
  53. }
  54. }
  55. /// Replace the old dentry with the new one in the dcache
  56. pub fn d_replace(old: &Arc<Dentry>, new: Arc<Dentry>) {
  57. d_hinted(old).replace(old, new);
  58. }
  59. /// Remove the dentry from the dcache so that later d_find_fast will fail
  60. pub fn d_remove(dentry: &Arc<Dentry>) {
  61. d_hinted(dentry).remove(&dentry);
  62. }
  63. pub async fn d_exchange(old: &Arc<Dentry>, new: &Arc<Dentry>) {
  64. if Arc::ptr_eq(old, new) {
  65. return;
  66. }
  67. let _lock = D_EXCHANGE_LOCK.lock().await;
  68. d_remove(old);
  69. d_remove(new);
  70. unsafe {
  71. RCUPointer::exchange(&old.parent, &new.parent);
  72. RCUPointer::exchange(&old.name, &new.name);
  73. }
  74. old.rehash();
  75. new.rehash();
  76. d_add(old.clone());
  77. d_add(new.clone());
  78. }