kernel/fs/vfs_v2/
mount_tree.rs

1//! VFS v2 Mount Tree Implementation
2//! 
3//! This module provides a new mount tree architecture for VFS v2 that supports:
4//! - Hierarchical mount points with parent-child relationships
5//! - Bind mounts and overlay mounts
6//! - Proper path resolution across mount boundaries
7//! - Efficient mount point lookup and traversal
8
9use alloc::collections::BTreeMap;
10use alloc::string::{String, ToString};
11use alloc::vec::Vec;
12use alloc::sync::{Arc, Weak};
13use alloc::format;
14use core::sync::atomic::{AtomicU64, Ordering};
15use spin::RwLock;
16
17use super::core::{VfsEntry, FileSystemOperations};
18use super::manager::{VfsManager, PathResolutionOptions};
19use crate::fs::{FileSystemError, FileSystemErrorKind};
20
21pub type VfsResult<T> = Result<T, FileSystemError>;
22pub type VfsEntryRef = Arc<VfsEntry>;
23pub type VfsEntryWeakRef = Weak<VfsEntry>;
24
25
26// Helper function to create FileSystemError
27fn vfs_error(kind: FileSystemErrorKind, message: &str) -> FileSystemError {
28    FileSystemError::new(kind, message)
29}
30
31/// Unique identifier for mount points
32#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
33pub struct MountId(u64);
34
35impl MountId {
36    fn new() -> Self {
37        static COUNTER: AtomicU64 = AtomicU64::new(1);
38        Self(COUNTER.fetch_add(1, Ordering::Relaxed))
39    }
40}
41
42/// Unique identifier for VfsManager instances
43#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
44pub struct VfsManagerId(u64);
45
46impl VfsManagerId {
47    pub fn new() -> Self {
48        static COUNTER: AtomicU64 = AtomicU64::new(1);
49        Self(COUNTER.fetch_add(1, Ordering::Relaxed))
50    }
51}
52
53/// Type of mount operation
54#[derive(Debug, Clone)]
55pub enum MountType {
56    /// Regular mount
57    Regular,
58    /// Bind mount (mount existing directory at another location)
59    Bind,
60    /// Overlay mount (overlay multiple directories)
61    Overlay {
62        /// The list of overlay layers (top to bottom priority)
63        layers: Vec<VfsEntryRef>,
64    },
65}
66
67/// Mount options (for compatibility with manager_v2.rs)
68#[derive(Debug, Clone, Default)]
69pub struct MountOptionsV2 {
70    pub readonly: bool,
71    pub flags: u32,
72}
73
74/// Mount point information
75#[derive(Debug)]
76pub struct MountPoint {
77    /// Unique mount ID
78    pub id: MountId,
79    /// Type of mount
80    pub mount_type: MountType,
81    /// Mount path (relative to parent mount)
82    pub path: String,
83    /// Root entry of the mounted filesystem
84    pub root: VfsEntryRef,
85    /// Parent mount (weak reference to avoid cycles)
86    pub parent: Option<Weak<MountPoint>>,
87    /// Parent entry (strong reference to the VFS entry at the mount point to ensure it stays alive)
88    pub parent_entry: Option<VfsEntryRef>,
89    /// Child mounts: shared map of VfsEntry ID to MountPoint
90    pub children: Arc<RwLock<BTreeMap<u64, Arc<MountPoint>>>>,
91}
92
93impl MountPoint {
94    /// Create a new regular mount point
95    pub fn new_regular(path: String, root: VfsEntryRef) -> Arc<Self> {
96        Arc::new(Self {
97            id: MountId::new(),
98            mount_type: MountType::Regular,
99            path,
100            root,
101            parent: None,
102            parent_entry: None,
103            children: Arc::new(RwLock::new(BTreeMap::new())),
104        })
105    }
106
107    /// Create a new bind mount point
108    pub fn new_bind(path: String, source: VfsEntryRef) -> Arc<Self> {
109        Arc::new(Self {
110            id: MountId::new(),
111            mount_type: MountType::Bind,
112            path,
113            root: source,
114            parent: None,
115            parent_entry: None,
116            children: Arc::new(RwLock::new(BTreeMap::new())),
117        })
118    }
119
120    /// Create a new overlay mount point
121    pub fn new_overlay(path: String, layers: Vec<VfsEntryRef>) -> VfsResult<Arc<Self>> {
122        if layers.is_empty() {
123            return Err(vfs_error(FileSystemErrorKind::InvalidPath, "Overlay mount requires at least one layer"));
124        }
125
126        // Use the top layer as the root
127        let root = layers[0].clone();
128
129        Ok(Arc::new(Self {
130            id: MountId::new(),
131            mount_type: MountType::Overlay {
132                layers: layers.clone(),
133            },
134            path,
135            root,
136            parent: None,
137            parent_entry: None,
138            children: Arc::new(RwLock::new(BTreeMap::new())),
139        }))
140    }
141
142    /// Get the parent mount point
143    pub fn get_parent(&self) -> Option<Arc<MountPoint>> {
144        self.parent.as_ref().and_then(|weak| weak.upgrade())
145    }
146
147    /// Check if this is the root mount
148    pub fn is_root_mount(&self) -> bool {
149        self.parent.is_none()
150    }
151
152    /// Get child mount by VfsEntry
153    pub fn get_child(&self, entry: &VfsEntryRef) -> Option<Arc<MountPoint>> {
154        let key = entry.node().id();
155        self.children.read().get(&key).cloned()
156    }
157
158    /// Add a child mount by VfsEntry
159    pub fn add_child(self: &Arc<Self>, entry: &VfsEntryRef, child: Arc<MountPoint>) -> VfsResult<()> {
160        // Set parent reference in child
161        let mut_child: *const MountPoint = Arc::as_ptr(&child);
162        unsafe {
163            let mut_child = mut_child as *mut MountPoint;
164            (*mut_child).parent = Some(Arc::downgrade(self));
165            (*mut_child).parent_entry = Some(entry.clone());
166        }
167        let key = entry.node().id();
168        self.children.write().insert(key, child);
169        Ok(())
170    }
171
172    /// Remove a child mount by VfsEntry
173    pub fn remove_child(&self, entry: &VfsEntryRef) -> Option<Arc<MountPoint>> {
174        let key = entry.node().id();
175        self.children.write().remove(&key)
176    }
177
178    /// List all child mount IDs
179    pub fn list_children(&self) -> Vec<u64> {
180        self.children.read().keys().cloned().collect()
181    }
182
183    /// Check if this mount point is a bind mount
184    pub fn is_bind_mount(&self) -> bool {
185        matches!(self.mount_type, MountType::Bind { .. })
186    }
187
188    /// Get the bind source entry (for regular bind mounts only)
189    pub fn get_bind_source(&self) -> Option<VfsEntryRef> {
190        match &self.mount_type {
191            MountType::Bind { .. } => Some(self.root.clone()),
192            _ => None,
193        }
194    }
195
196    /// Get cross-VFS bind information
197    pub fn get_cross_vfs_info(&self) -> Option<(Weak<VfsManager>, &str, u64)> {
198        match &self.mount_type {
199            MountType::Bind { .. } => {
200                None
201            }
202            _ => None,
203        }
204    }
205}
206
207/// Mount tree manager for VFS v2
208#[derive(Debug)]
209pub struct MountTree {
210    /// Root mount point (can be updated when mounting at "/")
211    pub root_mount: RwLock<Arc<MountPoint>>,
212}
213
214impl MountTree {
215    /// Create a new mount tree with the given root
216    pub fn new(root_entry: VfsEntryRef) -> Self {
217        let root_mount = MountPoint::new_regular("/".to_string(), root_entry);
218        let root_id = root_mount.id;
219        
220        let mut mounts = BTreeMap::new();
221        mounts.insert(root_id, Arc::downgrade(&root_mount));
222
223        Self {
224            root_mount: RwLock::new(root_mount.clone()),
225        }
226    }
227
228    /// Create a bind mount.
229    ///
230    /// # Arguments
231    /// * `source_entry` - The VFS entry to be mounted.
232    /// * `target_entry` - The VFS entry where the source will be mounted.
233    /// * `target_mount_point` - The mount point containing the target entry.
234    pub fn bind_mount(
235        &self,
236        source_entry: VfsEntryRef,
237        target_entry: VfsEntryRef,
238        target_mount_point: Arc<MountPoint>,
239    ) -> VfsResult<MountId> {
240        // Create a new bind mount point. The name of the mount point is the name of the target entry.
241        let bind_mount = MountPoint::new_bind(target_entry.name().clone(), source_entry);
242        let mount_id = bind_mount.id;
243
244        // Add the new mount as a child of the target's containing mount point, attached to the target entry.
245        target_mount_point.add_child(&target_entry, bind_mount.clone())?;
246
247        Ok(mount_id)
248    }
249
250    /// Mount a filesystem at a specific entry in the mount tree.
251    pub fn mount(
252        &self,
253        target_entry: VfsEntryRef,
254        target_mount_point: Arc<MountPoint>,
255        filesystem: Arc<dyn FileSystemOperations>,
256    ) -> VfsResult<MountId> {
257        // The root of the new filesystem.
258        let new_fs_root_node = filesystem.root_node();
259
260        // Create a VfsEntry for the root of the new filesystem.
261        let new_fs_root_entry = VfsEntry::new(None, "/".to_string(), new_fs_root_node);
262
263        // Create a new mount point for the filesystem.
264        let new_mount = MountPoint::new_regular(target_entry.name().clone(), new_fs_root_entry);
265        let mount_id = new_mount.id;
266
267        // Add the new mount as a child to the target's mount point.
268        target_mount_point.add_child(&target_entry, new_mount.clone())?;
269
270        Ok(mount_id)
271    }
272
273    /// Replaces the root mount point.
274    pub fn replace_root(&self, new_root: Arc<MountPoint>) {
275        *self.root_mount.write() = new_root.clone();
276    }
277
278    /// Check if a path is a mount point
279    /// 
280    /// # Arguments
281    /// * `entry_to_check` - The VFS entry to check if it is a mount point.
282    /// * `mount_point_to_check` - The mount point to check against.
283    /// 
284    /// # Notes
285    /// `entry_to_check` and `mount_point_to_check` should be in the same mount point.
286    pub fn is_mount_point(&self, entry_to_check: &VfsEntryRef, mount_point_to_check: &Arc<MountPoint>) -> bool {
287        // let node_to_check = entry_to_check.node();
288        // let node_id = node_to_check.id();
289        
290        // let fs_ptr_to_check = match node_to_check.filesystem().and_then(|w| w.upgrade()) {
291        //     Some(fs) => Arc::as_ptr(&fs) as *const (),
292        //     None => return false,
293        // };
294
295        // for mount in self.mounts.read().values().filter_map(|w| w.upgrade()) {
296        //     if let Some(parent_entry) = &mount.parent_entry {
297        //         if parent_entry.node().id() == node_id {
298        //             let parent_fs_ptr = parent_entry.node().filesystem().and_then(|w| w.upgrade())
299        //                 .map(|fs| Arc::as_ptr(&fs) as *const ());
300        //             if parent_fs_ptr == Some(fs_ptr_to_check) {
301        //                 return true;
302        //             }
303        //         }
304        //     }
305        // 
306
307        let children = mount_point_to_check.children.read();
308        children.contains_key(&entry_to_check.node().id())      
309    }
310
311    /// Check if an entry is a source for a bind mount
312    pub fn is_bind_source(&self, entry_to_check: &VfsEntryRef) -> bool {
313        let node_to_check = entry_to_check.node();
314        let node_id = node_to_check.id();
315        
316        let fs_ptr_to_check = match node_to_check.filesystem().and_then(|w| w.upgrade()) {
317            Some(fs) => Arc::as_ptr(&fs) as *const (),
318            None => return false,
319        };
320
321        false
322    }
323
324    /// Check if an entry is used in a mount (either as a mount point or a bind source)
325    pub fn is_entry_used_in_mount(&self, entry_to_check: &VfsEntryRef, mount_point_to_check: &Arc<MountPoint>) -> bool {
326        // self.is_mount_point(entry_to_check, mount_point_to_check) || self.is_bind_source(entry_to_check)
327        self.is_mount_point(entry_to_check, mount_point_to_check)
328    }
329
330    /// Unmount a filesystem
331    pub fn unmount(&self, entry: &VfsEntryRef, parent_mount_point: &Arc<MountPoint>) -> VfsResult<Arc<MountPoint>> {
332        let removed_mount = parent_mount_point.remove_child(&entry);
333        match removed_mount {
334            Some(mount) => Ok(mount),
335            None => Err(vfs_error(FileSystemErrorKind::NotFound, "Mount point not found for unmount")),
336        }
337    }
338
339    /// Resolve a path to a VFS entry, handling mount boundaries
340    pub fn resolve_path(&self, path: &str) -> VfsResult<(VfsEntryRef, Arc<MountPoint>)> {
341        self.resolve_path_internal(path, false, &PathResolutionOptions { no_follow: false })
342    }
343
344    /// Resolve a path to the mount point entry (not the mounted content)
345    /// This is used for unmount operations where we need the actual mount point
346    pub fn resolve_mount_point(&self, path: &str) -> VfsResult<(VfsEntryRef, Arc<MountPoint>)> {
347        self.resolve_path_internal(path, true, &PathResolutionOptions { no_follow: false })
348    }
349
350    /// Resolve a path with specified options
351    pub fn resolve_path_with_options(&self, path: &str, options: &PathResolutionOptions) -> VfsResult<(VfsEntryRef, Arc<MountPoint>)> {
352        self.resolve_path_internal(path, false, options)
353    }
354
355    /// Resolve a path to the mount point entry with options
356    pub fn resolve_mount_point_with_options(&self, path: &str, options: &PathResolutionOptions) -> VfsResult<(VfsEntryRef, Arc<MountPoint>)> {
357        self.resolve_path_internal(path, true, options)
358    }
359
360    fn resolve_path_internal(&self, path: &str, resolve_mount: bool, options: &PathResolutionOptions) -> VfsResult<(VfsEntryRef, Arc<MountPoint>)> {
361        if path.is_empty() || path == "/" {
362            return Ok((self.root_mount.read().root.clone(), self.root_mount.read().clone()));
363        }
364
365        let components = self.parse_path(path);
366        let mut current_mount = self.root_mount.read().clone();
367        let mut current_entry = current_mount.root.clone();
368        
369        let mut resolved_path = String::new();
370        for (i, component) in components.iter().enumerate() {
371            let is_final_component = i == components.len() - 1;
372            
373            if component == ".." {
374                // Handle parent directory traversal (same as original implementation)
375                let is_at_mount_root = current_entry.node().id() == current_mount.root.node().id();
376                
377                if is_at_mount_root {
378                    let parent_info = current_mount.get_parent().zip(current_mount.parent_entry.clone());
379                    match parent_info {
380                        Some((parent_mount, parent_entry)) => {
381                            current_mount = parent_mount;
382                            current_entry = self.resolve_component(parent_entry, &"..")?;
383                        },
384                        None => {
385                            // No parent mount - stay at current mount root
386                        }
387                    }
388                } else {
389                    current_entry = self.resolve_component(current_entry, &component)?;
390                }
391            } else {
392                // Regular path traversal with symlink handling based on options
393                let should_follow_symlinks = if is_final_component {
394                    // For the final component, check no_follow option
395                    !options.no_follow
396                } else {
397                    // For intermediate components, always follow symlinks
398                    true
399                };
400
401                if should_follow_symlinks {
402                    // Use normal component resolution (which follows symlinks)
403                    current_entry = self.resolve_component(current_entry, &component)?;
404                } else {
405                    // Don't follow symlinks - use direct filesystem lookup
406                    current_entry = self.resolve_component_no_symlink(current_entry, &component)?;
407                }
408
409                // Handle mount points (same as original implementation)
410                if resolve_mount && is_final_component {
411                    if let Some(_child_mount) = current_mount.get_child(&current_entry) {
412                        return Ok((current_entry, current_mount));
413                    }
414                } else {
415                    if let Some(child_mount) = current_mount.get_child(&current_entry) {
416                        current_mount = child_mount;
417                        current_entry = current_mount.root.clone();
418                    }
419                }
420            }
421
422            resolved_path.push('/');
423            resolved_path.push_str(&component);
424        }
425
426        Ok((current_entry, current_mount))
427    }
428
429    /// Resolve a single path component without following symlinks
430    fn resolve_component_no_symlink(&self, entry: VfsEntryRef, component: &str) -> VfsResult<VfsEntryRef> {
431        // Handle special cases
432        if component == "." {
433            return Ok(entry);
434        }
435
436        // Check cache first (fast path)
437        let component_string = component.to_string();
438        if let Some(cached_child) = entry.get_child(&component_string) {
439            return Ok(cached_child);
440        }
441
442        // Cache miss - perform filesystem lookup without symlink resolution
443        let parent_node = entry.node();
444        debug_assert!(parent_node.filesystem().is_some(), "resolve_component_no_symlink: parent_node.filesystem() is None");
445        let filesystem = parent_node.filesystem()
446            .and_then(|w| w.upgrade())
447            .ok_or_else(|| vfs_error(FileSystemErrorKind::NotSupported, "No filesystem reference"))?;
448        
449        // Ask filesystem to lookup the component
450        let child_node = filesystem.lookup(&parent_node, &component_string)
451            .map_err(|e| vfs_error(e.kind, &e.message))?;
452
453        // Don't resolve symlinks - just create VfsEntry as-is
454        let child_entry = VfsEntry::new(
455            Some(Arc::downgrade(&entry)),
456            component_string.clone(),
457            child_node,
458        );
459
460        // Add to parent's cache
461        entry.add_child(component_string, child_entry.clone());
462
463        Ok(child_entry)
464    }
465
466    // Helper methods
467
468    /// Parse a path into components
469    pub fn parse_path(&self, path: &str) -> Vec<String> {
470        path.split('/')
471            .filter(|s| !s.is_empty() && *s != ".")
472            .map(|s| s.to_string())
473            .collect()
474    }
475
476    /// Get the full path of a mount point
477    fn get_mount_path(&self, mount: &Arc<MountPoint>) -> String {
478        if mount.is_root_mount() {
479            return "/".to_string();
480        }
481
482        let mut components = Vec::new();
483        let mut current = Some(mount.clone());
484
485        while let Some(mount) = current {
486            if !mount.is_root_mount() {
487                components.push(mount.path.clone());
488                current = mount.get_parent();
489            } else {
490                break;
491            }
492        }
493
494        components.reverse();
495        if components.is_empty() {
496            "/".to_string()
497        } else {
498            format!("/{}", components.join("/"))
499        }
500    }
501
502    /// Resolve a single path component within a VFS entry
503    fn resolve_component(&self, entry: VfsEntryRef, component: &str) -> VfsResult<VfsEntryRef> {
504        self.resolve_component_with_depth(entry, component, 0)
505    }
506
507    /// Resolve a single path component with symlink depth tracking
508    fn resolve_component_with_depth(&self, entry: VfsEntryRef, component: &str, symlink_depth: u32) -> VfsResult<VfsEntryRef> {
509        const MAX_SYMLINK_DEPTH: u32 = 32; // Prevent infinite symlink loops
510        
511        if symlink_depth > MAX_SYMLINK_DEPTH {
512            return Err(vfs_error(FileSystemErrorKind::InvalidPath, "Too many symbolic links"));
513        }
514
515        // Handle special cases
516        if component == "." {
517            return Ok(entry);
518        }
519
520        // Check cache first (fast path)
521        let component_string = component.to_string();
522        if let Some(cached_child) = entry.get_child(&component_string) {
523            // Check if cached entry is a symlink that needs resolution
524            if cached_child.node().is_symlink()? {
525                let link_target = cached_child.node().read_link()
526                    .map_err(|e| vfs_error(e.kind, &e.message))?;
527                return self.resolve_symlink_target_with_depth(&entry, &link_target, symlink_depth + 1);
528            }
529            return Ok(cached_child);
530        }
531
532        // Cache miss - perform filesystem lookup
533        let parent_node = entry.node();
534        debug_assert!(parent_node.filesystem().is_some(), "resolve_component: parent_node.filesystem() is None");
535        let filesystem = parent_node.filesystem()
536            .and_then(|w| w.upgrade())
537            .ok_or_else(|| vfs_error(FileSystemErrorKind::NotSupported, "No filesystem reference"))?;
538        // Ask filesystem to lookup the component
539        let child_node = filesystem.lookup(&parent_node, &component_string)
540            .map_err(|e| vfs_error(e.kind, &e.message))?;
541
542        // Check if the resolved node is a symbolic link
543        if child_node.is_symlink()? {
544            // Resolve the symbolic link
545            let link_target = child_node.read_link()
546                .map_err(|e| vfs_error(e.kind, &e.message))?;
547            
548            // Recursively resolve the link target
549            return self.resolve_symlink_target_with_depth(&entry, &link_target, symlink_depth + 1);
550        }
551
552        // Create new VfsEntry for the child
553        let child_entry = VfsEntry::new(
554            Some(Arc::downgrade(&entry)),
555            component_string.clone(),
556            child_node,
557        );
558
559        // Add to parent's cache
560        entry.add_child(component_string, child_entry.clone());
561
562        Ok(child_entry)
563    }
564
565    /// Resolve a symbolic link target
566    fn resolve_symlink_target(&self, base_entry: &VfsEntryRef, target: &str) -> VfsResult<VfsEntryRef> {
567        self.resolve_symlink_target_with_depth(base_entry, target, 0)
568    }
569
570    /// Resolve a symbolic link target with depth tracking
571    fn resolve_symlink_target_with_depth(&self, base_entry: &VfsEntryRef, target: &str, symlink_depth: u32) -> VfsResult<VfsEntryRef> {
572        const MAX_SYMLINK_DEPTH: u32 = 32; // Prevent infinite symlink loops
573        
574        if symlink_depth > MAX_SYMLINK_DEPTH {
575            return Err(vfs_error(FileSystemErrorKind::InvalidPath, "Too many symbolic links"));
576        }
577
578        if target.starts_with('/') {
579            // Absolute path - resolve from root
580            let (resolved_entry, _mount) = self.resolve_path_internal(target, false, &PathResolutionOptions { no_follow: false })?;
581            Ok(resolved_entry)
582        } else {
583            // Relative path - resolve from current directory
584            let components = self.parse_path(target);
585            let mut current_entry = base_entry.clone();
586            
587            for component in components {
588                current_entry = self.resolve_component_with_depth(current_entry, &component, symlink_depth)?;
589            }
590            
591            Ok(current_entry)
592        }
593    }
594
595    // /// Resolve cross-VFS path for bind mounts
596    // fn resolve_cross_vfs_path(
597    //     &self, 
598    //     mount_point: &MountPoint, 
599    //     relative_path: &str
600    // ) -> VfsResult<(VfsEntryRef, Arc<MountPoint>)> {
601    //     if let Some((source_vfs, source_path, _cache_timeout)) = mount_point.get_cross_vfs_info() {
602    //         let source_vfs = source_vfs.upgrade()
603    //             .ok_or_else(|| vfs_error(FileSystemErrorKind::NotFound, "Source VFS no longer available"))?;
604
605    //         let full_source_path = if relative_path.is_empty() || relative_path == "/" {
606    //             source_path.to_string()
607    //         } else {
608    //             format!("{}/{}", source_path.trim_end_matches('/'), relative_path.trim_start_matches('/'))
609    //         };
610
611    //         // Delegate to source VFS for complete resolution (including child mounts)
612    //         source_vfs.resolve_path_cross_vfs(&full_source_path)
613    //     } else {
614    //         Err(vfs_error(FileSystemErrorKind::NotSupported, "Not a cross-VFS mount"))
615    //     }
616    // }
617}