From faf9cf7da8ad712223cbc84027cd5d4a8ce3d769 Mon Sep 17 00:00:00 2001 From: Zhenchen Wang Date: Sun, 2 Jun 2024 11:40:53 +0800 Subject: [PATCH] Fix some issues about naming, function parameters, and comments, and redefined the method for bind mount. Signed-off-by: Zhenchen Wang --- kernel/aster-nix/src/fs/path/dentry.rs | 34 ++++--- kernel/aster-nix/src/fs/path/mount.rs | 56 ++++++----- kernel/aster-nix/src/syscall/arch/x86.rs | 2 +- kernel/aster-nix/src/syscall/mount.rs | 116 +++++++++++------------ kernel/aster-nix/src/syscall/umount.rs | 10 +- 5 files changed, 117 insertions(+), 101 deletions(-) diff --git a/kernel/aster-nix/src/fs/path/dentry.rs b/kernel/aster-nix/src/fs/path/dentry.rs index 4e7e1f74f..ad03ec6e4 100644 --- a/kernel/aster-nix/src/fs/path/dentry.rs +++ b/kernel/aster-nix/src/fs/path/dentry.rs @@ -104,11 +104,12 @@ impl Dentry_ { DentryFlags::from_bits(flags).unwrap() } - /// Check if the Dentry_ is a subdir of the given Dentry_. - pub fn is_subdir(&self, dentry: Arc) -> bool { + /// Check if this dentry is a descendant (child, grandchild, or + /// great-grandchild, etc.) of another dentry. + pub fn is_descendant_of(&self, ancestor: &Arc) -> bool { let mut parent = self.parent(); while let Some(p) = parent { - if Arc::ptr_eq(&p, &dentry) { + if Arc::ptr_eq(&p, ancestor) { return true; } parent = p.parent(); @@ -571,10 +572,10 @@ impl Dentry { } } - /// Make this Dentry' inner to be a mountpoint, + /// Make this Dentry's inner to be a mountpoint, /// and set the mountpoint of the child mount to this Dentry's inner. - pub fn set_mountpoint(&self, child_mount: Arc) { - child_mount.set_mountpoint_dentry(self.inner.clone()); + pub(super) fn set_mountpoint(&self, child_mount: Arc) { + child_mount.set_mountpoint_dentry(&self.inner); self.inner.set_mountpoint_dentry(); } @@ -600,7 +601,7 @@ impl Dentry { /// Unmount and return the mounted child mount. /// /// Note that the root mount cannot be unmounted. - pub fn umount(&self) -> Result> { + pub fn unmount(&self) -> Result> { if !self.inner.is_root_of_mount() { return_errno_with_message!(Errno::EINVAL, "not mounted"); } @@ -613,7 +614,7 @@ impl Dentry { let mountpoint_mount_node = mount_node.parent().unwrap().upgrade().unwrap(); let mountpoint = Self::new(mountpoint_mount_node.clone(), mountpoint_dentry.clone()); - let child_mount = mountpoint_mount_node.umount(&mountpoint)?; + let child_mount = mountpoint_mount_node.unmount(&mountpoint)?; mountpoint_dentry.clear_mountpoint(); Ok(child_mount) } @@ -650,12 +651,17 @@ impl Dentry { self.inner.rename(old_name, &new_dir.inner, new_name) } - pub fn do_loopback(&self, recursive: bool) -> Arc { - if recursive { - self.mount_node.copy_mount_node_tree(self.inner.clone()) - } else { - self.mount_node.clone_mount_node(self.inner.clone()) - } + /// Bind mount the Dentry to the destination Dentry. + /// + /// If recursive is true, it will bind mount the whole mount tree + /// to the destination Dentry. Otherwise, it will only bind mount + /// the root mount node. + pub fn bind_mount_to(&self, dst_dentry: &Arc, recursive: bool) -> Result<()> { + let src_mount = self + .mount_node + .clone_mount_node_tree(&self.inner, recursive); + src_mount.graft_mount_node_tree(dst_dentry)?; + Ok(()) } /// Get the arc reference to self. diff --git a/kernel/aster-nix/src/fs/path/mount.rs b/kernel/aster-nix/src/fs/path/mount.rs index f13d5f38b..861528c5f 100644 --- a/kernel/aster-nix/src/fs/path/mount.rs +++ b/kernel/aster-nix/src/fs/path/mount.rs @@ -84,7 +84,7 @@ impl MountNode { /// Unmount a child mount node from the mountpoint and return it. /// /// The mountpoint should belong to this mount node, or an error is returned. - pub fn umount(&self, mountpoint: &Dentry) -> Result> { + pub fn unmount(&self, mountpoint: &Dentry) -> Result> { if !Arc::ptr_eq(mountpoint.mount_node(), &self.this()) { return_errno_with_message!(Errno::EINVAL, "mountpoint not belongs to this"); } @@ -97,12 +97,13 @@ impl MountNode { Ok(child_mount) } - /// Clone a mount node with the an root Dentry_. + /// Clone a mount node with the an root `Dentry_`. + /// /// The new mount node will have the same fs as the original one and /// have no parent and children. We should set the parent and children manually. - pub fn clone_mount_node(&self, root_dentry: Arc) -> Arc { + fn clone_mount_node(&self, root_dentry: &Arc) -> Arc { Arc::new_cyclic(|weak_self| Self { - root_dentry, + root_dentry: root_dentry.clone(), mountpoint_dentry: RwLock::new(None), parent: RwLock::new(None), children: Mutex::new(BTreeMap::new()), @@ -111,37 +112,46 @@ impl MountNode { }) } - /// Copies a mount tree starting from the specified root `Dentry_`. + /// Clone a mount tree starting from the specified root `Dentry_`. + /// /// The new mount tree will replicate the structure of the original tree. /// The new tree is a separate entity rooted at the given `Dentry_`, /// and the original tree remains unchanged. - pub fn copy_mount_node_tree(&self, root_dentry: Arc) -> Arc { + /// + /// If `recursive` is set to `true`, the entire tree will be copied. + /// Otherwise, only the root mount node will be copied. + pub(super) fn clone_mount_node_tree( + &self, + root_dentry: &Arc, + recursive: bool, + ) -> Arc { let new_root_mount = self.clone_mount_node(root_dentry); + if !recursive { + return new_root_mount.clone(); + } let mut stack = vec![self.this()]; let mut new_stack = vec![new_root_mount.clone()]; - let mut dentry = new_root_mount.root_dentry.clone(); while let Some(old_mount) = stack.pop() { let new_parent_mount = new_stack.pop().unwrap().clone(); let old_children = old_mount.children.lock(); for old_child_mount in old_children.values() { let mountpoint_dentry = old_child_mount.mountpoint_dentry().unwrap(); - if !dentry.is_subdir(mountpoint_dentry.clone()) { + if !mountpoint_dentry.is_descendant_of(old_mount.root_dentry()) { continue; } - stack.push(old_child_mount.clone()); let new_child_mount = - old_child_mount.clone_mount_node(old_child_mount.root_dentry.clone()); + old_child_mount.clone_mount_node(old_child_mount.root_dentry()); let key = mountpoint_dentry.key(); new_parent_mount .children .lock() .insert(key, new_child_mount.clone()); - new_child_mount.set_parent(new_parent_mount.clone()); + new_child_mount.set_parent(&new_parent_mount); new_child_mount - .set_mountpoint_dentry(old_child_mount.mountpoint_dentry().unwrap().clone()); + .set_mountpoint_dentry(&old_child_mount.mountpoint_dentry().unwrap()); + stack.push(old_child_mount.clone()); new_stack.push(new_child_mount.clone()); - dentry = new_child_mount.root_dentry.clone(); } } new_root_mount.clone() @@ -159,24 +169,24 @@ impl MountNode { } /// Attach the mount node to the mountpoint. - fn attach_mount_node(&self, mountpoint: Arc) { + fn attach_mount_node(&self, mountpoint: &Arc) { let key = mountpoint.key(); mountpoint .mount_node() .children .lock() .insert(key, self.this()); - self.set_parent(mountpoint.mount_node().clone()); + self.set_parent(mountpoint.mount_node()); mountpoint.set_mountpoint(self.this()); } /// Graft the mount node tree to the mountpoint. - pub fn graft_mount_node_tree(&self, mountpoint: Arc) -> Result<()> { + pub fn graft_mount_node_tree(&self, mountpoint: &Arc) -> Result<()> { if mountpoint.type_() != InodeType::Dir { return_errno!(Errno::ENOTDIR); } self.detach_mount_node(); - self.attach_mount_node(mountpoint.clone()); + self.attach_mount_node(mountpoint); Ok(()) } @@ -188,12 +198,12 @@ impl MountNode { self.children.lock().get(&mountpoint.key()).cloned() } - /// Get the root Dentry_ of this mount node. + /// Get the root `Dentry_` of this mount node. pub fn root_dentry(&self) -> &Arc { &self.root_dentry } - /// Try to get the mountpoint Dentry_ of this mount node. + /// Try to get the mountpoint `Dentry_` of this mount node. pub fn mountpoint_dentry(&self) -> Option> { self.mountpoint_dentry.read().clone() } @@ -202,9 +212,9 @@ impl MountNode { /// /// In some cases we may need to reset the mountpoint of /// the created MountNode, such as move mount. - pub fn set_mountpoint_dentry(&self, inner: Arc) { + pub fn set_mountpoint_dentry(&self, inner: &Arc) { let mut mountpoint_dentry = self.mountpoint_dentry.write(); - *mountpoint_dentry = Some(inner); + *mountpoint_dentry = Some(inner.clone()); } /// Flushes all pending filesystem metadata and cached file data to the device. @@ -228,9 +238,9 @@ impl MountNode { /// /// In some cases we may need to reset the parent of /// the created MountNode, such as move mount. - pub fn set_parent(&self, mount_node: Arc) { + pub fn set_parent(&self, mount_node: &Arc) { let mut parent = self.parent.write(); - *parent = Some(Arc::downgrade(&mount_node)); + *parent = Some(Arc::downgrade(mount_node)); } /// Get strong reference to self. diff --git a/kernel/aster-nix/src/syscall/arch/x86.rs b/kernel/aster-nix/src/syscall/arch/x86.rs index 4af57d68e..828fc6893 100644 --- a/kernel/aster-nix/src/syscall/arch/x86.rs +++ b/kernel/aster-nix/src/syscall/arch/x86.rs @@ -228,7 +228,7 @@ impl_syscall_nums_and_dispatch_fn! { SYS_CHROOT = 161 => sys_chroot(args[..1]); SYS_SYNC = 162 => sys_sync(args[..0]); SYS_MOUNT = 165 => sys_mount(args[..5]); - SYS_UMOUNT = 166 => sys_umount(args[..2]); + SYS_UMOUNT2 = 166 => sys_umount(args[..2]); SYS_GETTID = 186 => sys_gettid(args[..0]); SYS_TIME = 201 => sys_time(args[..1]); SYS_FUTEX = 202 => sys_futex(args[..6]); diff --git a/kernel/aster-nix/src/syscall/mount.rs b/kernel/aster-nix/src/syscall/mount.rs index 88c56bdc0..2e9818a94 100644 --- a/kernel/aster-nix/src/syscall/mount.rs +++ b/kernel/aster-nix/src/syscall/mount.rs @@ -14,10 +14,10 @@ use crate::{ util::read_cstring_from_user, }; -/// The data argument is interpreted by the different filesystems. +/// The `data` argument is interpreted by the different filesystems. /// Typically it is a string of comma-separated options understood by /// this filesystem. The current implementation only considers the case -/// where it is NULL. Because it should be interpreted by the specific filesystems. +/// where it is `NULL`. Because it should be interpreted by the specific filesystems. pub fn sys_mount( devname_addr: Vaddr, dirname_addr: Vaddr, @@ -34,7 +34,7 @@ pub fn sys_mount( ); let current = current!(); - let target_dentry = { + let dst_dentry = { let dirname = dirname.to_string_lossy(); if dirname.is_empty() { return_errno_with_message!(Errno::ENOENT, "dirname is empty"); @@ -48,9 +48,9 @@ pub fn sys_mount( } else if mount_flags.contains(MountFlags::MS_REMOUNT) { do_remount()?; } else if mount_flags.contains(MountFlags::MS_BIND) { - do_loopback( - devname.clone(), - target_dentry.clone(), + do_bind_mount( + devname, + dst_dentry, mount_flags.contains(MountFlags::MS_REC), )?; } else if mount_flags.contains(MountFlags::MS_SHARED) @@ -60,69 +60,69 @@ pub fn sys_mount( { do_change_type()?; } else if mount_flags.contains(MountFlags::MS_MOVE) { - do_move_mount_old(devname, target_dentry)?; + do_move_mount_old(devname, dst_dentry)?; } else { - do_new_mount(devname, fstype_addr, target_dentry)?; + do_new_mount(devname, fstype_addr, dst_dentry)?; } Ok(SyscallReturn::Return(0)) } fn do_reconfigure_mnt() -> Result<()> { - todo!() + return_errno_with_message!(Errno::EINVAL, "do_reconfigure_mnt is not supported"); } fn do_remount() -> Result<()> { - todo!() + return_errno_with_message!(Errno::EINVAL, "do_remount is not supported"); } -/// Bind a mount to a new location. -fn do_loopback(old_name: CString, new_dentry: Arc, recursive: bool) -> Result<()> { +/// Bind a mount to a dst location. +/// +/// If recursive is true, then bind the mount recursively. +/// Such as use user command `mount --rbind src dst`. +fn do_bind_mount(src_name: CString, dst_dentry: Arc, recursive: bool) -> Result<()> { let current = current!(); - let old_dentry = { - let old_name = old_name.to_string_lossy(); - if old_name.is_empty() { - return_errno_with_message!(Errno::ENOENT, "old_name is empty"); + let src_dentry = { + let src_name = src_name.to_string_lossy(); + if src_name.is_empty() { + return_errno_with_message!(Errno::ENOENT, "src_name is empty"); } - let fs_path = FsPath::new(AT_FDCWD, old_name.as_ref())?; + let fs_path = FsPath::new(AT_FDCWD, src_name.as_ref())?; current.fs().read().lookup(&fs_path)? }; - if old_dentry.type_() != InodeType::Dir { - return_errno_with_message!(Errno::ENOTDIR, "old_name must be directory"); + if src_dentry.type_() != InodeType::Dir { + return_errno_with_message!(Errno::ENOTDIR, "src_name must be directory"); }; - let new_mount = old_dentry.do_loopback(recursive); - new_mount.graft_mount_node_tree(new_dentry.clone())?; + src_dentry.bind_mount_to(&dst_dentry, recursive)?; Ok(()) } fn do_change_type() -> Result<()> { - todo!() + return_errno_with_message!(Errno::EINVAL, "do_change_type is not supported"); } -/// Move a mount from old location to new location. -fn do_move_mount_old(old_name: CString, new_dentry: Arc) -> Result<()> { +/// Move a mount from src location to dst location. +fn do_move_mount_old(src_name: CString, dst_dentry: Arc) -> Result<()> { let current = current!(); - let old_dentry = { - let old_name = old_name.to_string_lossy(); - if old_name.is_empty() { - return_errno_with_message!(Errno::ENOENT, "old_name is empty"); + let src_dentry = { + let src_name = src_name.to_string_lossy(); + if src_name.is_empty() { + return_errno_with_message!(Errno::ENOENT, "src_name is empty"); } - let fs_path = FsPath::new(AT_FDCWD, old_name.as_ref())?; + let fs_path = FsPath::new(AT_FDCWD, src_name.as_ref())?; current.fs().read().lookup(&fs_path)? }; - if !old_dentry.is_root_of_mount() { - return_errno_with_message!(Errno::EINVAL, "old_name can not be moved"); + if !src_dentry.is_root_of_mount() { + return_errno_with_message!(Errno::EINVAL, "src_name can not be moved"); }; - if old_dentry.mount_node().parent().is_none() { - return_errno_with_message!(Errno::EINVAL, "old_name can not be moved"); + if src_dentry.mount_node().parent().is_none() { + return_errno_with_message!(Errno::EINVAL, "src_name can not be moved"); } - old_dentry - .mount_node() - .graft_mount_node_tree(new_dentry.clone())?; + src_dentry.mount_node().graft_mount_node_tree(&dst_dentry)?; Ok(()) } @@ -165,27 +165,27 @@ fn get_fs(fs_type: CString, devname: CString) -> Result> { bitflags! { struct MountFlags: u32 { - const MS_RDONLY = 1; /* Mount read-only */ - const MS_NOSUID = 1<<1; /* Ignore suid and sgid bits */ - const MS_NODEV = 1<<2; /* Disallow access to device special files */ - const MS_NOEXEC = 1<<3; /* Disallow program execution */ - const MS_SYNCHRONOUS = 1<<4; /* Writes are synced at once */ - const MS_REMOUNT = 1<<5; /* Alter flags of a mounted FS */ - const MS_MANDLOCK = 1<<6; /* Allow mandatory locks on an FS */ - const MS_DIRSYNC = 1<<7; /* Directory modifications are synchronous */ - const MS_NOSYMFOLLOW = 1<<8; /* Do not follow symlinks */ - const MS_NOATIME = 1<<10; /* Do not update access times. */ - const MS_NODIRATIME = 1<<11; /* Do not update directory access times. */ - const MS_BIND = 1<<12; /* Bind directory at different place. */ - const MS_MOVE = 1<<13; /* Move mount from old to new. */ - const MS_REC = 1<<14; /* Create recursive mount. */ - const MS_SILENT = 1<<15; /* Suppress certain messages in kernel log. */ - const MS_POSIXACL = 1<<16; /* VFS does not apply the umask. */ - const MS_UNBINDABLE = 1<<17; /* Change to unbindable. */ - const MS_PRIVATE = 1<<18; /* Change to private. */ - const MS_SLAVE = 1<<19; /* Change to slave. */ - const MS_SHARED = 1<<20; /* Change to shared. */ - const MS_RELATIME = 1<<21; /* Update atime relative to mtime/ctime. */ - const MS_KERNMOUNT = 1<<22; /* This is a kern_mount call. */ + const MS_RDONLY = 1 << 0; // Mount read-only */ + const MS_NOSUID = 1 << 1; // Ignore suid and sgid bits */ + const MS_NODEV = 1 << 2; // Disallow access to device special files */ + const MS_NOEXEC = 1 << 3; // Disallow program execution */ + const MS_SYNCHRONOUS = 1 << 4; // Writes are synced at once + const MS_REMOUNT = 1 << 5; // Alter flags of a mounted FS. + const MS_MANDLOCK = 1 << 6; // Allow mandatory locks on an FS. + const MS_DIRSYNC = 1 << 7; // Directory modifications are synchronous + const MS_NOSYMFOLLOW = 1 << 8; // Do not follow symlinks. + const MS_NOATIME = 1 << 10; // Do not update access times. + const MS_NODIRATIME = 1 << 11; // Do not update directory access times. + const MS_BIND = 1 << 12; // Bind directory at different place. + const MS_MOVE = 1 << 13; // Move mount from old to new. + const MS_REC = 1 << 14; // Create recursive mount. + const MS_SILENT = 1 << 15; // Suppress certain messages in kernel log. + const MS_POSIXACL = 1 << 16; // VFS does not apply the umask. + const MS_UNBINDABLE = 1 << 17; // Change to unbindable. + const MS_PRIVATE = 1 << 18; // Change to private. + const MS_SLAVE = 1 << 19; // Change to slave. + const MS_SHARED = 1 << 20; // Change to shared. + const MS_RELATIME = 1 << 21; // Update atime relative to mtime/ctime. + const MS_KERNMOUNT = 1 << 22; // This is a kern_mount call. } } diff --git a/kernel/aster-nix/src/syscall/umount.rs b/kernel/aster-nix/src/syscall/umount.rs index 99896a79c..089e4467f 100644 --- a/kernel/aster-nix/src/syscall/umount.rs +++ b/kernel/aster-nix/src/syscall/umount.rs @@ -28,17 +28,17 @@ pub fn sys_umount(path_addr: Vaddr, flags: u64) -> Result { current.fs().read().lookup(&fs_path)? }; - target_dentry.umount()?; + target_dentry.unmount()?; Ok(SyscallReturn::Return(0)) } bitflags! { struct UmountFlags: u32 { - const MNT_FORCE = 0x00000001; /* Attempt to forcibily umount */ - const MNT_DETACH = 0x00000002; /* Just detach from the tree */ - const MNT_EXPIRE = 0x00000004; /* Mark for expiry */ - const UMOUNT_NOFOLLOW = 0x00000008; /* Don't follow symlink on umount */ + const MNT_FORCE = 0x00000001; // Attempt to forcibily umount. + const MNT_DETACH = 0x00000002; // Just detach from the tree. + const MNT_EXPIRE = 0x00000004; // Mark for expiry. + const UMOUNT_NOFOLLOW = 0x00000008; // Don't follow symlink on umount. } }