Skip to main content

starnix_core/vfs/
fs_node_cache.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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    /// The next node ID to allocate.
17    next_ino: Option<AtomicCounter<u64>>,
18
19    /// The FsNodes that have been created for this file system.
20    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        // Optimistic check with RCU read lock.
87        {
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        // Slow path: acquire the lock.
99        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}