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::{FsNode, FsNodeHandle, WeakFsNodeHandle};
6use starnix_lifecycle::AtomicU64Counter;
7use starnix_sync::Mutex;
8use starnix_uapi::errors::Errno;
9use starnix_uapi::ino_t;
10use std::collections::HashMap;
11use std::collections::hash_map::Entry;
12use std::ops::Range;
13use std::sync::Arc;
14
15pub struct FsNodeCache {
16    /// The next node ID to allocate.
17    next_ino: Option<AtomicU64Counter>,
18
19    /// The FsNodes that have been created for this file system.
20    nodes: Mutex<HashMap<ino_t, WeakFsNodeHandle>>,
21}
22
23impl Default for FsNodeCache {
24    fn default() -> Self {
25        Self::new(false)
26    }
27}
28
29impl FsNodeCache {
30    pub fn new(uses_external_node_ids: bool) -> Self {
31        Self {
32            next_ino: if uses_external_node_ids { None } else { Some(AtomicU64Counter::new(1)) },
33            nodes: Mutex::new(HashMap::new()),
34        }
35    }
36
37    pub fn uses_external_node_ids(&self) -> bool {
38        self.next_ino.is_none()
39    }
40
41    pub fn allocate_ino(&self) -> Option<ino_t> {
42        self.next_ino.as_ref().map(|counter| counter.next())
43    }
44
45    pub fn allocate_ino_range(&self, size: usize) -> Option<Range<ino_t>> {
46        assert!(size > 0);
47        self.next_ino.as_ref().map(|counter| {
48            let start = counter.add(size as u64);
49            Range { start: start as ino_t, end: start + size as ino_t }
50        })
51    }
52
53    pub fn insert_node(&self, node: &FsNodeHandle) {
54        let node_key = node.node_key();
55        let mut nodes = self.nodes.lock();
56        nodes.insert(node_key, Arc::downgrade(node));
57    }
58
59    pub fn remove_node(&self, node: &FsNode) {
60        let node_key = node.node_key();
61        let mut nodes = self.nodes.lock();
62        if let Some(weak_node) = nodes.get(&node_key) {
63            if weak_node.strong_count() == 0 {
64                nodes.remove(&node_key);
65            }
66        }
67    }
68
69    pub fn get_and_validate_or_create_node<V, C>(
70        &self,
71        node_key: ino_t,
72        validate_fn: V,
73        create_fn: C,
74    ) -> Result<FsNodeHandle, Errno>
75    where
76        V: FnOnce(&FsNodeHandle) -> bool,
77        C: FnOnce() -> Result<FsNodeHandle, Errno>,
78    {
79        let mut nodes = self.nodes.lock();
80        match nodes.entry(node_key) {
81            Entry::Vacant(entry) => {
82                let node = create_fn()?;
83                entry.insert(Arc::downgrade(&node));
84                Ok(node)
85            }
86            Entry::Occupied(mut entry) => {
87                if let Some(node) = entry.get().upgrade() {
88                    if validate_fn(&node) {
89                        return Ok(node);
90                    }
91                }
92                let node = create_fn()?;
93                entry.insert(Arc::downgrade(&node));
94                Ok(node)
95            }
96        }
97    }
98}