starnix_core/vfs/
fs_node_cache.rs1use crate::vfs::{FsLockDepType, FsNode, FsNodeHandle, WeakFsNodeHandle};
6use fuchsia_rcu::RcuReadScope;
7use starnix_lifecycle::AtomicCounter;
8use starnix_rcu::rcu_hash_map::{DynamicRcuHashMap, Entry};
9use starnix_sync::{FsNodeCacheLock, FsNodeCacheRecursiveLock, FuseFsNodeCacheLock};
10use starnix_uapi::errors::Errno;
11use starnix_uapi::ino_t;
12use std::ops::Range;
13use std::sync::Arc;
14
15pub struct FsNodeCache {
16 next_ino: Option<AtomicCounter<u64>>,
18
19 nodes: DynamicRcuHashMap<ino_t, WeakFsNodeHandle>,
21}
22
23impl Default for FsNodeCache {
24 fn default() -> Self {
25 Self::new(false, FsLockDepType::Normal)
26 }
27}
28
29impl FsNodeCache {
30 pub fn new(uses_external_node_ids: bool, fs_lockdep_type: FsLockDepType) -> Self {
31 Self {
32 next_ino: if uses_external_node_ids {
33 None
34 } else {
35 Some(AtomicCounter::<u64>::new(1))
36 },
37 nodes: match fs_lockdep_type {
38 FsLockDepType::Normal => DynamicRcuHashMap::new::<FsNodeCacheLock>(),
39 FsLockDepType::Recursive => DynamicRcuHashMap::new::<FsNodeCacheRecursiveLock>(),
40 FsLockDepType::Fuse => DynamicRcuHashMap::new::<FuseFsNodeCacheLock>(),
41 },
42 }
43 }
44
45 pub fn uses_external_node_ids(&self) -> bool {
46 self.next_ino.is_none()
47 }
48
49 pub fn allocate_ino(&self) -> Option<ino_t> {
50 self.next_ino.as_ref().map(|counter| counter.next())
51 }
52
53 pub fn allocate_ino_range(&self, size: usize) -> Option<Range<ino_t>> {
54 assert!(size > 0);
55 self.next_ino.as_ref().map(|counter| {
56 let start = counter.add(size as u64);
57 Range { start: start as ino_t, end: start + size as ino_t }
58 })
59 }
60
61 pub fn insert_node(&self, node: &FsNodeHandle) {
62 let node_key = node.node_key();
63 self.nodes.insert(node_key, Arc::downgrade(node));
64 }
65
66 pub fn remove_node(&self, node: &FsNode) {
67 let node_key = node.node_key();
68 let mut nodes = self.nodes.lock();
69 if let Some(weak_node) = nodes.get(&node_key) {
70 if weak_node.strong_count() == 0 {
71 nodes.remove(&node_key);
72 }
73 }
74 }
75
76 pub fn get_and_validate_or_create_node<V, C>(
77 &self,
78 node_key: ino_t,
79 validate_fn: V,
80 create_fn: C,
81 ) -> Result<FsNodeHandle, Errno>
82 where
83 V: Fn(&FsNodeHandle) -> bool,
84 C: FnOnce() -> Result<FsNodeHandle, Errno>,
85 {
86 {
88 let scope = RcuReadScope::new();
89 if let Some(weak_node) = self.nodes.get(&scope, &node_key) {
90 if let Some(node) = weak_node.upgrade() {
91 if validate_fn(&node) {
92 return Ok(node);
93 }
94 }
95 }
96 }
97
98 let mut nodes = self.nodes.lock();
100 match nodes.entry(node_key) {
101 Entry::Vacant(entry) => {
102 let node = create_fn()?;
103 entry.insert(Arc::downgrade(&node));
104 Ok(node)
105 }
106 Entry::Occupied(mut entry) => {
107 if let Some(node) = entry.get().upgrade() {
108 if validate_fn(&node) {
109 return Ok(node);
110 }
111 }
112 let node = create_fn()?;
113 entry.insert(Arc::downgrade(&node));
114 Ok(node)
115 }
116 }
117 }
118}