1use crate::security;
6use crate::task::{
7 CurrentTask, EventHandler, Kernel, MountsWriteToken, Task, WaitCanceler, Waiter,
8};
9use crate::time::utc;
10use crate::vfs::fs_registry::FsRegistry;
11use crate::vfs::pseudo::dynamic_file::{DynamicFile, DynamicFileBuf, DynamicFileSource};
12use crate::vfs::pseudo::simple_file::SimpleFileNode;
13use crate::vfs::socket::{SocketAddress, SocketHandle, UnixSocket};
14use crate::vfs::{
15 CheckAccessReason, DirEntry, DirEntryHandle, FileHandle, FileObject, FileOps, FileSystemHandle,
16 FileSystemOptions, FileWriteGuardMode, FsContext, FsNode, FsNodeHandle, FsNodeOps, FsStr,
17 FsString, PathBuilder, RenameFlags, SymlinkTarget, UnlinkKind, fileops_impl_dataless,
18 fileops_impl_delegate_read_write_and_seek, fileops_impl_nonseekable, fileops_impl_noop_sync,
19 fs_node_impl_not_dir,
20};
21use fuchsia_rcu::{RcuBox, RcuReadScope};
22use fuchsia_rcu_collections::rcu_raw_hash_map::RcuRawHashMap;
23use ref_cast::RefCast;
24use starnix_logging::log_warn;
25use starnix_rcu::RcuHashMap;
26use starnix_sync::{
27 BeforeFsNodeAppend, FileOpsCore, LockDepMutex, LockEqualOrBefore, Locked, NamespaceFlagsLock,
28 Unlocked,
29};
30use starnix_uapi::arc_key::{ArcKey, PtrKey, WeakKey};
31use starnix_uapi::auth::Credentials;
32use starnix_uapi::device_id::DeviceId;
33use starnix_uapi::errors::Errno;
34use starnix_uapi::file_mode::{AccessCheck, FileMode};
35use starnix_uapi::inotify_mask::InotifyMask;
36use starnix_uapi::mount_flags::{
37 AtomicMountpointFlags, FileSystemFlags, MountFlags, MountpointFlags,
38};
39use starnix_uapi::open_flags::OpenFlags;
40use starnix_uapi::unmount_flags::UnmountFlags;
41use starnix_uapi::vfs::{FdEvents, ResolveFlags};
42use starnix_uapi::{NAME_MAX, errno, error};
43use std::borrow::Borrow;
44use std::collections::HashSet;
45use std::fmt;
46use std::hash::{Hash, Hasher};
47use std::ops::{Deref, DerefMut};
48use std::sync::atomic::Ordering;
49use std::sync::{Arc, Weak};
50
51#[derive(Debug)]
55pub struct Namespace {
56 root_mount: MountHandle,
57
58 pub id: u64,
60}
61
62impl Namespace {
63 pub fn new(fs: FileSystemHandle) -> Arc<Namespace> {
64 Self::new_with_flags(fs, MountpointFlags::empty())
65 }
66
67 pub fn new_with_flags(fs: FileSystemHandle, flags: MountpointFlags) -> Arc<Namespace> {
68 let kernel = fs.kernel.upgrade().expect("can't create namespace without a kernel");
69 let mounts_guard = kernel.mounts_lock.lock();
70
71 let root_mount = Mount::new(&mounts_guard, WhatToMount::Fs(fs), flags);
72 Arc::new(Self { root_mount, id: kernel.get_next_namespace_id() })
73 }
74
75 pub fn root(&self) -> NamespaceNode {
76 self.root_mount.root()
77 }
78
79 pub fn kernel(&self) -> Arc<Kernel> {
80 self.root_mount.kernel()
81 }
82
83 pub fn clone_namespace(&self, mounts_guard: &MountsWriteToken) -> Arc<Namespace> {
84 Arc::new(Self {
85 root_mount: self.root_mount.clone_mount_recursive(mounts_guard),
86 id: self.kernel().get_next_namespace_id(),
87 })
88 }
89
90 pub fn translate_node(
93 mut node: NamespaceNode,
94 new_ns: &Namespace,
95 _mounts_guard: &MountsWriteToken,
96 ) -> Option<NamespaceNode> {
97 let mut mountpoints = vec![];
99 let mut mount = node.mount;
100 while let Some(mountpoint) = mount.as_ref().and_then(|m| m.mountpoint()) {
101 mountpoints.push(mountpoint.entry);
102 mount = mountpoint.mount;
103 }
104
105 let scope = RcuReadScope::new();
107 let mut mount = &new_ns.root_mount;
108 for mountpoint in mountpoints.iter().rev() {
109 let next_mount =
110 &mount.relations.get_submount(&scope, ArcKey::ref_cast(mountpoint))?.mount;
111 mount = next_mount;
112 }
113 node.mount = Some(Arc::clone(mount)).into();
114 Some(node)
115 }
116}
117
118impl FsNodeOps for Arc<Namespace> {
119 fs_node_impl_not_dir!();
120
121 fn create_file_ops(
122 &self,
123 _locked: &mut Locked<FileOpsCore>,
124 _node: &FsNode,
125 _current_task: &CurrentTask,
126 _flags: OpenFlags,
127 ) -> Result<Box<dyn FileOps>, Errno> {
128 Ok(Box::new(MountNamespaceFile(self.clone())))
129 }
130}
131
132pub struct MountNamespaceFile(pub Arc<Namespace>);
133
134impl FileOps for MountNamespaceFile {
135 fileops_impl_nonseekable!();
136 fileops_impl_dataless!();
137 fileops_impl_noop_sync!();
138}
139
140type MountClientMarker = Arc<()>;
145
146pub struct Mount {
155 root: DirEntryHandle,
156 fs: FileSystemHandle,
157
158 flags: AtomicMountpointFlags,
160
161 flags_lock: LockDepMutex<(), NamespaceFlagsLock>,
163
164 id: u64,
166
167 active_client_counter: MountClientMarker,
169
170 relations: MountRelations,
177 }
184type MountHandle = Arc<Mount>;
185
186#[derive(Clone, Debug)]
188pub struct MountInfo {
189 handle: Option<MountHandle>,
190}
191
192impl MountInfo {
193 pub fn detached() -> Self {
196 None.into()
197 }
198
199 pub fn flags(&self) -> MountFlags {
201 if let Some(handle) = &self.handle {
202 handle.flags()
203 } else {
204 MountFlags::NOATIME
206 }
207 }
208
209 pub fn check_readonly_filesystem(&self) -> Result<(), Errno> {
211 if self.flags().contains(MountFlags::RDONLY) {
212 return error!(EROFS);
213 }
214 Ok(())
215 }
216
217 pub fn check_noexec_filesystem(&self) -> Result<(), Errno> {
219 if self.flags().contains(MountFlags::NOEXEC) {
220 return error!(EACCES);
221 }
222 Ok(())
223 }
224}
225
226impl Deref for MountInfo {
227 type Target = Option<MountHandle>;
228
229 fn deref(&self) -> &Self::Target {
230 &self.handle
231 }
232}
233
234impl DerefMut for MountInfo {
235 fn deref_mut(&mut self) -> &mut Self::Target {
236 &mut self.handle
237 }
238}
239
240impl std::cmp::PartialEq for MountInfo {
241 fn eq(&self, other: &Self) -> bool {
242 self.handle.as_ref().map(Arc::as_ptr) == other.handle.as_ref().map(Arc::as_ptr)
243 }
244}
245
246impl std::cmp::Eq for MountInfo {}
247
248impl Into<MountInfo> for Option<MountHandle> {
249 fn into(self) -> MountInfo {
250 MountInfo { handle: self }
251 }
252}
253
254#[derive(Default)]
255struct MountRelations {
256 mountpoint: RcuBox<Option<(Weak<Mount>, DirEntryHandle)>>,
258 submounts: RcuRawHashMap<ArcKey<DirEntry>, Arc<Submount>>,
260 peer_group: RcuBox<Option<(Arc<PeerGroup>, PtrKey<Mount>)>>,
262 upstream: RcuBox<Option<(Weak<PeerGroup>, PtrKey<Mount>)>>,
264}
265
266impl MountRelations {
267 fn get_submount<'a>(
268 &'a self,
269 scope: &'a starnix_rcu::RcuReadScope,
270 key: &ArcKey<DirEntry>,
271 ) -> Option<&'a Arc<Submount>> {
272 self.submounts.get(scope, key)
273 }
274
275 fn insert_submount(
276 &self,
277 _guard: &MountsWriteToken,
278 key: ArcKey<DirEntry>,
279 value: Arc<Submount>,
280 ) -> Option<Arc<Submount>> {
281 let scope = starnix_rcu::RcuReadScope::new();
282 let result = unsafe { self.submounts.insert(&scope, key, value) };
284 match result {
285 fuchsia_rcu_collections::rcu_raw_hash_map::InsertionResult::Inserted(_) => None,
286 fuchsia_rcu_collections::rcu_raw_hash_map::InsertionResult::Updated(old) => Some(old),
287 }
288 }
289
290 fn remove_submount(
291 &self,
292 _guard: &MountsWriteToken,
293 key: &ArcKey<DirEntry>,
294 ) -> Result<(), Errno> {
295 let submount = unsafe { self.submounts.remove(key) };
297 if submount.is_some() { Ok(()) } else { error!(EINVAL) }
298 }
299
300 fn iter_submounts<'a>(
301 &'a self,
302 scope: &'a starnix_rcu::RcuReadScope,
303 ) -> impl Iterator<Item = (&'a ArcKey<DirEntry>, &'a Arc<Submount>)> {
304 let mut cursor = self.submounts.cursor(scope);
305 std::iter::from_fn(move || {
306 let current = cursor.current();
307 if current.is_some() {
308 cursor.advance();
309 }
310 current
311 })
312 }
313
314 fn submounts_len(&self) -> usize {
315 self.submounts.len()
316 }
317
318 fn set_mountpoint(
319 &self,
320 _guard: &MountsWriteToken,
321 mountpoint: Option<(Weak<Mount>, DirEntryHandle)>,
322 ) {
323 self.mountpoint.update(mountpoint);
324 }
325
326 fn mountpoint<'a>(
327 &'a self,
328 scope: &'a starnix_rcu::RcuReadScope,
329 ) -> Option<&'a (Weak<Mount>, DirEntryHandle)> {
330 self.mountpoint.as_ref(scope).as_ref()
331 }
332
333 fn take_peer_group(
334 &self,
335 _guard: &MountsWriteToken,
336 ) -> Option<(Arc<PeerGroup>, PtrKey<Mount>)> {
337 let peer_group = self.peer_group.cloned();
338 self.peer_group.update(None);
339 peer_group
340 }
341
342 fn take_upstream(&self, _guard: &MountsWriteToken) -> Option<(Weak<PeerGroup>, PtrKey<Mount>)> {
343 let upstream = self.upstream.cloned();
344 self.upstream.update(None);
345 upstream
346 }
347}
348
349#[derive(Default)]
353struct PeerGroup {
354 id: u64,
355 mounts: RcuRawHashMap<WeakKey<Mount>, ()>,
356 downstream: RcuRawHashMap<WeakKey<Mount>, ()>,
357}
358
359pub enum WhatToMount {
360 Fs(FileSystemHandle),
361 Bind(NamespaceNode),
362}
363
364enum WhatSubmount {
365 New(WhatToMount, MountpointFlags),
366 Existing(MountHandle),
367}
368
369impl Mount {
370 pub fn new(
371 mounts_guard: &MountsWriteToken,
372 what: WhatToMount,
373 mut flags: MountpointFlags,
374 ) -> MountHandle {
375 match what {
376 WhatToMount::Fs(fs) => {
377 flags.default_atime_from(MountpointFlags::RELATIME);
379 Self::new_with_root(fs.root().clone(), flags)
380 }
381 WhatToMount::Bind(node) => {
382 let mount = node.mount.as_ref().expect("can't bind mount from an anonymous node");
383 mount.clone_mount(mounts_guard, &node.entry, flags.into())
384 }
385 }
386 }
387
388 fn new_with_root(root: DirEntryHandle, flags: MountpointFlags) -> MountHandle {
389 let fs = root.node.fs();
390 let kernel = fs.kernel.upgrade().expect("can't create mount without kernel");
391 Arc::new(Self {
392 id: kernel.get_next_mount_id(),
393 flags: (flags & MountpointFlags::STORED_ON_MOUNT).into(),
394 flags_lock: Default::default(),
395 root,
396 active_client_counter: Default::default(),
397 fs,
398 relations: Default::default(),
399 })
400 }
401
402 pub fn root(self: &MountHandle) -> NamespaceNode {
404 NamespaceNode::new(Arc::clone(self), Arc::clone(&self.root))
405 }
406
407 fn kernel(&self) -> Arc<Kernel> {
408 self.fs.kernel.upgrade().expect("No Kernel")
409 }
410
411 fn create_submount(
413 self: &MountHandle,
414 mounts_guard: &MountsWriteToken,
415 dir: &DirEntryHandle,
416 what: WhatSubmount,
417 ) {
418 let peers = self.peer_group().map(|g| g.copy_propagation_targets()).unwrap_or_default();
421
422 let mount = match what {
427 WhatSubmount::Existing(mount) => mount,
428 WhatSubmount::New(what, flags) => Mount::new(mounts_guard, what, flags),
429 };
430
431 if self.is_shared() {
432 mount.make_shared(mounts_guard);
433 }
434
435 for peer in peers {
436 if Arc::ptr_eq(self, &peer) {
437 continue;
438 }
439 let clone = mount.clone_mount_recursive(mounts_guard);
440 peer.add_submount_internal(mounts_guard, dir, clone);
441 }
442
443 self.add_submount_internal(mounts_guard, dir, mount)
444 }
445
446 fn remove_submount(
447 self: &MountHandle,
448 mounts_guard: &MountsWriteToken,
449 mount_hash_key: &ArcKey<DirEntry>,
450 ) -> Result<(), Errno> {
451 let peers = self.peer_group().map(|g| g.copy_propagation_targets()).unwrap_or_default();
453
454 for peer in peers {
455 if Arc::ptr_eq(self, &peer) {
456 continue;
457 }
458 let scope = RcuReadScope::new();
462 if let Some(submount) = peer.relations.submounts.get(&scope, mount_hash_key) {
463 if submount.mount.relations.submounts_len() != 0 {
464 continue;
465 }
466 }
467 let _ = peer.remove_submount_internal(mounts_guard, mount_hash_key);
468 }
469
470 self.remove_submount_internal(mounts_guard, mount_hash_key)
471 }
472
473 pub fn move_mount(
474 source_mount: &MountHandle,
475 target_mount: &MountHandle,
476 target_dir: &DirEntryHandle,
477 ) -> Result<(), Errno> {
478 let kernel = target_mount.kernel();
479 let mounts_guard = kernel.mounts_lock.lock();
480
481 let source_mountpoint = source_mount.mountpoint().ok_or_else(|| errno!(EIO))?;
482 let source_parent =
483 source_mountpoint.mount.as_ref().expect("a mountpoint must be part of a mount");
484
485 {
487 if source_parent.peer_group().is_some() {
488 return error!(EINVAL);
492 }
493 source_parent
494 .remove_submount_internal(&mounts_guard, source_mountpoint.mount_hash_key())?;
495 source_mount.relations.set_mountpoint(&mounts_guard, None);
496 }
497
498 target_mount.create_submount(
499 &mounts_guard,
500 target_dir,
501 WhatSubmount::Existing(Arc::clone(source_mount)),
502 );
503 Ok(())
504 }
505
506 fn clone_mount(
509 self: &MountHandle,
510 mounts_guard: &MountsWriteToken,
511 new_root: &DirEntryHandle,
512 flags: MountFlags,
513 ) -> MountHandle {
514 assert!(new_root.is_descendant_of(&self.root));
515 let clone = Self::new_with_root(Arc::clone(new_root), self.mount_flags());
518
519 if flags.contains(MountFlags::REC) {
520 for (dir, submount) in self.relations.iter_submounts(&RcuReadScope::new()) {
521 let submount = submount.mount.clone_mount_recursive(mounts_guard);
522 clone.add_submount_internal(mounts_guard, dir, submount);
523 }
524 }
525
526 let peer_group = self.peer_group();
528 if let Some(peer_group) = peer_group {
529 clone.set_peer_group(mounts_guard, peer_group);
530 }
531
532 clone
533 }
534
535 fn clone_mount_recursive(self: &MountHandle, mounts_guard: &MountsWriteToken) -> MountHandle {
538 self.clone_mount(mounts_guard, &self.root, MountFlags::REC)
539 }
540
541 pub fn change_propagation(
542 self: &MountHandle,
543 mounts_guard: &MountsWriteToken,
544 flag: MountFlags,
545 recursive: bool,
546 ) {
547 match flag {
548 MountFlags::SHARED => self.make_shared(mounts_guard),
549 MountFlags::PRIVATE => self.make_private(mounts_guard),
550 MountFlags::DOWNSTREAM => self.make_downstream(mounts_guard),
551 _ => {
552 log_warn!("mount propagation {:?}", flag);
553 }
554 }
555
556 if recursive {
557 for (_, submount) in self.relations.iter_submounts(&starnix_rcu::RcuReadScope::new()) {
558 submount.mount.change_propagation(mounts_guard, flag, recursive);
559 }
560 }
561 }
562
563 fn flags(&self) -> MountFlags {
566 MountFlags::from(self.mount_flags()) | self.fs_flags().into()
567 }
568
569 fn mount_flags(&self) -> MountpointFlags {
571 self.flags.load(Ordering::Relaxed)
572 }
573
574 fn fs_flags(&self) -> FileSystemFlags {
576 self.fs.options.flags.load(Ordering::Relaxed)
577 }
578
579 pub fn update_flags(self: &MountHandle, mut flags: MountpointFlags) {
582 let _lock = self.flags_lock.lock();
583 flags.default_atime_from(self.flags.load(Ordering::Relaxed));
588 flags &= MountpointFlags::STORED_ON_MOUNT;
589 self.flags.store(flags, Ordering::Relaxed);
590 }
591
592 fn active_clients(&self) -> usize {
596 Arc::strong_count(&self.active_client_counter) - 1
598 }
599
600 pub fn unmount(
601 &self,
602 mounts_guard: &MountsWriteToken,
603 flags: UnmountFlags,
604 ) -> Result<(), Errno> {
605 if !flags.contains(UnmountFlags::DETACH) {
606 if self.active_clients() > 0 || self.relations.submounts_len() != 0 {
607 return error!(EBUSY);
608 }
609 }
610
611 let mountpoint = self.mountpoint().ok_or_else(|| errno!(EINVAL))?;
612 let parent_mount = mountpoint.mount.as_ref().expect("a mountpoint must be part of a mount");
613 parent_mount.remove_submount(mounts_guard, mountpoint.mount_hash_key())
614 }
615
616 pub fn security_state(&self) -> &security::FileSystemState {
618 &self.fs.security_state
619 }
620
621 pub fn fs_name(&self) -> &'static FsStr {
623 self.fs.name()
624 }
625
626 pub fn reconfigure_fs(
628 &self,
629 current_task: &CurrentTask,
630 flags: FileSystemFlags,
631 ) -> Result<(), Errno> {
632 self.fs.update_flags(current_task, flags)
633 }
634
635 pub fn has_submount(&self, dir_entry: &DirEntryHandle) -> bool {
637 let scope = RcuReadScope::new();
638 self.relations.get_submount(&scope, ArcKey::ref_cast(dir_entry)).is_some()
639 }
640
641 pub fn mountpoint(&self) -> Option<NamespaceNode> {
643 let scope = RcuReadScope::new();
644 let (mount, entry) = self.relations.mountpoint(&scope)?;
645 Some(NamespaceNode::new(mount.upgrade()?, entry.clone()))
646 }
647
648 pub fn add_submount_internal(
650 self: &MountHandle,
651 guard: &MountsWriteToken,
652 dir: &DirEntryHandle,
653 mount: MountHandle,
654 ) {
655 if !dir.is_descendant_of(&self.root) {
656 return;
657 }
658
659 let submount = mount.kernel().mounts.register_mount(dir, mount.clone());
660
661 let old_mountpoint = {
662 let scope = RcuReadScope::new();
663 mount.relations.mountpoint(&scope).map(|x| x.clone())
664 };
665 mount.relations.set_mountpoint(guard, Some((Arc::downgrade(self), Arc::clone(dir))));
666 assert!(old_mountpoint.is_none(), "add_submount can only take a newly created mount");
667
668 let old_mount = self.relations.insert_submount(
669 guard,
670 ArcKey::ref_cast(dir).clone(),
671 Arc::new(submount),
672 );
673
674 if let Some(old_mount) = old_mount {
675 old_mount
676 .mount
677 .relations
678 .set_mountpoint(guard, Some((Arc::downgrade(&mount), Arc::clone(dir))));
679 let new_old_submount =
680 mount.kernel().mounts.register_mount(&mount.root, old_mount.mount.clone());
681 mount.relations.insert_submount(
682 guard,
683 ArcKey(mount.root.clone()),
684 Arc::new(new_old_submount),
685 );
686 }
687 }
688
689 pub fn remove_submount_internal(
690 self: &MountHandle,
691 guard: &MountsWriteToken,
692 mount_hash_key: &ArcKey<DirEntry>,
693 ) -> Result<(), Errno> {
694 self.relations.remove_submount(guard, mount_hash_key)
695 }
696
697 fn peer_group(&self) -> Option<Arc<PeerGroup>> {
699 let scope = RcuReadScope::new();
700 self.relations.peer_group.as_ref(&scope).as_ref().map(|(g, _)| g.clone())
701 }
702
703 fn unregister_from_peer_group_and_upstream(
706 guard: &MountsWriteToken,
707 peer_group: Option<(Arc<PeerGroup>, PtrKey<Mount>)>,
708 upstream: Option<(Weak<PeerGroup>, PtrKey<Mount>)>,
709 ) {
710 let upstream_group = match upstream {
711 Some((weak_group, mount)) => {
712 if let Some(group) = weak_group.upgrade() {
713 group.remove_downstream(guard, mount);
714 Some(group)
715 } else {
716 None
717 }
718 }
719 None => None,
720 };
721
722 if let Some((group, mount)) = peer_group {
723 group.remove(guard, mount);
724
725 if let Some(upstream_group) = upstream_group {
726 let next_mount = {
727 let scope = RcuReadScope::new();
728 group.mounts.keys(&scope).next().map(|w| w.0.upgrade().unwrap())
729 };
730 if let Some(next_mount) = next_mount {
731 next_mount.set_upstream(guard, upstream_group);
732 }
733 }
734 }
735 }
736
737 fn take_from_peer_group(&self, guard: &MountsWriteToken) -> Option<Arc<PeerGroup>> {
739 let peer_group = self.relations.take_peer_group(guard);
740 if peer_group.is_none() {
741 return None;
742 }
743 let upstream = self.relations.take_upstream(guard);
744 let return_group = peer_group.as_ref().map(|(g, _)| g.clone());
745 Mount::unregister_from_peer_group_and_upstream(guard, peer_group, upstream);
746 return_group
747 }
748
749 fn upstream(&self) -> Option<Arc<PeerGroup>> {
750 let scope = RcuReadScope::new();
751 let (group, _) = self.relations.upstream.as_ref(&scope).as_ref()?;
752 group.upgrade()
753 }
754
755 fn remove_from_upstream(&self, guard: &MountsWriteToken) {
756 let upstream = self.relations.take_upstream(guard);
757 if let Some((weak_group, mount)) = upstream {
758 if let Some(group) = weak_group.upgrade() {
759 group.remove_downstream(guard, mount);
760 }
761 }
762 }
763
764 fn set_peer_group(self: &Arc<Mount>, guard: &MountsWriteToken, group: Arc<PeerGroup>) {
766 self.take_from_peer_group(guard);
767 group.add(guard, self);
768 self.relations.peer_group.update(Some((group, Arc::as_ptr(self).into())));
769 }
770
771 fn set_upstream(self: &Arc<Mount>, guard: &MountsWriteToken, group: Arc<PeerGroup>) {
772 self.remove_from_upstream(guard);
773 group.add_downstream(guard, self);
774 self.relations.upstream.update(Some((Arc::downgrade(&group), Arc::as_ptr(self).into())));
775 }
776
777 pub fn is_shared(&self) -> bool {
779 self.peer_group().is_some()
780 }
781
782 fn make_shared(self: &Arc<Mount>, guard: &MountsWriteToken) {
784 if self.is_shared() {
785 return;
786 }
787 let kernel = self.kernel();
788 self.set_peer_group(guard, PeerGroup::new(kernel.get_next_peer_group_id()))
789 }
790
791 fn make_private(&self, guard: &MountsWriteToken) {
793 let peer_group = self.relations.take_peer_group(guard);
794 let upstream = self.relations.take_upstream(guard);
795 Mount::unregister_from_peer_group_and_upstream(guard, peer_group, upstream);
796 }
797
798 fn make_downstream(self: &Arc<Mount>, guard: &MountsWriteToken) {
801 if let Some(peer_group) = self.take_from_peer_group(guard) {
802 self.set_upstream(guard, peer_group);
803 }
804 }
805}
806
807impl PeerGroup {
808 fn new(id: u64) -> Arc<Self> {
809 Arc::new(Self {
810 id,
811 mounts: RcuRawHashMap::default(),
812 downstream: RcuRawHashMap::default(),
813 })
814 }
815
816 fn add(&self, _guard: &MountsWriteToken, mount: &Arc<Mount>) {
817 unsafe { self.mounts.insert(&starnix_rcu::RcuReadScope::new(), WeakKey::from(mount), ()) };
819 }
820
821 fn remove(&self, _guard: &MountsWriteToken, mount: PtrKey<Mount>) {
822 unsafe { self.mounts.remove(&mount) };
824 }
825
826 fn add_downstream(&self, _guard: &MountsWriteToken, mount: &Arc<Mount>) {
827 unsafe {
829 self.downstream.insert(&starnix_rcu::RcuReadScope::new(), WeakKey::from(mount), ())
830 };
831 }
832
833 fn remove_downstream(&self, _guard: &MountsWriteToken, mount: PtrKey<Mount>) {
834 unsafe { self.downstream.remove(&mount) };
836 }
837
838 fn copy_propagation_targets(&self) -> Vec<MountHandle> {
839 let mut buf = vec![];
840 self.collect_propagation_targets(&mut buf);
841 buf
842 }
843
844 fn collect_propagation_targets(&self, buf: &mut Vec<MountHandle>) {
845 let downstream_mounts: Vec<_> = {
846 let scope = RcuReadScope::new();
847 buf.extend(self.mounts.keys(&scope).filter_map(|m| m.0.upgrade()));
848 self.downstream.keys(&scope).filter_map(|m| m.0.upgrade()).collect()
849 };
850 for mount in downstream_mounts {
851 let peer_group = mount.peer_group();
852 match peer_group {
853 Some(group) => group.collect_propagation_targets(buf),
854 None => buf.push(mount),
855 }
856 }
857 }
858}
859
860impl Kernel {
861 pub fn get_next_mount_id(&self) -> u64 {
862 self.next_mount_id.next()
863 }
864
865 pub fn get_next_peer_group_id(&self) -> u64 {
866 self.next_peer_group_id.next()
867 }
868
869 pub fn get_next_namespace_id(&self) -> u64 {
870 self.next_namespace_id.next()
871 }
872}
873
874impl CurrentTask {
875 pub fn create_filesystem(
876 &self,
877 locked: &mut Locked<Unlocked>,
878 fs_type: &FsStr,
879 options: FileSystemOptions,
880 ) -> Result<FileSystemHandle, Errno> {
881 self.kernel()
888 .expando
889 .get::<FsRegistry>()
890 .create(locked, self, fs_type, options)
891 .ok_or_else(|| errno!(ENODEV, fs_type))?
892 }
893}
894
895struct ProcMountsFileSource(Weak<Task>);
896
897impl DynamicFileSource for ProcMountsFileSource {
898 fn generate(
899 &self,
900 _current_task: &CurrentTask,
901 sink: &mut DynamicFileBuf,
902 ) -> Result<(), Errno> {
903 let task = Task::from_weak(&self.0)?;
908 let task_fs = task.running_state()?.fs.read();
909 let root = task_fs.root();
910 let ns = task_fs.namespace();
911 for_each_mount(&ns.root_mount, &mut |mount| {
912 let mountpoint = mount.mountpoint().unwrap_or_else(|| mount.root());
913 if !mountpoint.is_descendant_of(&root) {
914 return Ok(());
915 }
916 write!(
917 sink,
918 "{} {} {} {}{}",
919 mount.fs.options.source_for_display(),
920 mountpoint.path(&task_fs),
921 mount.fs.name(),
922 mount.flags(),
925 security::sb_show_options(&task.kernel(), &mount.fs)?,
926 )?;
927 writeln!(sink, " 0 0")?;
928 Ok(())
929 })?;
930 Ok(())
931 }
932}
933
934pub struct ProcMountsFile {
935 dynamic_file: DynamicFile<ProcMountsFileSource>,
936}
937
938impl ProcMountsFile {
939 pub fn new_node(task: Weak<Task>) -> impl FsNodeOps {
940 SimpleFileNode::new(move |_, _| {
941 Ok(Self { dynamic_file: DynamicFile::new(ProcMountsFileSource(task.clone())) })
942 })
943 }
944}
945
946impl FileOps for ProcMountsFile {
947 fileops_impl_delegate_read_write_and_seek!(self, self.dynamic_file);
948 fileops_impl_noop_sync!();
949
950 fn wait_async(
951 &self,
952 _locked: &mut Locked<FileOpsCore>,
953 _file: &FileObject,
954 _current_task: &CurrentTask,
955 waiter: &Waiter,
956 _events: FdEvents,
957 _handler: EventHandler,
958 ) -> Option<WaitCanceler> {
959 Some(waiter.fake_wait())
962 }
963
964 fn query_events(
965 &self,
966 _locked: &mut Locked<FileOpsCore>,
967 _file: &FileObject,
968 _current_task: &CurrentTask,
969 ) -> Result<FdEvents, Errno> {
970 Ok(FdEvents::empty())
971 }
972}
973
974#[derive(Clone)]
975pub struct ProcMountinfoFile(Weak<Task>);
976impl ProcMountinfoFile {
977 pub fn new_node(task: Weak<Task>) -> impl FsNodeOps {
978 DynamicFile::new_node(Self(task))
979 }
980}
981impl DynamicFileSource for ProcMountinfoFile {
982 fn generate(
983 &self,
984 _current_task: &CurrentTask,
985 sink: &mut DynamicFileBuf,
986 ) -> Result<(), Errno> {
987 fn path_from_fs_root(dir: &DirEntryHandle) -> FsString {
989 let mut path = PathBuilder::new();
990 if dir.is_dead() {
991 path.prepend_element("/deleted".into());
993 }
994 let scope = RcuReadScope::new();
995 let mut current = dir.deref();
996 while let Some(parent) = current.parent_ref(&scope) {
997 path.prepend_element(current.local_name(&scope));
998 current = parent;
999 }
1000 path.build_absolute()
1001 }
1002
1003 let task = Task::from_weak(&self.0)?;
1008 let task_fs = task.running_state()?.fs.read();
1009 let root = task_fs.root();
1010 let ns = task_fs.namespace();
1011 for_each_mount(&ns.root_mount, &mut |mount| {
1012 let mountpoint = mount.mountpoint().unwrap_or_else(|| mount.root());
1013 if !mountpoint.is_descendant_of(&root) {
1014 return Ok(());
1015 }
1016 let parent = mountpoint.mount.as_ref().unwrap();
1018 write!(
1019 sink,
1020 "{} {} {} {} {} {}",
1021 mount.id,
1022 parent.id,
1023 mount.root.node.fs().dev_id,
1024 path_from_fs_root(&mount.root),
1025 mountpoint.path(&task_fs),
1026 mount.mount_flags(),
1027 )?;
1028 if let Some(peer_group) = mount.peer_group() {
1029 write!(sink, " shared:{}", peer_group.id)?;
1030 }
1031 if let Some(upstream) = mount.upstream() {
1032 write!(sink, " master:{}", upstream.id)?;
1033 }
1034 writeln!(
1035 sink,
1036 " - {} {} {}{}",
1037 mount.fs.name(),
1038 mount.fs.options.source_for_display(),
1039 mount.fs_flags(),
1040 security::sb_show_options(&task.kernel(), &mount.fs)?
1042 )?;
1043 Ok(())
1044 })?;
1045 Ok(())
1046 }
1047}
1048
1049fn for_each_mount<E>(
1050 mount: &MountHandle,
1051 callback: &mut impl FnMut(&MountHandle) -> Result<(), E>,
1052) -> Result<(), E> {
1053 callback(mount)?;
1054 for (_, s) in mount.relations.iter_submounts(&RcuReadScope::new()) {
1055 for_each_mount(&s.mount, callback)?;
1056 }
1057 Ok(())
1058}
1059
1060#[derive(Default, PartialEq, Eq, Copy, Clone, Debug)]
1062pub enum SymlinkMode {
1063 #[default]
1065 Follow,
1066
1067 NoFollow,
1069}
1070
1071pub const MAX_SYMLINK_FOLLOWS: u8 = 40;
1073
1074pub struct LookupContext {
1079 pub symlink_mode: SymlinkMode,
1084
1085 pub remaining_follows: u8,
1089
1090 pub must_be_directory: bool,
1096
1097 pub resolve_flags: ResolveFlags,
1099
1100 pub resolve_base: ResolveBase,
1103}
1104
1105#[derive(Clone, Eq, PartialEq)]
1108pub enum ResolveBase {
1109 None,
1110
1111 Beneath(NamespaceNode),
1113
1114 InRoot(NamespaceNode),
1116}
1117
1118impl LookupContext {
1119 pub fn new(symlink_mode: SymlinkMode) -> LookupContext {
1120 LookupContext {
1121 symlink_mode,
1122 remaining_follows: MAX_SYMLINK_FOLLOWS,
1123 must_be_directory: false,
1124 resolve_flags: ResolveFlags::empty(),
1125 resolve_base: ResolveBase::None,
1126 }
1127 }
1128
1129 pub fn with(&self, symlink_mode: SymlinkMode) -> LookupContext {
1130 LookupContext { symlink_mode, resolve_base: self.resolve_base.clone(), ..*self }
1131 }
1132
1133 pub fn update_for_path(&mut self, path: &FsStr) {
1134 if path.last() == Some(&b'/') {
1135 self.must_be_directory = true;
1138 self.symlink_mode = SymlinkMode::Follow;
1141 }
1142 }
1143}
1144
1145impl Default for LookupContext {
1146 fn default() -> Self {
1147 LookupContext::new(SymlinkMode::Follow)
1148 }
1149}
1150
1151pub enum PathWithReachability {
1153 Reachable(FsString),
1155
1156 Unreachable(FsString),
1158}
1159
1160impl PathWithReachability {
1161 pub fn into_path(self) -> FsString {
1162 match self {
1163 PathWithReachability::Reachable(path) => path,
1164 PathWithReachability::Unreachable(path) => path,
1165 }
1166 }
1167}
1168
1169#[derive(Clone)]
1177pub struct NamespaceNode {
1178 pub mount: MountInfo,
1183
1184 pub entry: DirEntryHandle,
1186}
1187
1188impl NamespaceNode {
1189 pub fn new(mount: MountHandle, entry: DirEntryHandle) -> Self {
1190 Self { mount: Some(mount).into(), entry }
1191 }
1192
1193 pub fn new_anonymous(entry: DirEntryHandle) -> Self {
1195 Self { mount: None.into(), entry }
1196 }
1197
1198 pub fn new_anonymous_unrooted(current_task: &CurrentTask, node: FsNodeHandle) -> Self {
1201 let dir_entry = DirEntry::new_unrooted(node);
1202 let _ = security::fs_node_init_with_dentry_no_xattr(current_task, &dir_entry);
1203 Self::new_anonymous(dir_entry)
1204 }
1205
1206 pub fn open(
1212 &self,
1213 locked: &mut Locked<Unlocked>,
1214 current_task: &CurrentTask,
1215 flags: OpenFlags,
1216 access_check: AccessCheck,
1217 ) -> Result<FileHandle, Errno> {
1218 let ops = self.entry.node.open(locked, current_task, self, flags, access_check)?;
1219 FileObject::new(locked, current_task, ops, self.clone(), flags)
1220 }
1221
1222 pub fn open_create_node<L>(
1228 &self,
1229 locked: &mut Locked<L>,
1230 current_task: &CurrentTask,
1231 name: &FsStr,
1232 mode: FileMode,
1233 dev: DeviceId,
1234 flags: OpenFlags,
1235 ) -> Result<NamespaceNode, Errno>
1236 where
1237 L: LockEqualOrBefore<FileOpsCore>,
1238 {
1239 let owner = current_task.current_fscred();
1240 let mode = current_task.fs().apply_umask(mode);
1241 let create_fn =
1242 |locked: &mut Locked<L>, dir: &FsNodeHandle, mount: &MountInfo, name: &_| {
1243 dir.create_node(locked, current_task, mount, name, mode, dev, owner)
1244 };
1245 let entry = if flags.contains(OpenFlags::EXCL) {
1246 self.entry.create_entry(locked, current_task, &self.mount, name, create_fn)
1247 } else {
1248 self.entry.get_or_create_entry(locked, current_task, &self.mount, name, create_fn)
1249 }?;
1250 Ok(self.with_new_entry(entry))
1251 }
1252
1253 pub fn into_active(self) -> ActiveNamespaceNode {
1254 ActiveNamespaceNode::new(self)
1255 }
1256
1257 pub fn into_mapping(self, mode: Option<FileWriteGuardMode>) -> Result<Arc<FileMapping>, Errno> {
1258 self.into_active().into_mapping(mode)
1259 }
1260
1261 pub fn create_node<L>(
1267 &self,
1268 locked: &mut Locked<L>,
1269 current_task: &CurrentTask,
1270 name: &FsStr,
1271 mode: FileMode,
1272 dev: DeviceId,
1273 ) -> Result<NamespaceNode, Errno>
1274 where
1275 L: LockEqualOrBefore<FileOpsCore>,
1276 {
1277 let owner = current_task.current_fscred();
1278 let mode = current_task.fs().apply_umask(mode);
1279 let entry = self.entry.create_entry(
1280 locked,
1281 current_task,
1282 &self.mount,
1283 name,
1284 |locked, dir, mount, name| {
1285 dir.create_node(locked, current_task, mount, name, mode, dev, owner)
1286 },
1287 )?;
1288 Ok(self.with_new_entry(entry))
1289 }
1290
1291 pub fn create_symlink<L>(
1295 &self,
1296 locked: &mut Locked<L>,
1297 current_task: &CurrentTask,
1298 name: &FsStr,
1299 target: &FsStr,
1300 ) -> Result<NamespaceNode, Errno>
1301 where
1302 L: LockEqualOrBefore<FileOpsCore>,
1303 {
1304 let owner = current_task.current_fscred();
1305 let entry = self.entry.create_entry(
1306 locked,
1307 current_task,
1308 &self.mount,
1309 name,
1310 |locked, dir, mount, name| {
1311 dir.create_symlink(locked, current_task, mount, name, target, owner)
1312 },
1313 )?;
1314 Ok(self.with_new_entry(entry))
1315 }
1316
1317 pub fn create_tmpfile<L>(
1323 &self,
1324 locked: &mut Locked<L>,
1325 current_task: &CurrentTask,
1326 mode: FileMode,
1327 flags: OpenFlags,
1328 ) -> Result<NamespaceNode, Errno>
1329 where
1330 L: LockEqualOrBefore<FileOpsCore>,
1331 {
1332 let owner = current_task.current_fscred();
1333 let mode = current_task.fs().apply_umask(mode);
1334 Ok(self.with_new_entry(self.entry.create_tmpfile(
1335 locked,
1336 current_task,
1337 &self.mount,
1338 mode,
1339 owner,
1340 flags,
1341 )?))
1342 }
1343
1344 pub fn link<L>(
1345 &self,
1346 locked: &mut Locked<L>,
1347 current_task: &CurrentTask,
1348 name: &FsStr,
1349 child: &FsNodeHandle,
1350 ) -> Result<NamespaceNode, Errno>
1351 where
1352 L: LockEqualOrBefore<FileOpsCore>,
1353 {
1354 let dir_entry = self.entry.create_entry(
1355 locked,
1356 current_task,
1357 &self.mount,
1358 name,
1359 |locked, dir, mount, name| dir.link(locked, current_task, mount, name, child),
1360 )?;
1361 Ok(self.with_new_entry(dir_entry))
1362 }
1363
1364 pub fn bind_socket<L>(
1365 &self,
1366 locked: &mut Locked<L>,
1367 current_task: &CurrentTask,
1368 name: &FsStr,
1369 socket: SocketHandle,
1370 socket_address: SocketAddress,
1371 mode: FileMode,
1372 ) -> Result<NamespaceNode, Errno>
1373 where
1374 L: LockEqualOrBefore<FileOpsCore>,
1375 {
1376 let dir_entry = self.entry.create_entry(
1377 locked,
1378 current_task,
1379 &self.mount,
1380 name,
1381 |locked, dir, mount, name| {
1382 let node = dir.create_node(
1383 locked,
1384 current_task,
1385 mount,
1386 name,
1387 mode,
1388 DeviceId::NONE,
1389 current_task.current_fscred(),
1390 )?;
1391 if let Some(unix_socket) = socket.downcast_socket::<UnixSocket>() {
1392 unix_socket.bind_socket_to_node(&socket, socket_address, &node)?;
1393 } else {
1394 return error!(ENOTSUP);
1395 }
1396 Ok(node)
1397 },
1398 )?;
1399 Ok(self.with_new_entry(dir_entry))
1400 }
1401
1402 pub fn unlink<L>(
1403 &self,
1404 locked: &mut Locked<L>,
1405 current_task: &CurrentTask,
1406 name: &FsStr,
1407 kind: UnlinkKind,
1408 must_be_directory: bool,
1409 ) -> Result<(), Errno>
1410 where
1411 L: LockEqualOrBefore<FileOpsCore>,
1412 {
1413 if DirEntry::is_reserved_name(name) {
1414 match kind {
1415 UnlinkKind::Directory => {
1416 if name == ".." {
1417 error!(ENOTEMPTY)
1418 } else if self.parent().is_none() {
1419 error!(EBUSY)
1421 } else {
1422 error!(EINVAL)
1423 }
1424 }
1425 UnlinkKind::NonDirectory => error!(ENOTDIR),
1426 }
1427 } else {
1428 self.entry.unlink(locked, current_task, &self.mount, name, kind, must_be_directory)
1429 }
1430 }
1431
1432 fn resolve<L>(
1436 self,
1437 locked: &mut Locked<L>,
1438 current_task: &CurrentTask,
1439 context: &mut LookupContext,
1440 ) -> Result<NamespaceNode, Errno>
1441 where
1442 L: LockEqualOrBefore<FileOpsCore>,
1443 {
1444 let mut node = self;
1445
1446 loop {
1447 if !node.entry.node.is_lnk() || context.symlink_mode == SymlinkMode::NoFollow {
1448 break;
1449 }
1450 if context.remaining_follows == 0
1451 || context.resolve_flags.contains(ResolveFlags::NO_SYMLINKS)
1452 {
1453 return error!(ELOOP);
1454 }
1455 context.remaining_follows -= 1;
1456 node = match node.readlink(locked, current_task)? {
1457 SymlinkTarget::Path(link_target) => {
1458 let link_directory = if link_target[0] == b'/' {
1459 match &context.resolve_base {
1461 ResolveBase::None => current_task.fs().root(),
1462 ResolveBase::Beneath(_) => return error!(EXDEV),
1463 ResolveBase::InRoot(root) => root.clone(),
1464 }
1465 } else {
1466 node.parent().unwrap_or(node)
1470 };
1471 current_task.lookup_path(
1472 locked,
1473 context,
1474 link_directory,
1475 link_target.as_ref(),
1476 )?
1477 }
1478 SymlinkTarget::Node(node) => {
1479 if context.resolve_flags.contains(ResolveFlags::NO_MAGICLINKS) {
1480 return error!(ELOOP);
1481 }
1482 node
1483 }
1484 };
1485 }
1486 Ok(node.enter_mount())
1487 }
1488
1489 pub fn lookup_child<L>(
1491 &self,
1492 locked: &mut Locked<L>,
1493 current_task: &CurrentTask,
1494 context: &mut LookupContext,
1495 basename: &FsStr,
1496 ) -> Result<NamespaceNode, Errno>
1497 where
1498 L: LockEqualOrBefore<FileOpsCore>,
1499 {
1500 self.lookup_children(locked, current_task, context, &[basename])
1501 }
1502
1503 pub fn lookup_children<L>(
1505 &self,
1506 locked: &mut Locked<L>,
1507 current_task: &CurrentTask,
1508 context: &mut LookupContext,
1509 mut basenames: &[&FsStr],
1510 ) -> Result<NamespaceNode, Errno>
1511 where
1512 L: LockEqualOrBefore<FileOpsCore>,
1513 {
1514 for name in basenames {
1515 if name.len() > NAME_MAX as usize {
1516 return error!(ENAMETOOLONG);
1517 }
1518 }
1519
1520 let mut current_namespace_node = self.clone();
1521
1522 while basenames.len() > 0 {
1523 if !current_namespace_node.entry.node.is_dir() {
1524 return error!(ENOTDIR);
1525 }
1526
1527 let basename = basenames[0];
1528 if basename.is_empty() || basename == "." {
1529 basenames = &basenames[1..];
1530 continue;
1531 }
1532 if basename == ".." {
1533 let root = match &context.resolve_base {
1534 ResolveBase::None => current_task.fs().root(),
1535 ResolveBase::Beneath(node) => {
1536 if current_namespace_node == *node {
1538 return error!(EXDEV);
1539 }
1540 current_task.fs().root()
1541 }
1542 ResolveBase::InRoot(root) => root.clone(),
1543 };
1544
1545 if current_namespace_node != root {
1547 current_namespace_node =
1548 current_namespace_node.parent().unwrap_or(current_namespace_node)
1549 }
1550 if context.resolve_flags.contains(ResolveFlags::NO_XDEV)
1551 && current_namespace_node.mount != self.mount
1552 {
1553 return error!(EXDEV);
1554 }
1555
1556 if context.must_be_directory && !current_namespace_node.entry.node.is_dir() {
1557 return error!(ENOTDIR);
1558 }
1559 basenames = &basenames[1..];
1560 continue;
1561 }
1562 if basenames.len() == 1
1563 || !current_namespace_node.entry.node.ops().has_lookup_pipelined()
1564 {
1565 current_namespace_node = current_namespace_node.with_new_entry(
1566 current_namespace_node.entry.component_lookup(
1567 locked,
1568 current_task,
1569 ¤t_namespace_node.mount,
1570 basename,
1571 )?,
1572 );
1573
1574 current_namespace_node =
1575 current_namespace_node.resolve(locked, current_task, context)?;
1576
1577 if context.resolve_flags.contains(ResolveFlags::NO_XDEV)
1578 && current_namespace_node.mount != self.mount
1579 {
1580 return error!(EXDEV);
1581 }
1582
1583 if context.must_be_directory && !current_namespace_node.entry.node.is_dir() {
1584 return error!(ENOTDIR);
1585 }
1586
1587 basenames = &basenames[1..];
1588 continue;
1589 }
1590
1591 let pipelined_basenames = if let Some(pos) =
1592 basenames.iter().position(|&name| name.is_empty() || name == "." || name == "..")
1593 {
1594 &basenames[..pos]
1595 } else {
1596 basenames
1597 };
1598 let precomputed_entries = current_namespace_node.entry.get_children_pipelined(
1599 locked,
1600 current_task,
1601 ¤t_namespace_node.mount,
1602 pipelined_basenames,
1603 );
1604 for entry in precomputed_entries {
1605 basenames = &basenames[1..];
1606 let child = current_namespace_node.with_new_entry(entry?);
1607
1608 current_namespace_node = child.clone().resolve(locked, current_task, context)?;
1609
1610 if context.resolve_flags.contains(ResolveFlags::NO_XDEV)
1611 && current_namespace_node.mount != self.mount
1612 {
1613 return error!(EXDEV);
1614 }
1615
1616 if context.must_be_directory && !current_namespace_node.entry.node.is_dir() {
1617 return error!(ENOTDIR);
1618 }
1619
1620 if current_namespace_node != child {
1621 break;
1622 }
1623 }
1624 }
1625
1626 Ok(current_namespace_node)
1627 }
1628
1629 pub fn parent(&self) -> Option<NamespaceNode> {
1635 let mountpoint_or_self = self.escape_mount();
1636 let parent = mountpoint_or_self.entry.parent()?;
1637 Some(mountpoint_or_self.with_new_entry(parent))
1638 }
1639
1640 pub fn parent_within_mount(&self) -> Option<DirEntryHandle> {
1643 if let Ok(_) = self.mount_if_root() {
1644 return None;
1645 }
1646 self.entry.parent()
1647 }
1648
1649 pub fn is_descendant_of(&self, ancestor: &NamespaceNode) -> bool {
1654 let ancestor = ancestor.escape_mount();
1655 let mut current = self.escape_mount();
1656 while current != ancestor {
1657 if let Some(parent) = current.parent() {
1658 current = parent.escape_mount();
1659 } else {
1660 return false;
1661 }
1662 }
1663 true
1664 }
1665
1666 fn enter_one_mount(&self) -> Option<NamespaceNode> {
1671 if let Some(mount) = self.mount.deref() {
1672 if let Some(submount) =
1673 mount.relations.get_submount(&RcuReadScope::new(), ArcKey::ref_cast(&self.entry))
1674 {
1675 return Some(submount.mount.root());
1676 }
1677 }
1678 None
1679 }
1680
1681 fn enter_mount(&self) -> NamespaceNode {
1686 let kernel = self.entry.node.fs().kernel.upgrade().expect("kernel");
1688 kernel.mounts_lock.read_seq(|| {
1689 let mut inner = self.clone();
1690 while let Some(inner_root) = inner.enter_one_mount() {
1691 inner = inner_root;
1692 }
1693 inner
1694 })
1695 }
1696
1697 fn enter_mount_locked(&self, _mounts_guard: &MountsWriteToken) -> NamespaceNode {
1703 let mut inner = self.clone();
1705 while let Some(inner_root) = inner.enter_one_mount() {
1706 inner = inner_root;
1707 }
1708 inner
1709 }
1710
1711 fn escape_mount(&self) -> NamespaceNode {
1716 let kernel = self.entry.node.fs().kernel.upgrade().expect("kernel");
1717 kernel.mounts_lock.read_seq(|| {
1718 let mut mountpoint_or_self = self.clone();
1719 while let Some(mountpoint) = mountpoint_or_self.mountpoint() {
1720 mountpoint_or_self = mountpoint;
1721 }
1722 mountpoint_or_self
1723 })
1724 }
1725
1726 pub fn mount_if_root(&self) -> Result<&MountHandle, Errno> {
1728 if let Some(mount) = self.mount.deref() {
1729 if Arc::ptr_eq(&self.entry, &mount.root) {
1730 return Ok(mount);
1731 }
1732 }
1733 error!(EINVAL)
1734 }
1735
1736 fn mountpoint(&self) -> Option<NamespaceNode> {
1741 self.mount_if_root().ok()?.mountpoint()
1742 }
1743
1744 pub fn path(&self, fs: &FsContext) -> FsString {
1746 self.path_from_root(Some(&fs.root())).into_path()
1747 }
1748
1749 pub fn path_escaping_chroot(&self) -> FsString {
1751 self.path_from_root(None).into_path()
1752 }
1753
1754 pub fn path_from_root(&self, root: Option<&NamespaceNode>) -> PathWithReachability {
1757 if self.mount.is_none() {
1758 return self.unrooted_path();
1759 }
1760
1761 let mut path = PathBuilder::new();
1762 let mut current = self.escape_mount();
1763 if let Some(root) = root {
1764 let scope = RcuReadScope::new();
1765 let root = root.escape_mount();
1767 while current != root {
1768 if let Some(parent) = current.parent() {
1769 path.prepend_element(current.entry.local_name(&scope));
1770 current = parent.escape_mount();
1771 } else {
1772 let mut absolute_path = path.build_absolute();
1774 if self.entry.is_dead() {
1775 absolute_path.extend_from_slice(b" (deleted)");
1776 }
1777
1778 return PathWithReachability::Unreachable(absolute_path);
1779 }
1780 }
1781 } else {
1782 let scope = RcuReadScope::new();
1784 while let Some(parent) = current.parent() {
1785 path.prepend_element(current.entry.local_name(&scope));
1786 current = parent.escape_mount();
1787 }
1788 }
1789
1790 let mut absolute_path = path.build_absolute();
1791 if self.entry.is_dead() {
1792 absolute_path.extend_from_slice(b" (deleted)");
1793 }
1794
1795 PathWithReachability::Reachable(absolute_path)
1796 }
1797
1798 fn unrooted_path(&self) -> PathWithReachability {
1799 let scope = RcuReadScope::new();
1800 let mode = self.entry.node.info().mode;
1801 let local_name = self.entry.local_name(&scope);
1802 let path = if !local_name.is_empty() {
1803 format!("anon_inode:{}", local_name)
1804 } else if mode.is_sock() {
1805 format!("socket:[{}]", self.entry.node.ino)
1806 } else if mode.is_fifo() {
1807 format!("pipe:[{}]", self.entry.node.ino)
1808 } else {
1809 format!("file:[{}]", self.entry.node.ino)
1810 };
1811 PathWithReachability::Reachable(path.into())
1812 }
1813
1814 pub fn mount(&self, what: WhatToMount, flags: MountpointFlags) -> Result<(), Errno> {
1815 let kernel = self.entry.node.fs().kernel.upgrade().expect("can't mount without a kernel");
1816 let mounts_guard = kernel.mounts_lock.lock();
1817
1818 let mountpoint = self.enter_mount_locked(&mounts_guard);
1819 let mount = mountpoint.mount.as_ref().expect("a mountpoint must be part of a mount");
1820 mount.create_submount(&mounts_guard, &mountpoint.entry, WhatSubmount::New(what, flags));
1821 Ok(())
1822 }
1823
1824 pub fn unmount(&self, flags: UnmountFlags) -> Result<(), Errno> {
1826 let kernel = self.entry.node.fs().kernel.upgrade().expect("can't mount without a kernel");
1827 let mounts_guard = kernel.mounts_lock.lock();
1828
1829 let mount = self.enter_mount_locked(&mounts_guard).mount_if_root()?.clone();
1830 mount.unmount(&mounts_guard, flags)
1831 }
1832
1833 pub fn rename<L>(
1834 locked: &mut Locked<L>,
1835 current_task: &CurrentTask,
1836 old_parent: &NamespaceNode,
1837 old_name: &FsStr,
1838 new_parent: &NamespaceNode,
1839 new_name: &FsStr,
1840 flags: RenameFlags,
1841 ) -> Result<(), Errno>
1842 where
1843 L: LockEqualOrBefore<FileOpsCore>,
1844 {
1845 DirEntry::rename(
1846 locked,
1847 current_task,
1848 &old_parent.entry,
1849 &old_parent.mount,
1850 old_name,
1851 &new_parent.entry,
1852 &new_parent.mount,
1853 new_name,
1854 flags,
1855 )
1856 }
1857
1858 fn with_new_entry(&self, entry: DirEntryHandle) -> NamespaceNode {
1859 Self { mount: self.mount.clone(), entry }
1860 }
1861
1862 fn mount_hash_key(&self) -> &ArcKey<DirEntry> {
1863 ArcKey::ref_cast(&self.entry)
1864 }
1865
1866 pub fn apply_suid_and_sgid(&self, creds: &mut Credentials) {
1867 if self.mount.flags().contains(MountFlags::NOSUID) {
1873 return;
1874 }
1875 self.entry.node.info().apply_suid_and_sgid(creds)
1876 }
1877
1878 pub fn update_atime(&self) {
1879 if !self.mount.flags().contains(MountFlags::NOATIME) {
1881 self.entry.node.update_info(|info| {
1882 let now = utc::utc_now();
1883 info.time_access = now;
1884 info.pending_time_access_update = true;
1885 });
1886 }
1887 }
1888
1889 pub fn readlink<L>(
1890 &self,
1891 locked: &mut Locked<L>,
1892 current_task: &CurrentTask,
1893 ) -> Result<SymlinkTarget, Errno>
1894 where
1895 L: LockEqualOrBefore<FileOpsCore>,
1896 {
1897 self.update_atime();
1898 self.entry.node.readlink(locked, current_task)
1899 }
1900
1901 pub fn notify(&self, event_mask: InotifyMask) {
1902 if self.mount.is_some() {
1903 self.entry.notify(event_mask);
1904 }
1905 }
1906
1907 pub fn check_access<L>(
1911 &self,
1912 locked: &mut Locked<L>,
1913 current_task: &CurrentTask,
1914 permission_flags: impl Into<security::PermissionFlags>,
1915 reason: CheckAccessReason,
1916 ) -> Result<(), Errno>
1917 where
1918 L: LockEqualOrBefore<FileOpsCore>,
1919 {
1920 self.entry.node.check_access(
1921 locked,
1922 current_task,
1923 &self.mount,
1924 permission_flags,
1925 reason,
1926 self,
1927 )
1928 }
1929
1930 pub fn check_o_noatime_allowed(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1932 self.entry.node.check_o_noatime_allowed(current_task)
1933 }
1934
1935 pub fn truncate<L>(
1936 &self,
1937 locked: &mut Locked<L>,
1938 current_task: &CurrentTask,
1939 length: u64,
1940 ) -> Result<(), Errno>
1941 where
1942 L: LockEqualOrBefore<BeforeFsNodeAppend>,
1943 {
1944 self.entry.node.truncate(locked, current_task, &self.mount, length)?;
1945 self.entry.notify_ignoring_excl_unlink(InotifyMask::MODIFY);
1946 Ok(())
1947 }
1948}
1949
1950impl fmt::Debug for NamespaceNode {
1951 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1952 f.debug_struct("NamespaceNode")
1953 .field("path", &self.path_escaping_chroot())
1954 .field("mount", &self.mount)
1955 .field("entry", &self.entry)
1956 .finish()
1957 }
1958}
1959
1960impl PartialEq for NamespaceNode {
1962 fn eq(&self, other: &Self) -> bool {
1963 self.mount.as_ref().map(Arc::as_ptr).eq(&other.mount.as_ref().map(Arc::as_ptr))
1964 && Arc::ptr_eq(&self.entry, &other.entry)
1965 }
1966}
1967impl Eq for NamespaceNode {}
1968impl Hash for NamespaceNode {
1969 fn hash<H: Hasher>(&self, state: &mut H) {
1970 self.mount.as_ref().map(Arc::as_ptr).hash(state);
1971 Arc::as_ptr(&self.entry).hash(state);
1972 }
1973}
1974
1975#[derive(Debug, Clone)]
1977pub struct ActiveNamespaceNode {
1978 name: NamespaceNode,
1980
1981 _marker: Option<MountClientMarker>,
1985}
1986
1987impl ActiveNamespaceNode {
1988 pub fn new(name: NamespaceNode) -> Self {
1989 let marker = name.mount.as_ref().map(|mount| mount.active_client_counter.clone());
1990 Self { name, _marker: marker }
1991 }
1992
1993 pub fn to_passive(&self) -> NamespaceNode {
1994 self.deref().clone()
1995 }
1996
1997 pub fn into_mapping(self, mode: Option<FileWriteGuardMode>) -> Result<Arc<FileMapping>, Errno> {
1998 if let Some(mode) = mode {
1999 self.entry.node.write_guard_state.lock().acquire(mode)?;
2000 }
2001 Ok(Arc::new(FileMapping { name: self, mode }))
2002 }
2003}
2004
2005impl Deref for ActiveNamespaceNode {
2006 type Target = NamespaceNode;
2007
2008 fn deref(&self) -> &Self::Target {
2009 &self.name
2010 }
2011}
2012
2013impl PartialEq for ActiveNamespaceNode {
2014 fn eq(&self, other: &Self) -> bool {
2015 self.deref().eq(other.deref())
2016 }
2017}
2018impl Eq for ActiveNamespaceNode {}
2019impl Hash for ActiveNamespaceNode {
2020 fn hash<H: Hasher>(&self, state: &mut H) {
2021 self.deref().hash(state)
2022 }
2023}
2024
2025#[derive(Debug, Clone, PartialEq, Eq)]
2026#[must_use]
2027pub struct FileMapping {
2028 pub name: ActiveNamespaceNode,
2029 mode: Option<FileWriteGuardMode>,
2030}
2031
2032impl Drop for FileMapping {
2033 fn drop(&mut self) {
2034 if let Some(mode) = self.mode {
2035 self.name.entry.node.write_guard_state.lock().release(mode);
2036 }
2037 }
2038}
2039
2040pub struct Mounts {
2042 mounts: RcuHashMap<WeakKey<DirEntry>, Vec<ArcKey<Mount>>>,
2043}
2044
2045impl Mounts {
2046 pub fn new() -> Self {
2047 Mounts { mounts: RcuHashMap::default() }
2048 }
2049
2050 fn register_mount(&self, dir_entry: &Arc<DirEntry>, mount: MountHandle) -> Submount {
2052 let mut mounts = self.mounts.lock();
2053 let key = WeakKey::from(dir_entry);
2054 let mut vec = mounts.get(&key).unwrap_or_else(|| {
2055 dir_entry.set_has_mounts(true);
2056 Vec::new()
2057 });
2058 vec.push(ArcKey(mount.clone()));
2059 mounts.insert(key, vec);
2060 Submount { dir: ArcKey(dir_entry.clone()), mount }
2061 }
2062
2063 fn unregister_mount(&self, dir_entry: &Arc<DirEntry>, mount: &MountHandle) {
2065 let mut mounts = self.mounts.lock();
2066 let key = WeakKey::from(dir_entry);
2067 if let Some(mut vec) = mounts.get(&key) {
2068 let index = vec.iter().position(|e| e == ArcKey::ref_cast(mount)).unwrap();
2069 if vec.len() == 1 {
2070 mounts.remove(&key);
2071 dir_entry.set_has_mounts(false);
2072 } else {
2073 vec.swap_remove(index);
2074 mounts.insert(key, vec);
2075 }
2076 }
2077 }
2078
2079 pub fn unmount(&self, dir_entry: &DirEntry) {
2083 let mounts = self.mounts.lock().remove(&PtrKey::from(dir_entry as *const _));
2084 if let Some(mounts) = mounts {
2085 if let Some(kernel) = mounts.get(0).map(|m| m.kernel()) {
2086 let mounts_guard = kernel.mounts_lock.lock();
2087 for mount in mounts {
2088 let _ = mount.unmount(&mounts_guard, UnmountFlags::DETACH);
2090 }
2091 }
2092 }
2093 }
2094
2095 pub fn clear(&self) {
2099 for (_dir_entry, mounts) in self.mounts.lock().drain() {
2100 for mount in mounts {
2101 mount.fs.force_unmount_ops();
2102 }
2103 }
2104 }
2105
2106 pub fn sync_all(
2107 &self,
2108 locked: &mut Locked<Unlocked>,
2109 current_task: &CurrentTask,
2110 ) -> Result<(), Errno> {
2111 let mut filesystems = Vec::new();
2112 {
2113 let scope = RcuReadScope::new();
2114 let mut seen = HashSet::new();
2115 for (_dir_entry, m_list) in self.mounts.iter(&scope) {
2116 for m in m_list {
2117 if seen.insert(Arc::as_ptr(&m.fs)) {
2118 filesystems.push(m.fs.clone());
2119 }
2120 }
2121 }
2122 }
2123
2124 for fs in filesystems {
2125 if let Err(e) = fs.sync(locked, current_task) {
2126 log_warn!("sync failed for filesystem {:?}: {:?}", fs.name(), e);
2127 }
2128 }
2129 Ok(())
2130 }
2131}
2132
2133impl Drop for Mount {
2134 fn drop(&mut self) {
2135 let kernel = self.kernel();
2138 let peer_group = self.relations.peer_group.cloned();
2139 let upstream = self.relations.upstream.cloned();
2140 self.relations.peer_group.update(None);
2141 self.relations.upstream.update(None);
2142 if peer_group.is_some() || upstream.is_some() {
2143 fuchsia_rcu::rcu_drop(scopeguard::guard(
2144 (kernel, peer_group, upstream),
2145 |(kernel, peer_group, upstream)| {
2146 let guard = kernel.mounts_lock.lock();
2147 Mount::unregister_from_peer_group_and_upstream(&guard, peer_group, upstream);
2148 },
2149 ));
2150 }
2151 }
2152}
2153
2154impl fmt::Debug for Mount {
2155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2156 let scope = RcuReadScope::new();
2157 f.debug_struct("Mount")
2158 .field("id", &(self as *const Mount))
2159 .field("root", &self.root)
2160 .field("mountpoint", &self.relations.mountpoint(&scope))
2161 .field("submounts", &self.relations.iter_submounts(&scope).collect::<Vec<_>>())
2162 .finish()
2163 }
2164}
2165
2166#[derive(Debug)]
2168struct Submount {
2169 dir: ArcKey<DirEntry>,
2170 mount: MountHandle,
2171}
2172
2173impl Drop for Submount {
2174 fn drop(&mut self) {
2175 self.mount.kernel().mounts.unregister_mount(&self.dir, &self.mount)
2176 }
2177}
2178
2179impl Eq for Submount {}
2181impl PartialEq<Self> for Submount {
2182 fn eq(&self, other: &Self) -> bool {
2183 self.dir == other.dir
2184 }
2185}
2186impl Hash for Submount {
2187 fn hash<H: Hasher>(&self, state: &mut H) {
2188 self.dir.hash(state)
2189 }
2190}
2191
2192impl Borrow<ArcKey<DirEntry>> for Submount {
2193 fn borrow(&self) -> &ArcKey<DirEntry> {
2194 &self.dir
2195 }
2196}
2197
2198#[cfg(test)]
2199mod test {
2200 use crate::fs::tmpfs::TmpFs;
2201 use crate::testing::spawn_kernel_and_run;
2202 use crate::vfs::namespace::DeviceId;
2203 use crate::vfs::{
2204 CallbackSymlinkNode, FsNodeInfo, LookupContext, MountInfo, Namespace, NamespaceNode,
2205 RenameFlags, SymlinkMode, SymlinkTarget, UnlinkKind, WhatToMount,
2206 };
2207 use starnix_uapi::mount_flags::MountpointFlags;
2208 use starnix_uapi::{errno, mode};
2209 use std::sync::Arc;
2210
2211 #[::fuchsia::test]
2212 async fn test_namespace() {
2213 spawn_kernel_and_run(async |locked, current_task| {
2214 let kernel = current_task.kernel();
2215 let root_fs = TmpFs::new_fs(locked, &kernel);
2216 let root_node = Arc::clone(root_fs.root());
2217 let _dev_node = root_node
2218 .create_dir(locked, ¤t_task, "dev".into())
2219 .expect("failed to mkdir dev");
2220 let dev_fs = TmpFs::new_fs(locked, &kernel);
2221 let dev_root_node = Arc::clone(dev_fs.root());
2222 let _dev_pts_node = dev_root_node
2223 .create_dir(locked, ¤t_task, "pts".into())
2224 .expect("failed to mkdir pts");
2225
2226 let ns = Namespace::new(root_fs);
2227 let mut context = LookupContext::default();
2228 let dev = ns
2229 .root()
2230 .lookup_child(locked, ¤t_task, &mut context, "dev".into())
2231 .expect("failed to lookup dev");
2232 dev.mount(WhatToMount::Fs(dev_fs), MountpointFlags::empty())
2233 .expect("failed to mount dev root node");
2234
2235 let mut context = LookupContext::default();
2236 let dev = ns
2237 .root()
2238 .lookup_child(locked, ¤t_task, &mut context, "dev".into())
2239 .expect("failed to lookup dev");
2240 let mut context = LookupContext::default();
2241 let pts = dev
2242 .lookup_child(locked, ¤t_task, &mut context, "pts".into())
2243 .expect("failed to lookup pts");
2244 let pts_parent =
2245 pts.parent().ok_or_else(|| errno!(ENOENT)).expect("failed to get parent of pts");
2246 assert!(Arc::ptr_eq(&pts_parent.entry, &dev.entry));
2247
2248 let dev_parent =
2249 dev.parent().ok_or_else(|| errno!(ENOENT)).expect("failed to get parent of dev");
2250 assert!(Arc::ptr_eq(&dev_parent.entry, &ns.root().entry));
2251 })
2252 .await;
2253 }
2254
2255 #[::fuchsia::test]
2256 async fn test_mount_does_not_upgrade() {
2257 spawn_kernel_and_run(async |locked, current_task| {
2258 let kernel = current_task.kernel();
2259 let root_fs = TmpFs::new_fs(locked, &kernel);
2260 let root_node = Arc::clone(root_fs.root());
2261 let _dev_node = root_node
2262 .create_dir(locked, ¤t_task, "dev".into())
2263 .expect("failed to mkdir dev");
2264 let dev_fs = TmpFs::new_fs(locked, &kernel);
2265 let dev_root_node = Arc::clone(dev_fs.root());
2266 let _dev_pts_node = dev_root_node
2267 .create_dir(locked, ¤t_task, "pts".into())
2268 .expect("failed to mkdir pts");
2269
2270 let ns = Namespace::new(root_fs);
2271 let mut context = LookupContext::default();
2272 let dev = ns
2273 .root()
2274 .lookup_child(locked, ¤t_task, &mut context, "dev".into())
2275 .expect("failed to lookup dev");
2276 dev.mount(WhatToMount::Fs(dev_fs), MountpointFlags::empty())
2277 .expect("failed to mount dev root node");
2278 let mut context = LookupContext::default();
2279 let new_dev = ns
2280 .root()
2281 .lookup_child(locked, ¤t_task, &mut context, "dev".into())
2282 .expect("failed to lookup dev again");
2283 assert!(!Arc::ptr_eq(&dev.entry, &new_dev.entry));
2284 assert_ne!(&dev, &new_dev);
2285
2286 let mut context = LookupContext::default();
2287 let _new_pts = new_dev
2288 .lookup_child(locked, ¤t_task, &mut context, "pts".into())
2289 .expect("failed to lookup pts");
2290 let mut context = LookupContext::default();
2291 assert!(dev.lookup_child(locked, ¤t_task, &mut context, "pts".into()).is_err());
2292 })
2293 .await;
2294 }
2295
2296 #[::fuchsia::test]
2297 async fn test_path() {
2298 spawn_kernel_and_run(async |locked, current_task| {
2299 let kernel = current_task.kernel();
2300 let root_fs = TmpFs::new_fs(locked, &kernel);
2301 let root_node = Arc::clone(root_fs.root());
2302 let _dev_node = root_node
2303 .create_dir(locked, ¤t_task, "dev".into())
2304 .expect("failed to mkdir dev");
2305 let dev_fs = TmpFs::new_fs(locked, &kernel);
2306 let dev_root_node = Arc::clone(dev_fs.root());
2307 let _dev_pts_node = dev_root_node
2308 .create_dir(locked, ¤t_task, "pts".into())
2309 .expect("failed to mkdir pts");
2310
2311 let ns = Namespace::new(root_fs);
2312 let mut context = LookupContext::default();
2313 let dev = ns
2314 .root()
2315 .lookup_child(locked, ¤t_task, &mut context, "dev".into())
2316 .expect("failed to lookup dev");
2317 dev.mount(WhatToMount::Fs(dev_fs), MountpointFlags::empty())
2318 .expect("failed to mount dev root node");
2319
2320 let mut context = LookupContext::default();
2321 let dev = ns
2322 .root()
2323 .lookup_child(locked, ¤t_task, &mut context, "dev".into())
2324 .expect("failed to lookup dev");
2325 let mut context = LookupContext::default();
2326 let pts = dev
2327 .lookup_child(locked, ¤t_task, &mut context, "pts".into())
2328 .expect("failed to lookup pts");
2329
2330 assert_eq!("/", ns.root().path_escaping_chroot());
2331 assert_eq!("/dev", dev.path_escaping_chroot());
2332 assert_eq!("/dev/pts", pts.path_escaping_chroot());
2333 })
2334 .await;
2335 }
2336
2337 #[::fuchsia::test]
2338 async fn test_shadowing() {
2339 spawn_kernel_and_run(async |locked, current_task| {
2340 let kernel = current_task.kernel();
2341 let root_fs = TmpFs::new_fs(locked, &kernel);
2342 let ns = Namespace::new(root_fs.clone());
2343 let _foo_node = root_fs.root().create_dir(locked, ¤t_task, "foo".into()).unwrap();
2344 let mut context = LookupContext::default();
2345 let foo_dir =
2346 ns.root().lookup_child(locked, ¤t_task, &mut context, "foo".into()).unwrap();
2347
2348 let foofs1 = TmpFs::new_fs(locked, &kernel);
2349 foo_dir.mount(WhatToMount::Fs(foofs1.clone()), MountpointFlags::empty()).unwrap();
2350 let mut context = LookupContext::default();
2351 assert!(Arc::ptr_eq(
2352 &ns.root()
2353 .lookup_child(locked, ¤t_task, &mut context, "foo".into())
2354 .unwrap()
2355 .entry,
2356 foofs1.root()
2357 ));
2358 let foo_dir =
2359 ns.root().lookup_child(locked, ¤t_task, &mut context, "foo".into()).unwrap();
2360
2361 let ns_clone = ns.clone_namespace(&kernel.mounts_lock.lock());
2362
2363 let foofs2 = TmpFs::new_fs(locked, &kernel);
2364 foo_dir.mount(WhatToMount::Fs(foofs2.clone()), MountpointFlags::empty()).unwrap();
2365 let mut context = LookupContext::default();
2366 assert!(Arc::ptr_eq(
2367 &ns.root()
2368 .lookup_child(locked, ¤t_task, &mut context, "foo".into())
2369 .unwrap()
2370 .entry,
2371 foofs2.root()
2372 ));
2373
2374 assert!(Arc::ptr_eq(
2375 &ns_clone
2376 .root()
2377 .lookup_child(
2378 locked,
2379 ¤t_task,
2380 &mut LookupContext::default(),
2381 "foo".into()
2382 )
2383 .unwrap()
2384 .entry,
2385 foofs1.root()
2386 ));
2387 })
2388 .await;
2389 }
2390
2391 #[::fuchsia::test]
2392 async fn test_unlink_mounted_directory() {
2393 spawn_kernel_and_run(async |locked, current_task| {
2394 let kernel = current_task.kernel();
2395 let root_fs = TmpFs::new_fs(locked, &kernel);
2396 let ns1 = Namespace::new(root_fs.clone());
2397 let ns2 = Namespace::new(root_fs.clone());
2398 let _foo_node = root_fs.root().create_dir(locked, ¤t_task, "foo".into()).unwrap();
2399 let mut context = LookupContext::default();
2400 let foo_dir =
2401 ns1.root().lookup_child(locked, ¤t_task, &mut context, "foo".into()).unwrap();
2402
2403 let foofs = TmpFs::new_fs(locked, &kernel);
2404 foo_dir.mount(WhatToMount::Fs(foofs), MountpointFlags::empty()).unwrap();
2405
2406 assert_eq!(
2408 ns1.root()
2409 .unlink(locked, ¤t_task, "foo".into(), UnlinkKind::Directory, false)
2410 .unwrap_err(),
2411 errno!(EBUSY),
2412 );
2413
2414 ns2.root()
2416 .unlink(locked, ¤t_task, "foo".into(), UnlinkKind::Directory, false)
2417 .expect("unlink failed");
2418
2419 assert_eq!(
2421 ns1.root()
2422 .unlink(locked, ¤t_task, "foo".into(), UnlinkKind::Directory, false)
2423 .unwrap_err(),
2424 errno!(ENOENT),
2425 );
2426 })
2427 .await;
2428 }
2429
2430 #[::fuchsia::test]
2431 async fn test_rename_mounted_directory() {
2432 spawn_kernel_and_run(async |locked, current_task| {
2433 let kernel = current_task.kernel();
2434 let root_fs = TmpFs::new_fs(locked, &kernel);
2435 let ns1 = Namespace::new(root_fs.clone());
2436 let ns2 = Namespace::new(root_fs.clone());
2437 let _foo_node = root_fs.root().create_dir(locked, ¤t_task, "foo".into()).unwrap();
2438 let _bar_node = root_fs.root().create_dir(locked, ¤t_task, "bar".into()).unwrap();
2439 let _baz_node = root_fs.root().create_dir(locked, ¤t_task, "baz".into()).unwrap();
2440 let mut context = LookupContext::default();
2441 let foo_dir =
2442 ns1.root().lookup_child(locked, ¤t_task, &mut context, "foo".into()).unwrap();
2443
2444 let foofs = TmpFs::new_fs(locked, &kernel);
2445 foo_dir.mount(WhatToMount::Fs(foofs), MountpointFlags::empty()).unwrap();
2446
2447 let root = ns1.root();
2449 assert_eq!(
2450 NamespaceNode::rename(
2451 locked,
2452 ¤t_task,
2453 &root,
2454 "bar".into(),
2455 &root,
2456 "foo".into(),
2457 RenameFlags::empty()
2458 )
2459 .unwrap_err(),
2460 errno!(EBUSY),
2461 );
2462 assert_eq!(
2464 NamespaceNode::rename(
2465 locked,
2466 ¤t_task,
2467 &root,
2468 "foo".into(),
2469 &root,
2470 "bar".into(),
2471 RenameFlags::empty()
2472 )
2473 .unwrap_err(),
2474 errno!(EBUSY),
2475 );
2476
2477 let root = ns2.root();
2479
2480 NamespaceNode::rename(
2482 locked,
2483 ¤t_task,
2484 &root,
2485 "foo".into(),
2486 &root,
2487 "bar".into(),
2488 RenameFlags::empty(),
2489 )
2490 .expect("rename failed");
2491
2492 NamespaceNode::rename(
2494 locked,
2495 ¤t_task,
2496 &root,
2497 "baz".into(),
2498 &root,
2499 "bar".into(),
2500 RenameFlags::empty(),
2501 )
2502 .expect("rename failed");
2503
2504 assert_eq!(
2506 ns1.root()
2507 .lookup_child(locked, ¤t_task, &mut context, "foo".into())
2508 .unwrap_err(),
2509 errno!(ENOENT)
2510 );
2511 assert_eq!(
2512 ns1.root()
2513 .lookup_child(locked, ¤t_task, &mut context, "baz".into())
2514 .unwrap_err(),
2515 errno!(ENOENT)
2516 );
2517 })
2518 .await;
2519 }
2520
2521 #[::fuchsia::test]
2524 async fn test_lookup_with_symlink_chain() {
2525 spawn_kernel_and_run(async |locked, current_task| {
2526 let kernel = current_task.kernel();
2528 let root_fs = TmpFs::new_fs(locked, &kernel);
2529 let root_node = Arc::clone(root_fs.root());
2530 let _first_subdir_node = root_node
2531 .create_dir(locked, ¤t_task, "first_subdir".into())
2532 .expect("failed to mkdir dev");
2533 let _second_subdir_node = root_node
2534 .create_dir(locked, ¤t_task, "second_subdir".into())
2535 .expect("failed to mkdir dev");
2536
2537 let first_subdir_fs = TmpFs::new_fs(locked, &kernel);
2539 let second_subdir_fs = TmpFs::new_fs(locked, &kernel);
2540
2541 let ns = Namespace::new(root_fs);
2542 let mut context = LookupContext::default();
2543 let first_subdir = ns
2544 .root()
2545 .lookup_child(locked, ¤t_task, &mut context, "first_subdir".into())
2546 .expect("failed to lookup first_subdir");
2547 first_subdir
2548 .mount(WhatToMount::Fs(first_subdir_fs), MountpointFlags::empty())
2549 .expect("failed to mount first_subdir fs node");
2550 let second_subdir = ns
2551 .root()
2552 .lookup_child(locked, ¤t_task, &mut context, "second_subdir".into())
2553 .expect("failed to lookup second_subdir");
2554 second_subdir
2555 .mount(WhatToMount::Fs(second_subdir_fs), MountpointFlags::empty())
2556 .expect("failed to mount second_subdir fs node");
2557
2558 let real_file_node = first_subdir
2567 .create_node(
2568 locked,
2569 ¤t_task,
2570 "real_file".into(),
2571 mode!(IFREG, 0o777),
2572 DeviceId::NONE,
2573 )
2574 .expect("failed to create real_file");
2575 first_subdir
2576 .create_symlink(locked, ¤t_task, "path_symlink".into(), "real_file".into())
2577 .expect("failed to create path_symlink");
2578
2579 let mut no_follow_lookup_context = LookupContext::new(SymlinkMode::NoFollow);
2580 let path_symlink_node = first_subdir
2581 .lookup_child(
2582 locked,
2583 ¤t_task,
2584 &mut no_follow_lookup_context,
2585 "path_symlink".into(),
2586 )
2587 .expect("Failed to lookup path_symlink");
2588
2589 let node_symlink_node = second_subdir.entry.node.fs().create_node_and_allocate_node_id(
2593 CallbackSymlinkNode::new(move || {
2594 let node = path_symlink_node.clone();
2595 Ok(SymlinkTarget::Node(node))
2596 }),
2597 FsNodeInfo::new(mode!(IFLNK, 0o777), current_task.current_fscred()),
2598 );
2599 second_subdir
2600 .entry
2601 .create_entry(
2602 locked,
2603 ¤t_task,
2604 &MountInfo::detached(),
2605 "node_symlink".into(),
2606 move |_locked, _dir, _mount, _name| Ok(node_symlink_node),
2607 )
2608 .expect("failed to create node_symlink entry");
2609
2610 let mut follow_lookup_context = LookupContext::new(SymlinkMode::Follow);
2612 let node_symlink_resolution = second_subdir
2613 .lookup_child(
2614 locked,
2615 ¤t_task,
2616 &mut follow_lookup_context,
2617 "node_symlink".into(),
2618 )
2619 .expect("lookup with symlink chain failed");
2620
2621 assert!(node_symlink_resolution.entry.node.ino == real_file_node.entry.node.ino);
2623 })
2624 .await;
2625 }
2626}