Add syscall umount.

Signed-off-by: Zhenchen Wang <m202372036@hust.edu.cn>
This commit is contained in:
Zhenchen Wang
2024-05-18 13:43:19 +08:00
committed by Tate, Hongliang Tian
parent a893ceca4a
commit 980ffb5a98
8 changed files with 123 additions and 56 deletions

View File

@ -185,8 +185,8 @@ provided by Linux on x86-64 architecture.
| 162 | sync | ✅ | | 162 | sync | ✅ |
| 163 | acct | ❌ | | 163 | acct | ❌ |
| 164 | settimeofday | ❌ | | 164 | settimeofday | ❌ |
| 165 | mount | | | 165 | mount | |
| 166 | umount2 | | | 166 | umount2 | |
| 167 | swapon | ❌ | | 167 | swapon | ❌ |
| 168 | swapoff | ❌ | | 168 | swapoff | ❌ |
| 169 | reboot | ❌ | | 169 | reboot | ❌ |

View File

@ -23,7 +23,6 @@ use crate::{
exfat::{ExfatFS, ExfatMountOptions}, exfat::{ExfatFS, ExfatMountOptions},
ext2::Ext2, ext2::Ext2,
fs_resolver::FsPath, fs_resolver::FsPath,
utils::FileSystem,
}, },
prelude::*, prelude::*,
thread::kernel_thread::KernelThreadExt, thread::kernel_thread::KernelThreadExt,
@ -65,26 +64,3 @@ pub fn lazy_init() {
self::rootfs::mount_fs_at(exfat_fs, &target_path).unwrap(); self::rootfs::mount_fs_at(exfat_fs, &target_path).unwrap();
} }
} }
pub fn get_fs(fs_type: &str) -> Result<Arc<dyn FileSystem>> {
match fs_type {
"ext2" => {
if let Ok(block_device_ext2) = start_block_device("vext2") {
let ext2_fs = Ext2::open(block_device_ext2).unwrap();
Ok(ext2_fs)
} else {
return_errno_with_message!(Errno::EINVAL, "Ext2 fs does not exist")
}
}
"exfat" => {
if let Ok(block_device_exfat) = start_block_device("vexfat") {
let exfat_fs =
ExfatFS::open(block_device_exfat, ExfatMountOptions::default()).unwrap();
Ok(exfat_fs)
} else {
return_errno_with_message!(Errno::EINVAL, "Exfat fs dose not exist")
}
}
_ => return_errno_with_message!(Errno::EINVAL, "Invalid fs type"),
}
}

View File

