os/vfs/dentry.rs
1//! 目录项(Dentry)与全局缓存
2//!
3//! 该模块实现了 VFS 路径层的核心组件,提供目录树结构管理和路径到 Inode 的映射缓存。
4//!
5//! # 组件
6//!
7//! - [`Dentry`] - 目录项结构,表示路径中的一个节点
8//! - [`DentryCache`] - 全局路径缓存,加速重复路径查找
9//! - [`DENTRY_CACHE`] - 全局缓存单例
10//!
11//! # 核心概念
12//!
13//! ## Dentry 的作用
14//!
15//! Dentry (Directory Entry) 是文件系统目录树中的一个节点,它:
16//! - 缓存文件名到 Inode 的映射
17//! - 维护父子关系,构成目录树
18//! - 标记挂载点信息
19//!
20//! ## 与 Inode 的关系
21//!
22//! - **Dentry**: 路径层组件,可能有多个 Dentry 指向同一个 Inode (硬链接)
23//! - **Inode**: 存储层组件,代表实际的文件或目录
24//!
25//! ```text
26//! /home/user/file.txt ──┐
27//! ├──> Dentry ──> Inode (文件数据)
28//! /tmp/link_to_file ───┘
29//! ```
30//!
31//! # 引用计数设计
32//!
33//! Dentry 使用 `Arc` 和 `Weak` 管理生命周期,避免循环引用:
34//!
35//! - **parent**: `Weak<Dentry>` - 弱引用父节点,避免循环
36//! - **children**: `Arc<Dentry>` - 强引用子节点
37//! - **全局缓存**: `Weak<Dentry>` - 不延长生命周期
38//!
39//! ```text
40//! Arc<Dentry("/")>
41//! └─> Arc<Dentry("/etc")> { parent: Weak<Dentry("/">") }
42//! └─> Arc<Dentry("/etc/passwd")> { parent: Weak<Dentry("/etc")> }
43//! ```
44//!
45//! # 缓存机制
46//!
47//! ## 全局缓存 (DENTRY_CACHE)
48//!
49//! 维护路径字符串到 Dentry 的映射:
50//!
51//! - **插入**: 路径解析成功后自动插入
52//! - **查找**: O(log n) BTreeMap 查找
53//! - **失效**: Weak 引用自动失效,无需手动清理
54//!
55//! ## 树状缓存
56//!
57//! Dentry 内部维护子项缓存,加速相对路径查找:
58//!
59//! ```rust
60//! let parent = vfs_lookup("/etc")?;
61//! // 快速查找,不需要再次访问 Inode
62//! if let Some(child) = parent.lookup_child("passwd") {
63//! // 缓存命中
64//! }
65//! ```
66//!
67//! # 使用示例
68//!
69//! ## 创建 Dentry
70//!
71//! ```rust
72//! use vfs::{Dentry, Inode};
73//!
74//! let inode = create_inode()?;
75//! let dentry = Dentry::new(String::from("file.txt"), inode);
76//! ```
77//!
78//! ## 管理父子关系
79//!
80//! ```rust
81//! // 添加子项
82//! parent.add_child(child_dentry.clone());
83//!
84//! // 查找子项
85//! if let Some(child) = parent.lookup_child("file.txt") {
86//! println!("找到: {}", child.name);
87//! }
88//!
89//! // 删除子项
90//! parent.remove_child("file.txt");
91//! ```
92//!
93//! ## 使用全局缓存
94//!
95//! ```rust
96//! use vfs::DENTRY_CACHE;
97//!
98//! // 插入缓存
99//! DENTRY_CACHE.insert(&dentry);
100//!
101//! // 查找缓存
102//! if let Some(cached) = DENTRY_CACHE.lookup("/etc/passwd") {
103//! // 缓存命中,避免重复路径解析
104//! }
105//!
106//! // 删除缓存
107//! DENTRY_CACHE.remove("/etc/passwd");
108//! ```
109
110use crate::sync::SpinLock;
111use crate::vfs::inode::Inode;
112use alloc::collections::BTreeMap;
113use alloc::string::String;
114use alloc::sync::{Arc, Weak};
115use core::fmt;
116
117/// 目录项(Dentry)
118///
119/// 表示路径中的一个组件,缓存文件名到 inode 的映射
120pub struct Dentry {
121 /// 文件名(不含路径)
122 pub name: String,
123
124 /// 关联的 inode
125 pub inode: Arc<dyn Inode>,
126
127 /// 父目录 dentry(弱引用避免循环)
128 parent: SpinLock<Weak<Dentry>>,
129
130 /// 子 dentry 映射(文件名 -> dentry)
131 children: SpinLock<BTreeMap<String, Arc<Dentry>>>,
132
133 /// 如果此 dentry 是挂载点,指向挂载的根 dentry
134 mount_point: SpinLock<Option<Weak<Dentry>>>,
135}
136
137impl fmt::Debug for Dentry {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 let parent_name = self.parent().map(|p| p.name.clone());
140 let child_names = {
141 let children = self.children.lock();
142 children.keys().cloned().collect::<alloc::vec::Vec<_>>()
143 };
144
145 f.debug_struct("Dentry")
146 .field("name", &self.name)
147 .field("parent", &parent_name)
148 .field("children", &child_names)
149 .finish()
150 }
151}
152
153impl Dentry {
154 /// 创建新的 dentry
155 pub fn new(name: String, inode: Arc<dyn Inode>) -> Arc<Self> {
156 let dentry = Arc::new(Self {
157 name,
158 inode,
159 parent: SpinLock::new(Weak::new()),
160 children: SpinLock::new(BTreeMap::new()),
161 mount_point: SpinLock::new(None),
162 });
163
164 dentry.inode.set_dentry(Arc::downgrade(&dentry));
165
166 dentry
167 }
168
169 /// 设置父 dentry
170 pub fn set_parent(&self, parent: &Arc<Dentry>) {
171 *self.parent.lock() = Arc::downgrade(parent);
172 }
173
174 /// 获取父 dentry
175 pub fn parent(&self) -> Option<Arc<Dentry>> {
176 self.parent.lock().upgrade()
177 }
178
179 /// 查找子 dentry
180 pub fn lookup_child(&self, name: &str) -> Option<Arc<Dentry>> {
181 self.children.lock().get(name).cloned()
182 }
183
184 /// 添加子 dentry
185 pub fn add_child(self: &Arc<Self>, child: Arc<Dentry>) {
186 child.set_parent(self);
187 self.children.lock().insert(child.name.clone(), child);
188 }
189
190 /// 删除子 dentry
191 pub fn remove_child(&self, name: &str) -> Option<Arc<Dentry>> {
192 self.children.lock().remove(name)
193 }
194
195 /// 获取完整路径(通过向上遍历父节点直到根目录)
196 pub fn full_path(&self) -> String {
197 let mut components = alloc::vec::Vec::new();
198 let mut current: *const Dentry = self;
199
200 // 向上遍历到根目录
201 loop {
202 let dentry = unsafe { &*current };
203
204 // 根目录的名字是 "/"
205 if dentry.name == "/" {
206 break;
207 }
208
209 components.push(dentry.name.clone());
210
211 // 获取父节点
212 match dentry.parent() {
213 Some(parent) => current = Arc::as_ptr(&parent),
214 None => break, // 到达根或孤立节点
215 }
216 }
217
218 // 反转(从根到当前)
219 components.reverse();
220
221 if components.is_empty() {
222 String::from("/")
223 } else {
224 String::from("/") + &components.join("/")
225 }
226 }
227
228 /// 设置挂载点
229 pub fn set_mount(&self, mounted_root: &Arc<Dentry>) {
230 *self.mount_point.lock() = Some(Arc::downgrade(mounted_root));
231 }
232
233 /// 清除挂载点
234 pub fn clear_mount(&self) {
235 *self.mount_point.lock() = None;
236 }
237
238 /// 获取挂载的根 dentry(如果有)
239 pub fn get_mount(&self) -> Option<Arc<Dentry>> {
240 self.mount_point.lock().as_ref()?.upgrade()
241 }
242}
243
244// 全局 dentry 缓存实例
245lazy_static::lazy_static! {
246 pub static ref DENTRY_CACHE: DentryCache = DentryCache::new();
247}
248
249/// 全局 Dentry 缓存
250pub struct DentryCache {
251 /// 路径 -> dentry 的弱引用映射
252 cache: SpinLock<BTreeMap<String, Weak<Dentry>>>,
253}
254
255impl DentryCache {
256 /// 创建新的缓存
257 pub const fn new() -> Self {
258 Self {
259 cache: SpinLock::new(BTreeMap::new()),
260 }
261 }
262
263 /// 从缓存中查找 dentry
264 pub fn lookup(&self, path: &str) -> Option<Arc<Dentry>> {
265 let cache = self.cache.lock();
266 let weak = cache.get(path)?;
267 weak.upgrade()
268 }
269
270 /// 插入 dentry 到缓存
271 pub fn insert(&self, dentry: &Arc<Dentry>) {
272 let path = dentry.full_path();
273 self.cache.lock().insert(path, Arc::downgrade(dentry));
274 }
275
276 /// 从缓存中移除
277 pub fn remove(&self, path: &str) {
278 self.cache.lock().remove(path);
279 }
280
281 /// 清空缓存
282 pub fn clear(&self) {
283 self.cache.lock().clear();
284 }
285}