|
@@ -3,7 +3,7 @@
|
|
|
use crate::{
|
|
|
arch::{interrupt::TrapFrame, syscall::nr::SYS_MOUNT},
|
|
|
filesystem::vfs::{
|
|
|
- fcntl::AtFlags, mount::MountFlags, produce_fs, utils::user_path_at, FileSystem, MountFS,
|
|
|
+ fcntl::AtFlags, mount::MountFlags, produce_fs, utils::user_path_at, IndexNode, MountFS,
|
|
|
MAX_PATHLEN, VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
|
|
},
|
|
|
process::ProcessManager,
|
|
@@ -12,6 +12,7 @@ use crate::{
|
|
|
user_access,
|
|
|
},
|
|
|
};
|
|
|
+use alloc::string::String;
|
|
|
use alloc::sync::Arc;
|
|
|
use alloc::vec::Vec;
|
|
|
use system_error::SystemError;
|
|
@@ -39,28 +40,33 @@ impl Syscall for SysMountHandle {
|
|
|
}
|
|
|
|
|
|
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
|
|
+ let source = Self::source(args);
|
|
|
let target = Self::target(args);
|
|
|
let filesystemtype = Self::filesystemtype(args);
|
|
|
let data = Self::raw_data(args);
|
|
|
- let source = Self::source(args);
|
|
|
let mount_flags = Self::mountflags(args);
|
|
|
-
|
|
|
+ log::debug!(
|
|
|
+ "sys_mount: source: {:?}, target: {:?}, filesystemtype: {:?}, mount_flags: {:?}, data: {:?}",
|
|
|
+ source, target, filesystemtype, mount_flags, data
|
|
|
+ );
|
|
|
let mount_flags = MountFlags::from_bits_truncate(mount_flags);
|
|
|
|
|
|
- let target = user_access::check_and_clone_cstr(target, Some(MAX_PATHLEN))?
|
|
|
- .into_string()
|
|
|
- .map_err(|_| SystemError::EINVAL)?;
|
|
|
- let source = user_access::check_and_clone_cstr(source, Some(MAX_PATHLEN))?
|
|
|
- .into_string()
|
|
|
- .map_err(|_| SystemError::EINVAL)?;
|
|
|
- let source = source.as_str();
|
|
|
+ let target = copy_mount_string(target).inspect_err(|e| {
|
|
|
+ log::error!("Failed to read mount target: {:?}", e);
|
|
|
+ })?;
|
|
|
+ let source = copy_mount_string(source).inspect_err(|e| {
|
|
|
+ log::error!("Failed to read mount source: {:?}", e);
|
|
|
+ })?;
|
|
|
|
|
|
- let fstype_str = user_access::check_and_clone_cstr(filesystemtype, Some(MAX_PATHLEN))?;
|
|
|
- let fstype_str = fstype_str.to_str().map_err(|_| SystemError::EINVAL)?;
|
|
|
+ let data = copy_mount_string(data).inspect_err(|e| {
|
|
|
+ log::error!("Failed to read mount data: {:?}", e);
|
|
|
+ })?;
|
|
|
|
|
|
- let fs = produce_fs(fstype_str, data, source)?;
|
|
|
+ let fstype_str = copy_mount_string(filesystemtype).inspect_err(|e| {
|
|
|
+ log::error!("Failed to read filesystem type: {:?}", e);
|
|
|
+ })?;
|
|
|
|
|
|
- do_mount(fs, &target, mount_flags)?;
|
|
|
+ do_mount(source, target, fstype_str, data, mount_flags)?;
|
|
|
|
|
|
return Ok(0);
|
|
|
}
|
|
@@ -69,11 +75,11 @@ impl Syscall for SysMountHandle {
|
|
|
let flags = MountFlags::from_bits(Self::mountflags(args)).unwrap_or(MountFlags::empty());
|
|
|
|
|
|
vec![
|
|
|
- FormattedSyscallParam::new("source", format!("{:#x}", Self::source(args) as usize)),
|
|
|
- FormattedSyscallParam::new("target", format!("{:#x}", Self::target(args) as usize)),
|
|
|
+ FormattedSyscallParam::new("source", format!("{:?}", Self::source(args))),
|
|
|
+ FormattedSyscallParam::new("target", format!("{:?}", Self::target(args))),
|
|
|
FormattedSyscallParam::new(
|
|
|
"filesystem type",
|
|
|
- format!("{:#x}", Self::filesystemtype(args) as usize),
|
|
|
+ format!("{:?}", Self::filesystemtype(args)),
|
|
|
),
|
|
|
FormattedSyscallParam::new(
|
|
|
"mountflags",
|
|
@@ -85,28 +91,40 @@ impl Syscall for SysMountHandle {
|
|
|
}
|
|
|
|
|
|
impl SysMountHandle {
|
|
|
- fn source(args: &[usize]) -> *const u8 {
|
|
|
- args[0] as *const u8
|
|
|
+ fn source(args: &[usize]) -> Option<*const u8> {
|
|
|
+ let source = args[0] as *const u8;
|
|
|
+ if source.is_null() {
|
|
|
+ None
|
|
|
+ } else {
|
|
|
+ Some(source)
|
|
|
+ }
|
|
|
}
|
|
|
- fn target(args: &[usize]) -> *const u8 {
|
|
|
- args[1] as *const u8
|
|
|
+ fn target(args: &[usize]) -> Option<*const u8> {
|
|
|
+ let target = args[1] as *const u8;
|
|
|
+ if target.is_null() {
|
|
|
+ None
|
|
|
+ } else {
|
|
|
+ Some(target)
|
|
|
+ }
|
|
|
}
|
|
|
- fn filesystemtype(args: &[usize]) -> *const u8 {
|
|
|
- args[2] as *const u8
|
|
|
+ fn filesystemtype(args: &[usize]) -> Option<*const u8> {
|
|
|
+ let p = args[2] as *const u8;
|
|
|
+ if p.is_null() {
|
|
|
+ None
|
|
|
+ } else {
|
|
|
+ Some(p)
|
|
|
+ }
|
|
|
}
|
|
|
fn mountflags(args: &[usize]) -> u32 {
|
|
|
args[3] as u32
|
|
|
}
|
|
|
- fn raw_data(args: &[usize]) -> Option<&'static str> {
|
|
|
+ fn raw_data(args: &[usize]) -> Option<*const u8> {
|
|
|
let raw = args[4] as *const u8;
|
|
|
if raw.is_null() {
|
|
|
return None;
|
|
|
}
|
|
|
- let len = (0..).find(|&i| unsafe { raw.add(i).read() } == 0).unwrap();
|
|
|
|
|
|
- let slice = unsafe { core::slice::from_raw_parts(raw, len) };
|
|
|
- let raw_str = core::str::from_utf8(slice).ok().unwrap();
|
|
|
- Some(raw_str)
|
|
|
+ Some(raw)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -129,22 +147,147 @@ syscall_table_macros::declare_syscall!(SYS_MOUNT, SysMountHandle);
|
|
|
/// - `Ok(Arc<MountFS>)`: 挂载成功后返回挂载的文件系统。
|
|
|
/// - `Err(SystemError)`: 挂载失败时返回错误。
|
|
|
pub fn do_mount(
|
|
|
- fs: Arc<dyn FileSystem>,
|
|
|
- mount_point: &str,
|
|
|
+ source: Option<String>,
|
|
|
+ target: Option<String>,
|
|
|
+ filesystemtype: Option<String>,
|
|
|
+ data: Option<String>,
|
|
|
mount_flags: MountFlags,
|
|
|
-) -> Result<Arc<MountFS>, SystemError> {
|
|
|
+) -> Result<(), SystemError> {
|
|
|
let (current_node, rest_path) = user_path_at(
|
|
|
&ProcessManager::current_pcb(),
|
|
|
AtFlags::AT_FDCWD.bits(),
|
|
|
- mount_point,
|
|
|
+ target.as_deref().unwrap_or(""),
|
|
|
)?;
|
|
|
let inode = current_node.lookup_follow_symlink(&rest_path, VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
|
|
|
- let result = ProcessManager::current_mntns().get_mount_point(mount_point);
|
|
|
+ return path_mount(source, inode, filesystemtype, data, mount_flags);
|
|
|
+}
|
|
|
+
|
|
|
+fn path_mount(
|
|
|
+ source: Option<String>,
|
|
|
+ target_inode: Arc<dyn IndexNode>,
|
|
|
+ filesystemtype: Option<String>,
|
|
|
+ data: Option<String>,
|
|
|
+ mut flags: MountFlags,
|
|
|
+) -> Result<(), SystemError> {
|
|
|
+ let mut mnt_flags = MountFlags::empty();
|
|
|
+
|
|
|
+ if flags & MountFlags::MGC_MASK == MountFlags::MGC_VAL {
|
|
|
+ flags.remove(MountFlags::MGC_MASK);
|
|
|
+ }
|
|
|
+
|
|
|
+ if flags.contains(MountFlags::NOUSER) {
|
|
|
+ return Err(SystemError::EINVAL);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Default to relatime unless overriden
|
|
|
+ if !flags.contains(MountFlags::NOATIME) {
|
|
|
+ mnt_flags.insert(MountFlags::RELATIME);
|
|
|
+ }
|
|
|
+
|
|
|
+ if flags.contains(MountFlags::NOSUID) {
|
|
|
+ mnt_flags.insert(MountFlags::NOSUID);
|
|
|
+ }
|
|
|
+
|
|
|
+ if flags.contains(MountFlags::NODEV) {
|
|
|
+ mnt_flags.insert(MountFlags::NODEV);
|
|
|
+ }
|
|
|
+
|
|
|
+ if flags.contains(MountFlags::NOEXEC) {
|
|
|
+ mnt_flags.insert(MountFlags::NOEXEC);
|
|
|
+ }
|
|
|
+
|
|
|
+ if flags.contains(MountFlags::NOATIME) {
|
|
|
+ mnt_flags.insert(MountFlags::NOATIME);
|
|
|
+ }
|
|
|
+
|
|
|
+ if flags.contains(MountFlags::NODIRATIME) {
|
|
|
+ mnt_flags.insert(MountFlags::NODIRATIME);
|
|
|
+ }
|
|
|
+
|
|
|
+ if flags.contains(MountFlags::STRICTATIME) {
|
|
|
+ mnt_flags.remove(MountFlags::RELATIME);
|
|
|
+ mnt_flags.remove(MountFlags::NOATIME);
|
|
|
+ }
|
|
|
+ if flags.contains(MountFlags::RDONLY) {
|
|
|
+ mnt_flags.insert(MountFlags::RDONLY);
|
|
|
+ }
|
|
|
+ if flags.contains(MountFlags::NOSYMFOLLOW) {
|
|
|
+ mnt_flags.insert(MountFlags::NOSYMFOLLOW);
|
|
|
+ }
|
|
|
+
|
|
|
+ // todo: 处理remount时,atime相关的选项
|
|
|
+ // https://code.dragonos.org.cn/xref/linux-6.6.21/fs/namespace.c#3646
|
|
|
+
|
|
|
+ // todo: 参考linux的,实现对各个挂载选项的处理
|
|
|
+ // https://code.dragonos.org.cn/xref/linux-6.6.21/fs/namespace.c#3662
|
|
|
+ if flags.intersection(MountFlags::REMOUNT | MountFlags::BIND)
|
|
|
+ == (MountFlags::REMOUNT | MountFlags::BIND)
|
|
|
+ {
|
|
|
+ log::warn!("todo: reconfigure mnt");
|
|
|
+ return Err(SystemError::ENOSYS);
|
|
|
+ }
|
|
|
+
|
|
|
+ if flags.contains(MountFlags::REMOUNT) {
|
|
|
+ log::warn!("todo: remount");
|
|
|
+ return Err(SystemError::ENOSYS);
|
|
|
+ }
|
|
|
+
|
|
|
+ if flags.contains(MountFlags::BIND) {
|
|
|
+ log::warn!("todo: bind mnt");
|
|
|
+ return Err(SystemError::ENOSYS);
|
|
|
+ }
|
|
|
+ if flags.intersects(
|
|
|
+ MountFlags::SHARED | MountFlags::PRIVATE | MountFlags::SLAVE | MountFlags::UNBINDABLE,
|
|
|
+ ) {
|
|
|
+ log::warn!("todo: change mnt type: {:?}", flags);
|
|
|
+ // 这里暂时返回OK,否则unshare会失败!!!
|
|
|
+ return Ok(());
|
|
|
+ // return Err(SystemError::ENOSYS);
|
|
|
+ }
|
|
|
+
|
|
|
+ if flags.contains(MountFlags::MOVE) {
|
|
|
+ log::warn!("todo: move mnt");
|
|
|
+ return Err(SystemError::ENOSYS);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建新的挂载
|
|
|
+ return do_new_mount(source, target_inode, filesystemtype, data, mnt_flags).map(|_| ());
|
|
|
+}
|
|
|
+
|
|
|
+fn do_new_mount(
|
|
|
+ source: Option<String>,
|
|
|
+ target_inode: Arc<dyn IndexNode>,
|
|
|
+ filesystemtype: Option<String>,
|
|
|
+ data: Option<String>,
|
|
|
+ mount_flags: MountFlags,
|
|
|
+) -> Result<Arc<MountFS>, SystemError> {
|
|
|
+ let fs_type_str = filesystemtype.ok_or(SystemError::EINVAL)?;
|
|
|
+ let source = source.ok_or(SystemError::EINVAL)?;
|
|
|
+ let fs = produce_fs(&fs_type_str, data.as_deref(), &source).inspect_err(|e| {
|
|
|
+ log::error!("Failed to produce filesystem: {:?}", e);
|
|
|
+ })?;
|
|
|
+
|
|
|
+ let abs_path = target_inode.absolute_path()?;
|
|
|
+
|
|
|
+ let result = ProcessManager::current_mntns().get_mount_point(&abs_path);
|
|
|
if let Some((_, rest, _fs)) = result {
|
|
|
if rest.is_empty() {
|
|
|
return Err(SystemError::EBUSY);
|
|
|
}
|
|
|
}
|
|
|
- // 移至IndexNode.mount()来记录
|
|
|
- return inode.mount(fs, mount_flags);
|
|
|
+ return target_inode.mount(fs, mount_flags);
|
|
|
+}
|
|
|
+#[inline(never)]
|
|
|
+fn copy_mount_string(raw: Option<*const u8>) -> Result<Option<String>, SystemError> {
|
|
|
+ if let Some(raw) = raw {
|
|
|
+ let s = user_access::check_and_clone_cstr(raw, Some(MAX_PATHLEN))
|
|
|
+ .inspect_err(|e| {
|
|
|
+ log::error!("Failed to read mount string: {:?}", e);
|
|
|
+ })?
|
|
|
+ .into_string()
|
|
|
+ .map_err(|_| SystemError::EINVAL)?;
|
|
|
+ Ok(Some(s))
|
|
|
+ } else {
|
|
|
+ Ok(None)
|
|
|
+ }
|
|
|
}
|