@ -652,9 +652,9 @@ impl Dentry {
pub fn do_loopback(&self, recursive: bool) -> Arc<MountNode> { pub fn do_loopback(&self, recursive: bool) -> Arc<MountNode> {
if recursive { if recursive {
self.mount_node.copy_mount_tree(self.inner.clone()) self.mount_node.copy_mount_node_tree(self.inner.clone())
} else { } else {
self.mount_node.clone_mount(self.inner.clone()) self.mount_node.clone_mount_node(self.inner.clone())
} }
} }

View File

@ -98,11 +98,9 @@ impl MountNode {
} }
/// 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. /// The new mount node will have the same fs as the original one and
/// The new mount node root Dentry_ will be the given one. /// have no parent and children. We should set the parent and children manually.
/// The new mount node will have no parent and children. pub fn clone_mount_node(&self, root_dentry: Arc<Dentry_>) -> Arc<Self> {
/// We should set the parent and children manually.
pub fn clone_mount(&self, root_dentry: Arc<Dentry_>) -> Arc<Self> {
Arc::new_cyclic(|weak_self| Self { Arc::new_cyclic(|weak_self| Self {
root_dentry, root_dentry,
mountpoint_dentry: RwLock::new(None), mountpoint_dentry: RwLock::new(None),
@ -113,12 +111,12 @@ impl MountNode {
}) })
} }
/// Copy a mount tree with the given root Dentry_. /// Copies a mount tree starting from the specified root `Dentry_`.
/// The new mount tree will have the same structure as the original one. /// The new mount tree will replicate the structure of the original tree.
/// But the new mount tree is a subtree which is rooted at the given root Dentry_. /// The new tree is a separate entity rooted at the given `Dentry_`,
/// The new mount tree is a new tree, which means the original one is not affected. /// and the original tree remains unchanged.
pub fn copy_mount_tree(&self, root_dentry: Arc<Dentry_>) -> Arc<Self> { pub fn copy_mount_node_tree(&self, root_dentry: Arc<Dentry_>) -> Arc<Self> {
let new_root_mount = self.clone_mount(root_dentry); let new_root_mount = self.clone_mount_node(root_dentry);
let mut stack = vec![self.this()]; let mut stack = vec![self.this()];
let mut new_stack = vec![new_root_mount.clone()]; let mut new_stack = vec![new_root_mount.clone()];
@ -133,7 +131,7 @@ impl MountNode {
} }
stack.push(old_child_mount.clone()); stack.push(old_child_mount.clone());
let new_child_mount = let new_child_mount =
old_child_mount.clone_mount(old_child_mount.root_dentry.clone()); old_child_mount.clone_mount_node(old_child_mount.root_dentry.clone());
let key = mountpoint_dentry.key(); let key = mountpoint_dentry.key();
new_parent_mount new_parent_mount
.children .children
@ -149,8 +147,8 @@ impl MountNode {
new_root_mount.clone() new_root_mount.clone()
} }
/// Unattach the mount node from the parent mount node. /// Detach the mount node from the parent mount node.
fn unattach_mount(&self) { fn detach_mount_node(&self) {
if let Some(parent) = self.parent() { if let Some(parent) = self.parent() {
let parent = parent.upgrade().unwrap(); let parent = parent.upgrade().unwrap();
parent parent
@ -161,7 +159,7 @@ impl MountNode {
} }
/// Attach the mount node to the mountpoint. /// Attach the mount node to the mountpoint.
fn attach_mount(&self, mountpoint: Arc<Dentry>) { fn attach_mount_node(&self, mountpoint: Arc<Dentry>) {
let key = mountpoint.key(); let key = mountpoint.key();
mountpoint mountpoint
.mount_node() .mount_node()
@ -172,13 +170,13 @@ impl MountNode {
mountpoint.set_mountpoint(self.this()); mountpoint.set_mountpoint(self.this());
} }
/// Graft the mount tree to the mountpoint. /// Graft the mount node tree to the mountpoint.
pub fn graft_mount_tree(&self, mountpoint: Arc<Dentry>) -> Result<()> { pub fn graft_mount_node_tree(&self, mountpoint: Arc<Dentry>) -> Result<()> {
if mountpoint.type_() != InodeType::Dir { if mountpoint.type_() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
self.unattach_mount(); self.detach_mount_node();
self.attach_mount(mountpoint.clone()); self.attach_mount_node(mountpoint.clone());
Ok(()) Ok(())
} }

View File

@ -109,6 +109,7 @@ use crate::syscall::{
timer_settime::{sys_timer_gettime, sys_timer_settime}, timer_settime::{sys_timer_gettime, sys_timer_settime},
truncate::{sys_ftruncate, sys_truncate}, truncate::{sys_ftruncate, sys_truncate},
umask::sys_umask, umask::sys_umask,
umount::sys_umount,
uname::sys_uname, uname::sys_uname,
unlink::{sys_unlink, sys_unlinkat}, unlink::{sys_unlink, sys_unlinkat},
utimens::sys_utimensat, utimens::sys_utimensat,
@ -227,6 +228,7 @@ impl_syscall_nums_and_dispatch_fn! {
SYS_CHROOT = 161 => sys_chroot(args[..1]); SYS_CHROOT = 161 => sys_chroot(args[..1]);
SYS_SYNC = 162 => sys_sync(args[..0]); SYS_SYNC = 162 => sys_sync(args[..0]);
SYS_MOUNT = 165 => sys_mount(args[..5]); SYS_MOUNT = 165 => sys_mount(args[..5]);
SYS_UMOUNT = 166 => sys_umount(args[..2]);
SYS_GETTID = 186 => sys_gettid(args[..0]); SYS_GETTID = 186 => sys_gettid(args[..0]);
SYS_TIME = 201 => sys_time(args[..1]); SYS_TIME = 201 => sys_time(args[..1]);
SYS_FUTEX = 202 => sys_futex(args[..6]); SYS_FUTEX = 202 => sys_futex(args[..6]);

View File

@ -116,6 +116,7 @@ mod timer_create;
mod timer_settime; mod timer_settime;
mod truncate; mod truncate;
mod umask; mod umask;
mod umount;
mod uname; mod uname;
mod unlink; mod unlink;
mod utimens; mod utimens;

View File

@ -3,14 +3,21 @@
use super::SyscallReturn; use super::SyscallReturn;
use crate::{ use crate::{
fs::{ fs::{
exfat::{ExfatFS, ExfatMountOptions},
ext2::Ext2,
fs_resolver::{FsPath, AT_FDCWD}, fs_resolver::{FsPath, AT_FDCWD},
path::Dentry, path::Dentry,
utils::{FileSystem, InodeType},
}, },
prelude::*, prelude::*,
syscall::constants::MAX_FILENAME_LEN, syscall::constants::MAX_FILENAME_LEN,
util::read_cstring_from_user, util::read_cstring_from_user,
}; };
/// 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.
pub fn sys_mount( pub fn sys_mount(
devname_addr: Vaddr, devname_addr: Vaddr,
dirname_addr: Vaddr, dirname_addr: Vaddr,
@ -81,8 +88,12 @@ fn do_loopback(old_name: CString, new_dentry: Arc<Dentry>, recursive: bool) -> R
current.fs().read().lookup(&fs_path)? current.fs().read().lookup(&fs_path)?
}; };
if old_dentry.type_() != InodeType::Dir {
return_errno_with_message!(Errno::ENOTDIR, "old_name must be directory");
};
let new_mount = old_dentry.do_loopback(recursive); let new_mount = old_dentry.do_loopback(recursive);
new_mount.graft_mount_tree(new_dentry.clone())?; new_mount.graft_mount_node_tree(new_dentry.clone())?;
Ok(()) Ok(())
} }
@ -111,23 +122,47 @@ fn do_move_mount_old(old_name: CString, new_dentry: Arc<Dentry>) -> Result<()> {
old_dentry old_dentry
.mount_node() .mount_node()
.graft_mount_tree(new_dentry.clone())?; .graft_mount_node_tree(new_dentry.clone())?;
Ok(()) Ok(())
} }
/// Mount a new filesystem. /// Mount a new filesystem.
fn do_new_mount(devname: CString, fs_type: Vaddr, target_dentry: Arc<Dentry>) -> Result<()> { fn do_new_mount(devname: CString, fs_type: Vaddr, target_dentry: Arc<Dentry>) -> Result<()> {
if target_dentry.type_() != InodeType::Dir {
return_errno_with_message!(Errno::ENOTDIR, "mountpoint must be directory");
};
let fs_type = read_cstring_from_user(fs_type, MAX_FILENAME_LEN)?; let fs_type = read_cstring_from_user(fs_type, MAX_FILENAME_LEN)?;
if fs_type.is_empty() { if fs_type.is_empty() {
return_errno_with_message!(Errno::EINVAL, "fs_type is empty"); return_errno_with_message!(Errno::EINVAL, "fs_type is empty");
} }
let fs_type = fs_type.to_str().unwrap(); let fs = get_fs(fs_type, devname)?;
let fs = crate::fs::get_fs(fs_type)?;
target_dentry.mount(fs)?; target_dentry.mount(fs)?;
Ok(()) Ok(())
} }
/// Get the filesystem by fs_type and devname.
fn get_fs(fs_type: CString, devname: CString) -> Result<Arc<dyn FileSystem>> {
let devname = devname.to_str().unwrap();
let device = match aster_block::get_device(devname) {
Some(device) => device,
None => return_errno_with_message!(Errno::ENOENT, "Device does not exist"),
};
let fs_type = fs_type.to_str().unwrap();
match fs_type {
"ext2" => {
let ext2_fs = Ext2::open(device)?;
Ok(ext2_fs)
}
"exfat" => {
let exfat_fs = ExfatFS::open(device, ExfatMountOptions::default())?;
Ok(exfat_fs)
}
_ => return_errno_with_message!(Errno::EINVAL, "Invalid fs type"),
}
}
bitflags! { bitflags! {
struct MountFlags: u32 { struct MountFlags: u32 {
const MS_RDONLY = 1; /* Mount read-only */ const MS_RDONLY = 1; /* Mount read-only */
@ -137,16 +172,14 @@ bitflags! {
const MS_SYNCHRONOUS = 1<<4; /* Writes are synced at once */ const MS_SYNCHRONOUS = 1<<4; /* Writes are synced at once */
const MS_REMOUNT = 1<<5; /* Alter flags of a mounted FS */ const MS_REMOUNT = 1<<5; /* Alter flags of a mounted FS */
const MS_MANDLOCK = 1<<6; /* Allow mandatory locks on an FS */ const MS_MANDLOCK = 1<<6; /* Allow mandatory locks on an FS */
const MS_DIRSYNS = 1<<7; /* Directory modifications are synchronous */ const MS_DIRSYNC = 1<<7; /* Directory modifications are synchronous */
const MS_NOSYMFOLLOW = 1<<8; /* Do not follow symlinks */ const MS_NOSYMFOLLOW = 1<<8; /* Do not follow symlinks */
const MS_NOATIME = 1<<10; /* Do not update access times. */ const MS_NOATIME = 1<<10; /* Do not update access times. */
const MS_NODIRATIME = 1<<11; /* Do not update directory 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_BIND = 1<<12; /* Bind directory at different place. */
const MS_MOVE = 1<<13; /* Move mount from old to new. */ const MS_MOVE = 1<<13; /* Move mount from old to new. */
const MS_REC = 1<<14; const MS_REC = 1<<14; /* Create recursive mount. */
const MS_VERBOSE = 1<<15; /* War is peace. Verbosity is silence. MS_VERBOSE is deprecated. */ const MS_SILENT = 1<<15; /* Suppress certain messages in kernel log. */
const MS_SILENT = 1<<15;
const MS_POSIXACL = 1<<16; /* VFS does not apply the umask. */ const MS_POSIXACL = 1<<16; /* VFS does not apply the umask. */
const MS_UNBINDABLE = 1<<17; /* Change to unbindable. */ const MS_UNBINDABLE = 1<<17; /* Change to unbindable. */
const MS_PRIVATE = 1<<18; /* Change to private. */ const MS_PRIVATE = 1<<18; /* Change to private. */

View File

@ -0,0 +1,57 @@
// SPDX-License-Identifier: MPL-2.0
use super::SyscallReturn;
use crate::{
fs::fs_resolver::{FsPath, AT_FDCWD},
prelude::*,
syscall::constants::MAX_FILENAME_LEN,
util::read_cstring_from_user,
};
pub fn sys_umount(path_addr: Vaddr, flags: u64) -> Result<SyscallReturn> {
let path = read_cstring_from_user(path_addr, MAX_FILENAME_LEN)?;
let umount_flags = UmountFlags::from_bits_truncate(flags as u32);
debug!("path = {:?}, flags = {:?}", path, umount_flags);
umount_flags.check_unsupported_flags()?;
let current = current!();
let path = path.to_string_lossy();
if path.is_empty() {
return_errno_with_message!(Errno::ENOENT, "path is empty");
}
let fs_path = FsPath::new(AT_FDCWD, path.as_ref())?;
let target_dentry = if umount_flags.contains(UmountFlags::UMOUNT_NOFOLLOW) {
current.fs().read().lookup_no_follow(&fs_path)?
} else {
current.fs().read().lookup(&fs_path)?
};
target_dentry.umount()?;
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 */
}
}
impl UmountFlags {
fn check_unsupported_flags(&self) -> Result<()> {
let supported_flags = UmountFlags::MNT_FORCE
| UmountFlags::MNT_DETACH
| UmountFlags::MNT_EXPIRE
| UmountFlags::UMOUNT_NOFOLLOW;
let unsupported_flags = *self - supported_flags;
if !unsupported_flags.is_empty() {
return_errno_with_message!(Errno::EINVAL, "unsupported flags");
}
Ok(())
}
}