axfs_ng_vfs/
mount.rs

1use alloc::{
2    string::String,
3    sync::{Arc, Weak},
4    vec,
5};
6use core::{
7    iter, mem,
8    sync::atomic::{AtomicU64, Ordering},
9    task::Context,
10};
11
12use axpoll::{IoEvents, Pollable};
13use hashbrown::HashMap;
14use inherit_methods_macro::inherit_methods;
15
16use crate::{
17    DirEntry, DirEntrySink, Filesystem, FilesystemOps, Metadata, MetadataUpdate, Mutex, MutexGuard,
18    NodeFlags, NodePermission, NodeType, OpenOptions, ReferenceKey, TypeMap, VfsError, VfsResult,
19    path::{DOT, DOTDOT, PathBuf},
20};
21
22#[derive(Debug)]
23pub struct Mountpoint {
24    /// Root dir entry in the mountpoint.
25    root: DirEntry,
26    /// Location in the parent mountpoint.
27    location: Option<Location>,
28    /// Children of the mountpoint.
29    children: Mutex<HashMap<ReferenceKey, Weak<Self>>>,
30    /// Device ID
31    device: u64,
32}
33
34impl Mountpoint {
35    pub fn new(fs: &Filesystem, location_in_parent: Option<Location>) -> Arc<Self> {
36        static DEVICE_COUNTER: AtomicU64 = AtomicU64::new(1);
37
38        let root = fs.root_dir();
39        Arc::new(Self {
40            root,
41            location: location_in_parent,
42            children: Mutex::default(),
43            device: DEVICE_COUNTER.fetch_add(1, Ordering::Relaxed),
44        })
45    }
46
47    pub fn new_root(fs: &Filesystem) -> Arc<Self> {
48        Self::new(fs, None)
49    }
50
51    pub fn root_location(self: &Arc<Self>) -> Location {
52        Location::new(self.clone(), self.root.clone())
53    }
54
55    /// Returns the location in the parent mountpoint.
56    pub fn location(&self) -> Option<Location> {
57        self.location.clone()
58    }
59
60    pub fn is_root(&self) -> bool {
61        self.location.is_none()
62    }
63
64    /// Returns the effective mountpoint.
65    ///
66    /// For example, first `mount /dev/sda1 /mnt` and then `mount /dev/sda2
67    /// /mnt`. After the second mount is completed, the content of the first
68    /// mount will be overridden (root mount -> mnt1 -> mnt2). We need to
69    /// return `mnt2` for `mnt1.effective_mountpoint()`.
70    pub(crate) fn effective_mountpoint(self: &Arc<Self>) -> Arc<Mountpoint> {
71        let mut mountpoint = self.clone();
72        while let Some(mount) = mountpoint.root.as_dir().unwrap().mountpoint() {
73            mountpoint = mount;
74        }
75        mountpoint
76    }
77
78    pub fn device(self: &Arc<Self>) -> u64 {
79        self.device
80    }
81}
82
83#[derive(Debug, Clone)]
84pub struct Location {
85    mountpoint: Arc<Mountpoint>,
86    entry: DirEntry,
87}
88
89#[inherit_methods(from = "self.entry")]
90impl Location {
91    pub fn inode(&self) -> u64;
92
93    pub fn filesystem(&self) -> &dyn FilesystemOps;
94
95    pub fn update_metadata(&self, update: MetadataUpdate) -> VfsResult<()>;
96
97    #[allow(clippy::len_without_is_empty)]
98    pub fn len(&self) -> VfsResult<u64>;
99
100    pub fn sync(&self, data_only: bool) -> VfsResult<()>;
101
102    pub fn is_file(&self) -> bool;
103
104    pub fn is_dir(&self) -> bool;
105
106    pub fn node_type(&self) -> NodeType;
107
108    pub fn is_root_of_mount(&self) -> bool;
109
110    pub fn read_link(&self) -> VfsResult<String>;
111
112    pub fn ioctl(&self, cmd: u32, arg: usize) -> VfsResult<usize>;
113
114    pub fn flags(&self) -> NodeFlags;
115
116    pub fn user_data(&self) -> MutexGuard<'_, TypeMap>;
117}
118
119impl Location {
120    pub fn new(mountpoint: Arc<Mountpoint>, entry: DirEntry) -> Self {
121        Self { mountpoint, entry }
122    }
123
124    fn wrap(&self, entry: DirEntry) -> Self {
125        Self::new(self.mountpoint.clone(), entry)
126    }
127
128    pub fn mountpoint(&self) -> &Arc<Mountpoint> {
129        &self.mountpoint
130    }
131
132    pub fn entry(&self) -> &DirEntry {
133        &self.entry
134    }
135
136    pub fn name(&self) -> &str {
137        if self.is_root_of_mount() {
138            self.mountpoint.location.as_ref().map_or("", Location::name)
139        } else {
140            self.entry.name()
141        }
142    }
143
144    pub fn parent(&self) -> Option<Self> {
145        if !self.is_root_of_mount() {
146            return Some(self.wrap(self.entry.parent().unwrap()));
147        }
148        self.mountpoint.location()?.parent()
149    }
150
151    pub fn is_root(&self) -> bool {
152        self.mountpoint.is_root() && self.entry.is_root_of_mount()
153    }
154
155    pub fn check_is_dir(&self) -> VfsResult<()> {
156        self.entry.as_dir().map(|_| ())
157    }
158
159    pub fn check_is_file(&self) -> VfsResult<()> {
160        self.entry.as_file().map(|_| ())
161    }
162
163    pub fn metadata(&self) -> VfsResult<Metadata> {
164        let mut metadata = self.entry.metadata()?;
165        metadata.device = self.mountpoint.device();
166        Ok(metadata)
167    }
168
169    pub fn absolute_path(&self) -> VfsResult<PathBuf> {
170        let mut components = vec![];
171        let mut cur = self.clone();
172        loop {
173            cur.entry.collect_absolute_path(&mut components);
174            cur = match cur.mountpoint.location() {
175                Some(loc) => loc,
176                None => break,
177            }
178        }
179        Ok(iter::once("/")
180            .chain(components.iter().map(String::as_str).rev())
181            .collect())
182    }
183
184    pub fn ptr_eq(&self, other: &Self) -> bool {
185        Arc::ptr_eq(&self.mountpoint, &other.mountpoint) && self.entry.ptr_eq(&other.entry)
186    }
187
188    pub fn is_mountpoint(&self) -> bool {
189        self.entry.as_dir().is_ok_and(|it| it.is_mountpoint())
190    }
191
192    /// See [`Mountpoint::effective_mountpoint`].
193    fn resolve_mountpoint(self) -> Self {
194        let Some(mountpoint) = self.entry.as_dir().ok().and_then(|it| it.mountpoint()) else {
195            return self;
196        };
197        let mountpoint = mountpoint.effective_mountpoint();
198        let entry = mountpoint.root.clone();
199        Self::new(mountpoint, entry)
200    }
201
202    pub fn lookup_no_follow(&self, name: &str) -> VfsResult<Self> {
203        Ok(match name {
204            DOT => self.clone(),
205            DOTDOT => self.parent().unwrap_or_else(|| self.clone()),
206            _ => {
207                let loc = Self::new(self.mountpoint.clone(), self.entry.as_dir()?.lookup(name)?);
208                loc.resolve_mountpoint()
209            }
210        })
211    }
212
213    pub fn create(
214        &self,
215        name: &str,
216        node_type: NodeType,
217        permission: NodePermission,
218    ) -> VfsResult<Self> {
219        self.entry
220            .as_dir()?
221            .create(name, node_type, permission)
222            .map(|entry| self.wrap(entry))
223    }
224
225    pub fn link(&self, name: &str, node: &Self) -> VfsResult<Self> {
226        if !Arc::ptr_eq(&self.mountpoint, &node.mountpoint) {
227            return Err(VfsError::CrossesDevices);
228        }
229        self.entry
230            .as_dir()?
231            .link(name, &node.entry)
232            .map(|entry| self.wrap(entry))
233    }
234
235    pub fn rename(&self, src_name: &str, dst_dir: &Self, dst_name: &str) -> VfsResult<()> {
236        if !Arc::ptr_eq(&self.mountpoint, &dst_dir.mountpoint) {
237            return Err(VfsError::CrossesDevices);
238        }
239        if !self.ptr_eq(dst_dir) && self.entry.is_ancestor_of(&dst_dir.entry)? {
240            return Err(VfsError::InvalidInput);
241        }
242        self.entry
243            .as_dir()?
244            .rename(src_name, dst_dir.entry.as_dir()?, dst_name)
245    }
246
247    pub fn unlink(&self, name: &str, is_dir: bool) -> VfsResult<()> {
248        self.entry.as_dir()?.unlink(name, is_dir)
249    }
250
251    pub fn open_file(&self, name: &str, options: &OpenOptions) -> VfsResult<Location> {
252        self.entry
253            .as_dir()?
254            .open_file(name, options)
255            .map(|entry| self.wrap(entry).resolve_mountpoint())
256    }
257
258    pub fn read_dir(&self, offset: u64, sink: &mut dyn DirEntrySink) -> VfsResult<usize> {
259        self.entry.as_dir()?.read_dir(offset, sink)
260    }
261
262    pub fn mount(&self, fs: &Filesystem) -> VfsResult<Arc<Mountpoint>> {
263        let mut mountpoint = self.entry.as_dir()?.mountpoint.lock();
264        if mountpoint.is_some() {
265            return Err(VfsError::ResourceBusy);
266        }
267        let result = Mountpoint::new(fs, Some(self.clone()));
268        *mountpoint = Some(result.clone());
269        self.mountpoint
270            .children
271            .lock()
272            .insert(self.entry.key(), Arc::downgrade(&result));
273        Ok(result)
274    }
275
276    pub fn unmount(&self) -> VfsResult<()> {
277        if !self.is_root_of_mount() {
278            return Err(VfsError::InvalidInput);
279        }
280        if !self.mountpoint.children.lock().is_empty() {
281            return Err(VfsError::ResourceBusy);
282        }
283        assert!(self.entry.ptr_eq(&self.mountpoint.root));
284        self.entry.as_dir()?.forget();
285        if let Some(parent_loc) = &self.mountpoint.location {
286            *parent_loc.entry.as_dir()?.mountpoint.lock() = None;
287        }
288        Ok(())
289    }
290
291    pub fn unmount_all(&self) -> VfsResult<()> {
292        if !self.is_root_of_mount() {
293            return Err(VfsError::InvalidInput);
294        }
295        let children = mem::take(&mut *self.mountpoint.children.lock());
296        for (_, child) in children {
297            if let Some(child) = child.upgrade() {
298                child.root_location().unmount_all()?;
299            }
300        }
301        self.unmount()
302    }
303}
304
305#[inherit_methods(from = "self.entry")]
306impl Pollable for Location {
307    fn poll(&self) -> IoEvents;
308
309    fn register(&self, context: &mut Context<'_>, events: IoEvents);
310}