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 | ✅ |
| 163 | acct | ❌ |
| 164 | settimeofday | ❌ |
| 165 | mount | |
| 166 | umount2 | |
| 165 | mount | |
| 166 | umount2 | |
| 167 | swapon | ❌ |
| 168 | swapoff | ❌ |
| 169 | reboot | ❌ |

View File

@ -23,7 +23,6 @@ use crate::{
exfat::{ExfatFS, ExfatMountOptions},
ext2::Ext2,
fs_resolver::FsPath,
utils::FileSystem,
},
prelude::*,
thread::kernel_thread::KernelThreadExt,
@ -65,26 +64,3 @@ pub fn lazy_init() {
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> {
if recursive {
self.mount_node.copy_mount_tree(self.inner.clone())
self.mount_node.copy_mount_node_tree(self.inner.clone())
} 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_.
/// The new mount node will have the same fs as the original one.
/// The new mount node root Dentry_ will be the given one.
/// The new mount node will have no parent and children.
/// We should set the parent and children manually.
pub fn clone_mount(&self, root_dentry: Arc<Dentry_>) -> Arc<Self> {
/// 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<Dentry_>) -> Arc<Self> {
Arc::new_cyclic(|weak_self| Self {
root_dentry,
mountpoint_dentry: RwLock::new(None),
@ -113,12 +111,12 @@ impl MountNode {
})
}
/// Copy a mount tree with the given root Dentry_.
/// The new mount tree will have the same structure as the original one.
/// But the new mount tree is a subtree which is rooted at the given root Dentry_.
/// The new mount tree is a new tree, which means the original one is not affected.
pub fn copy_mount_tree(&self, root_dentry: Arc<Dentry_>) -> Arc<Self> {
let new_root_mount = self.clone_mount(root_dentry);
/// Copies 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<Dentry_>) -> Arc<Self> {
let new_root_mount = self.clone_mount_node(root_dentry);
let mut stack = vec![self.this()];
let mut new_stack = vec![new_root_mount.clone()];
@ -133,7 +131,7 @@ impl MountNode {
}
stack.push(old_child_mount.clone());
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();
new_parent_mount
.children
@ -149,8 +147,8 @@ impl MountNode {
new_root_mount.clone()
}
/// Unattach the mount node from the parent mount node.
fn unattach_mount(&self) {
/// Detach the mount node from the parent mount node.
fn detach_mount_node(&self) {
if let Some(parent) = self.parent() {
let parent = parent.upgrade().unwrap();
parent
@ -161,7 +159,7 @@ impl MountNode {
}
/// 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();
mountpoint
.mount_node()
@ -172,13 +170,13 @@ impl MountNode {
mountpoint.set_mountpoint(self.this());
}
/// Graft the mount tree to the mountpoint.
pub fn graft_mount_tree(&self, mountpoint: Arc<Dentry>) -> Result<()> {
/// Graft the mount node tree to the mountpoint.
pub fn graft_mount_node_tree(&self, mountpoint: Arc<Dentry>) -> Result<()> {
if mountpoint.type_() != InodeType::Dir {
return_errno!(Errno::ENOTDIR);
}
self.unattach_mount();
self.attach_mount(mountpoint.clone());
self.detach_mount_node();
self.attach_mount_node(mountpoint.clone());
Ok(())
}

View File

@ -109,6 +109,7 @@ use crate::syscall::{
timer_settime::{sys_timer_gettime, sys_timer_settime},
truncate::{sys_ftruncate, sys_truncate},
umask::sys_umask,
umount::sys_umount,
uname::sys_uname,
unlink::{sys_unlink, sys_unlinkat},
utimens::sys_utimensat,
@ -227,6 +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_GETTID = 186 => sys_gettid(args[..0]);
SYS_TIME = 201 => sys_time(args[..1]);
SYS_FUTEX = 202 => sys_futex(args[..6]);

View File

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

View File

@ -3,14 +3,21 @@
use super::SyscallReturn;
use crate::{
fs::{
exfat::{ExfatFS, ExfatMountOptions},
ext2::Ext2,
fs_resolver::{FsPath, AT_FDCWD},
path::Dentry,
utils::{FileSystem, InodeType},
},
prelude::*,
syscall::constants::MAX_FILENAME_LEN,
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(
devname_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)?
};
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);
new_mount.graft_mount_tree(new_dentry.clone())?;
new_mount.graft_mount_node_tree(new_dentry.clone())?;
Ok(())
}
@ -111,23 +122,47 @@ fn do_move_mount_old(old_name: CString, new_dentry: Arc<Dentry>) -> Result<()> {
old_dentry
.mount_node()
.graft_mount_tree(new_dentry.clone())?;
.graft_mount_node_tree(new_dentry.clone())?;
Ok(())
}
/// Mount a new filesystem.
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)?;
if fs_type.is_empty() {
return_errno_with_message!(Errno::EINVAL, "fs_type is empty");
}
let fs_type = fs_type.to_str().unwrap();
let fs = crate::fs::get_fs(fs_type)?;
let fs = get_fs(fs_type, devname)?;
target_dentry.mount(fs)?;
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! {
struct MountFlags: u32 {
const MS_RDONLY = 1; /* Mount read-only */
@ -137,16 +172,14 @@ bitflags! {
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_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_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;
const MS_VERBOSE = 1<<15; /* War is peace. Verbosity is silence. MS_VERBOSE is deprecated. */
const MS_SILENT = 1<<15;
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. */

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(())
}
}