mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 17:03:23 +00:00
Add syscall umount.
Signed-off-by: Zhenchen Wang <m202372036@hust.edu.cn>
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
a893ceca4a
commit
980ffb5a98
@ -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 | ❌ |
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(())
|
||||
}
|
||||
|
||||
|
@ -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]);
|
||||
|
@ -116,6 +116,7 @@ mod timer_create;
|
||||
mod timer_settime;
|
||||
mod truncate;
|
||||
mod umask;
|
||||
mod umount;
|
||||
mod uname;
|
||||
mod unlink;
|
||||
mod utimens;
|
||||
|
@ -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. */
|
||||
|
57
kernel/aster-nix/src/syscall/umount.rs
Normal file
57
kernel/aster-nix/src/syscall/umount.rs
Normal 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(())
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user