dcache.rs 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. use core::{mem::MaybeUninit, sync::atomic::AtomicPtr};
  2. use alloc::sync::Arc;
  3. use bindings::ENOENT;
  4. use crate::{
  5. kernel::vfs::{s_isdir, s_islnk},
  6. prelude::*,
  7. rcu::{RCUIterator, RCUList, RCUPointer},
  8. };
  9. use super::{Dentry, Inode};
  10. use lazy_static::lazy_static;
  11. const DCACHE_HASH_BITS: u32 = 8;
  12. static DCACHE: [RCUList<Dentry>; 1 << DCACHE_HASH_BITS] =
  13. [const { RCUList::new() }; 1 << DCACHE_HASH_BITS];
  14. lazy_static! {
  15. static ref DROOT: Arc<Dentry> = {
  16. let dentry = Arc::new_uninit();
  17. let fake_parent = unsafe { dentry.clone().assume_init() };
  18. unsafe { &mut *(Arc::as_ptr(&dentry) as *mut MaybeUninit<Dentry>) }
  19. .write(Dentry {
  20. parent: fake_parent,
  21. name: b"[root]".as_slice().into(),
  22. hash: 0,
  23. prev: AtomicPtr::default(),
  24. next: AtomicPtr::default(),
  25. data: RCUPointer::empty(),
  26. });
  27. unsafe { dentry.assume_init() }
  28. };
  29. }
  30. pub fn _looped_droot() -> &'static Arc<Dentry> {
  31. &DROOT
  32. }
  33. pub fn d_hinted(hash: u64) -> &'static RCUList<Dentry> {
  34. let hash = hash as usize & ((1 << DCACHE_HASH_BITS) - 1);
  35. &DCACHE[hash]
  36. }
  37. pub fn d_iter_for(hash: u64) -> RCUIterator<'static, Dentry> {
  38. d_hinted(hash).iter()
  39. }
  40. pub fn d_add(dentry: &Arc<Dentry>) {
  41. d_hinted(dentry.hash).insert(dentry.clone());
  42. }
  43. pub fn d_find_fast(dentry: &Arc<Dentry>) -> Option<Arc<Dentry>> {
  44. d_iter_for(dentry.rehash())
  45. .find(|cur| cur.hash_eq(dentry))
  46. .map(|dentry| dentry.clone())
  47. }
  48. /// Silently fail without any side effects
  49. pub fn d_try_revalidate(dentry: &Arc<Dentry>) {
  50. (|| -> KResult<()> {
  51. let parent = dentry.parent().get_inode()?;
  52. let inode = parent.lookup(&parent, dentry)?.ok_or(ENOENT)?;
  53. d_save(dentry, inode)
  54. })()
  55. .unwrap_or_default();
  56. }
  57. pub fn d_save(dentry: &Arc<Dentry>, inode: Arc<Inode>) -> KResult<()> {
  58. let mode = inode.idata.lock().mode;
  59. match mode {
  60. mode if s_isdir(mode) => dentry.save_dir(inode),
  61. mode if s_islnk(mode) => dentry.save_symlink(inode),
  62. _ => dentry.save_reg(inode),
  63. }
  64. }
  65. pub fn d_replace(old: &Arc<Dentry>, new: Arc<Dentry>) {
  66. d_hinted(old.hash).replace(old, new);
  67. }