mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-23 09:23:25 +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 | ✅ |
|
| 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 | ❌ |
|
||||||
|
@ -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"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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]);
|
||||||
|
@ -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;
|
||||||
|
@ -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. */
|
||||||
|
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