2024-05-17 03:19:36 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
|
|
|
|
use super::SyscallReturn;
|
|
|
|
|
use crate::{
|
|
|
|
|
fs::{
|
|
|
|
|
fs_resolver::{FsPath, AT_FDCWD},
|
2025-09-02 07:05:24 +00:00
|
|
|
path::{MountPropType, Path},
|
2025-07-17 03:24:35 +00:00
|
|
|
registry::FsProperties,
|
2024-05-18 05:43:19 +00:00
|
|
|
utils::{FileSystem, InodeType},
|
2024-05-17 03:19:36 +00:00
|
|
|
},
|
|
|
|
|
prelude::*,
|
|
|
|
|
syscall::constants::MAX_FILENAME_LEN,
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-02 03:40:53 +00:00
|
|
|
/// The `data` argument is interpreted by the different filesystems.
|
2024-05-18 05:43:19 +00:00
|
|
|
/// Typically it is a string of comma-separated options understood by
|
|
|
|
|
/// this filesystem. The current implementation only considers the case
|
2024-06-02 03:40:53 +00:00
|
|
|
/// where it is `NULL`. Because it should be interpreted by the specific filesystems.
|
2024-05-17 03:19:36 +00:00
|
|
|
pub fn sys_mount(
|
|
|
|
|
devname_addr: Vaddr,
|
|
|
|
|
dirname_addr: Vaddr,
|
|
|
|
|
fstype_addr: Vaddr,
|
|
|
|
|
flags: u64,
|
|
|
|
|
data: Vaddr,
|
2024-08-11 13:35:27 +00:00
|
|
|
ctx: &Context,
|
2024-05-17 03:19:36 +00:00
|
|
|
) -> Result<SyscallReturn> {
|
2024-11-13 15:39:10 +00:00
|
|
|
let user_space = ctx.user_space();
|
2024-08-09 08:11:43 +00:00
|
|
|
let devname = user_space.read_cstring(devname_addr, MAX_FILENAME_LEN)?;
|
|
|
|
|
let dirname = user_space.read_cstring(dirname_addr, MAX_FILENAME_LEN)?;
|
2024-05-17 03:19:36 +00:00
|
|
|
let mount_flags = MountFlags::from_bits_truncate(flags as u32);
|
|
|
|
|
debug!(
|
|
|
|
|
"devname = {:?}, dirname = {:?}, fstype = 0x{:x}, flags = {:?}, data = 0x{:x}",
|
|
|
|
|
devname, dirname, fstype_addr, mount_flags, data,
|
|
|
|
|
);
|
|
|
|
|
|
2025-08-04 03:40:23 +00:00
|
|
|
let dst_path = {
|
2024-05-17 03:19:36 +00:00
|
|
|
let dirname = dirname.to_string_lossy();
|
2025-10-16 15:57:17 +00:00
|
|
|
let fs_path = FsPath::from_fd_and_path(AT_FDCWD, &dirname)?;
|
2025-08-04 09:31:53 +00:00
|
|
|
ctx.thread_local
|
|
|
|
|
.borrow_fs()
|
|
|
|
|
.resolver()
|
|
|
|
|
.read()
|
|
|
|
|
.lookup(&fs_path)?
|
2024-05-17 03:19:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if mount_flags.contains(MountFlags::MS_REMOUNT) && mount_flags.contains(MountFlags::MS_BIND) {
|
|
|
|
|
do_reconfigure_mnt()?;
|
|
|
|
|
} else if mount_flags.contains(MountFlags::MS_REMOUNT) {
|
|
|
|
|
do_remount()?;
|
|
|
|
|
} else if mount_flags.contains(MountFlags::MS_BIND) {
|
2024-06-02 03:40:53 +00:00
|
|
|
do_bind_mount(
|
|
|
|
|
devname,
|
2025-08-04 03:40:23 +00:00
|
|
|
dst_path,
|
2024-05-17 03:19:36 +00:00
|
|
|
mount_flags.contains(MountFlags::MS_REC),
|
2024-08-11 13:35:27 +00:00
|
|
|
ctx,
|
2024-05-17 03:19:36 +00:00
|
|
|
)?;
|
2025-09-02 07:05:24 +00:00
|
|
|
} else if mount_flags.intersects(MS_PROPAGATION) {
|
|
|
|
|
do_change_type(dst_path, mount_flags, ctx)?;
|
2024-05-17 03:19:36 +00:00
|
|
|
} else if mount_flags.contains(MountFlags::MS_MOVE) {
|
2025-08-04 03:40:23 +00:00
|
|
|
do_move_mount_old(devname, dst_path, ctx)?;
|
2024-05-17 03:19:36 +00:00
|
|
|
} else {
|
2025-08-04 03:40:23 +00:00
|
|
|
do_new_mount(devname, fstype_addr, dst_path, data, ctx)?;
|
2024-05-17 03:19:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(SyscallReturn::Return(0))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn do_reconfigure_mnt() -> Result<()> {
|
2024-06-02 03:40:53 +00:00
|
|
|
return_errno_with_message!(Errno::EINVAL, "do_reconfigure_mnt is not supported");
|
2024-05-17 03:19:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn do_remount() -> Result<()> {
|
2024-06-02 03:40:53 +00:00
|
|
|
return_errno_with_message!(Errno::EINVAL, "do_remount is not supported");
|
2024-05-17 03:19:36 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-02 03:40:53 +00:00
|
|
|
/// 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`.
|
2025-08-04 03:40:23 +00:00
|
|
|
fn do_bind_mount(src_name: CString, dst_path: Path, recursive: bool, ctx: &Context) -> Result<()> {
|
|
|
|
|
let src_path = {
|
2024-06-02 03:40:53 +00:00
|
|
|
let src_name = src_name.to_string_lossy();
|
2025-10-16 15:57:17 +00:00
|
|
|
let fs_path = FsPath::from_fd_and_path(AT_FDCWD, &src_name)?;
|
2025-08-04 09:31:53 +00:00
|
|
|
ctx.thread_local
|
|
|
|
|
.borrow_fs()
|
|
|
|
|
.resolver()
|
|
|
|
|
.read()
|
|
|
|
|
.lookup(&fs_path)?
|
2024-05-17 03:19:36 +00:00
|
|
|
};
|
|
|
|
|
|
2025-09-02 05:03:26 +00:00
|
|
|
src_path.bind_mount_to(&dst_path, recursive, ctx)?;
|
2024-05-17 03:19:36 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-02 07:05:24 +00:00
|
|
|
// All valid propagation flags.
|
|
|
|
|
const MS_PROPAGATION: MountFlags = MountFlags::MS_SHARED
|
|
|
|
|
.union(MountFlags::MS_PRIVATE)
|
|
|
|
|
.union(MountFlags::MS_SLAVE)
|
|
|
|
|
.union(MountFlags::MS_UNBINDABLE);
|
|
|
|
|
|
|
|
|
|
fn do_change_type(target_path: Path, flags: MountFlags, ctx: &Context) -> Result<()> {
|
|
|
|
|
// All flags that are allowed during a propagation change.
|
|
|
|
|
const ALLOWED_FLAGS: MountFlags = MS_PROPAGATION
|
|
|
|
|
.union(MountFlags::MS_REC)
|
|
|
|
|
.union(MountFlags::MS_SILENT);
|
|
|
|
|
|
|
|
|
|
if !(flags & !ALLOWED_FLAGS).is_empty() {
|
|
|
|
|
return_errno_with_message!(Errno::EINVAL, "the mount propagation flags are unsupported");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let propagation_flags = flags & MS_PROPAGATION;
|
|
|
|
|
if propagation_flags.bits().count_ones() > 1 {
|
|
|
|
|
return_errno_with_message!(
|
|
|
|
|
Errno::EINVAL,
|
|
|
|
|
"mount flags includes more than one of MS_SHARED, MS_PRIVATE, MS_SLAVE, or MS_UNBINDABLE"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if flags.contains(MountFlags::MS_PRIVATE) {
|
|
|
|
|
let recursive = flags.contains(MountFlags::MS_REC);
|
|
|
|
|
target_path.set_mount_propagation(MountPropType::Private, recursive, ctx)?;
|
|
|
|
|
Ok(())
|
|
|
|
|
} else {
|
|
|
|
|
return_errno_with_message!(Errno::EINVAL, "the mount propagation type is unsupported");
|
|
|
|
|
}
|
2024-05-17 03:19:36 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-02 03:40:53 +00:00
|
|
|
/// Move a mount from src location to dst location.
|
2025-08-04 03:40:23 +00:00
|
|
|
fn do_move_mount_old(src_name: CString, dst_path: Path, ctx: &Context) -> Result<()> {
|
|
|
|
|
let src_path = {
|
2024-06-02 03:40:53 +00:00
|
|
|
let src_name = src_name.to_string_lossy();
|
2025-10-16 15:57:17 +00:00
|
|
|
let fs_path = FsPath::from_fd_and_path(AT_FDCWD, &src_name)?;
|
2025-08-04 09:31:53 +00:00
|
|
|
ctx.thread_local
|
|
|
|
|
.borrow_fs()
|
|
|
|
|
.resolver()
|
|
|
|
|
.read()
|
|
|
|
|
.lookup(&fs_path)?
|
2024-05-17 03:19:36 +00:00
|
|
|
};
|
|
|
|
|
|
2025-09-02 05:03:26 +00:00
|
|
|
src_path.move_mount_to(&dst_path, ctx)?;
|
2024-05-17 03:19:36 +00:00
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Mount a new filesystem.
|
2024-08-11 14:42:17 +00:00
|
|
|
fn do_new_mount(
|
|
|
|
|
devname: CString,
|
|
|
|
|
fs_type: Vaddr,
|
2025-08-04 03:40:23 +00:00
|
|
|
target_path: Path,
|
2025-04-24 07:58:18 +00:00
|
|
|
data: Vaddr,
|
2024-08-11 14:42:17 +00:00
|
|
|
ctx: &Context,
|
|
|
|
|
) -> Result<()> {
|
2025-08-04 03:40:23 +00:00
|
|
|
if target_path.type_() != InodeType::Dir {
|
2024-05-18 05:43:19 +00:00
|
|
|
return_errno_with_message!(Errno::ENOTDIR, "mountpoint must be directory");
|
|
|
|
|
};
|
|
|
|
|
|
2024-11-13 15:39:10 +00:00
|
|
|
let fs_type = ctx.user_space().read_cstring(fs_type, MAX_FILENAME_LEN)?;
|
2024-05-17 03:19:36 +00:00
|
|
|
if fs_type.is_empty() {
|
|
|
|
|
return_errno_with_message!(Errno::EINVAL, "fs_type is empty");
|
|
|
|
|
}
|
2025-04-24 07:58:18 +00:00
|
|
|
let fs = get_fs(fs_type, devname, data, ctx)?;
|
2025-09-02 05:03:26 +00:00
|
|
|
target_path.mount(fs, ctx)?;
|
2024-05-17 03:19:36 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-18 05:43:19 +00:00
|
|
|
/// Get the filesystem by fs_type and devname.
|
2025-04-24 07:58:18 +00:00
|
|
|
fn get_fs(
|
|
|
|
|
fs_type: CString,
|
|
|
|
|
devname: CString,
|
|
|
|
|
data: Vaddr,
|
|
|
|
|
ctx: &Context,
|
|
|
|
|
) -> Result<Arc<dyn FileSystem>> {
|
|
|
|
|
let user_space = ctx.user_space();
|
2025-07-17 03:24:35 +00:00
|
|
|
let data = if data == 0 {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
Some(user_space.read_cstring(data, MAX_FILENAME_LEN)?)
|
|
|
|
|
};
|
2025-04-24 07:58:18 +00:00
|
|
|
|
2025-06-06 09:52:08 +00:00
|
|
|
let fs_type = fs_type
|
|
|
|
|
.to_str()
|
|
|
|
|
.map_err(|_| Error::with_message(Errno::ENODEV, "Invalid file system type"))?;
|
2025-07-17 03:24:35 +00:00
|
|
|
let fs_type = crate::fs::registry::look_up(fs_type)
|
|
|
|
|
.ok_or(Error::with_message(Errno::EINVAL, "Invalid fs type"))?;
|
|
|
|
|
|
|
|
|
|
let disk = if fs_type.properties().contains(FsProperties::NEED_DISK) {
|
|
|
|
|
Some(
|
|
|
|
|
aster_block::get_device(devname.to_str().unwrap())
|
|
|
|
|
.ok_or(Error::with_message(Errno::ENOENT, "device does not exist"))?,
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
2025-04-24 07:58:18 +00:00
|
|
|
|
2025-09-05 02:33:22 +00:00
|
|
|
fs_type.create(data, disk)
|
2025-04-24 07:58:18 +00:00
|
|
|
}
|
|
|
|
|
|
2024-05-17 03:19:36 +00:00
|
|
|
bitflags! {
|
|
|
|
|
struct MountFlags: u32 {
|
2024-06-27 02:14:19 +00:00
|
|
|
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.
|
2024-06-02 03:40:53 +00:00
|
|
|
const MS_REMOUNT = 1 << 5; // Alter flags of a mounted FS.
|
|
|
|
|
const MS_MANDLOCK = 1 << 6; // Allow mandatory locks on an FS.
|
2024-06-27 02:14:19 +00:00
|
|
|
const MS_DIRSYNC = 1 << 7; // Directory modifications are synchronous.
|
2024-06-02 03:40:53 +00:00
|
|
|
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.
|
2024-05-17 03:19:36 +00:00
|
|
|
}
|
|
|
|
|
}
|