From 1d37ca6d172e01a98fa6785d2b3e07fb8202a4a9 Mon Sep 17 00:00:00 2001 From: Donkey Kane <109840258+xiaolin2004@users.noreply.github.com> Date: Wed, 20 Mar 2024 15:31:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0mount=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E8=B0=83=E7=94=A8=20(#561)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Modify dadk config to switch NovaShell revision * finish primary build of mount(2), usable now * 使用read_from_cstr函数优化代码可读性 , 针对文件系统新增错误EUNSUPFS * small changes * 添加系统调用文档 * cargo fmt * Revert "small changes" This reverts commit e1991314ce687faa2d652479e8ef64f5bea25fa1. * 修复用户程序参数传入错误 * Revert "small changes" This reverts commit e1991314ce687faa2d652479e8ef64f5bea25fa1. * 解决合并冲突,最终提交 * 将dadk_config切换为相对路径以修复依赖问题 * Update settings.json * Delete user/apps/test-mount/LICENSE * 换用更好的c字符串读取函数,优化系统调用函数注释,修复错误处理bug,删除无用文件,修改测试程序readme * 修改用户程序readme * 代码格式化,初级版本 * 初级版本,未实现文件系统管理器,未支持设备挂载 * 为文件系统添加name方法,返回文件系统名字字符串,为挂载查询服务 * mount系统调用:添加统一文件系统初始化管理器 * null * 解除冲突 * 删除无用kdebug --- .gitignore | 1 + .vscode/settings.json | 2 +- kernel/src/filesystem/devfs/mod.rs | 4 ++ kernel/src/filesystem/fat/fs.rs | 5 ++- kernel/src/filesystem/kernfs/mod.rs | 4 ++ kernel/src/filesystem/procfs/mod.rs | 3 ++ kernel/src/filesystem/ramfs/mod.rs | 35 +++++++++++----- kernel/src/filesystem/vfs/core.rs | 8 ++++ kernel/src/filesystem/vfs/mod.rs | 49 +++++++++++++++++++++- kernel/src/filesystem/vfs/mount.rs | 4 ++ kernel/src/filesystem/vfs/syscall.rs | 44 ++++++++++++++++++-- kernel/src/syscall/mod.rs | 9 +++++ kernel/src/syscall/syscall_num.h | 1 + user/apps/test-mount/.gitignore | 3 ++ user/apps/test-mount/Cargo.toml | 11 +++++ user/apps/test-mount/Makefile | 56 ++++++++++++++++++++++++++ user/apps/test-mount/README.md | 3 ++ user/apps/test-mount/src/main.rs | 17 ++++++++ user/dadk/config/test_mount_1_0_0.dadk | 22 ++++++++++ 19 files changed, 265 insertions(+), 16 deletions(-) create mode 100644 user/apps/test-mount/.gitignore create mode 100644 user/apps/test-mount/Cargo.toml create mode 100644 user/apps/test-mount/Makefile create mode 100644 user/apps/test-mount/README.md create mode 100644 user/apps/test-mount/src/main.rs create mode 100644 user/dadk/config/test_mount_1_0_0.dadk diff --git a/.gitignore b/.gitignore index 52e685b5..ed295766 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ Cargo.lock .cache compile_commands.json /logs/ +.vscode \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 42f592d2..f7a476bc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -150,6 +150,7 @@ "rust-analyzer.linkedProjects": [ "./kernel/Cargo.toml", "./tools/Cargo.toml", + ], // "rust-analyzer.cargo.target": "riscv64imac-unknown-none-elf", "rust-analyzer.cargo.target": "x86_64-unknown-none", @@ -158,5 +159,4 @@ "check", ], - } \ No newline at end of file diff --git a/kernel/src/filesystem/devfs/mod.rs b/kernel/src/filesystem/devfs/mod.rs index e77b0243..c7b82f8a 100644 --- a/kernel/src/filesystem/devfs/mod.rs +++ b/kernel/src/filesystem/devfs/mod.rs @@ -49,6 +49,10 @@ impl FileSystem for DevFS { max_name_len: DEVFS_MAX_NAMELEN, }; } + + fn name(&self) -> &str { + "devfs" + } } impl DevFS { diff --git a/kernel/src/filesystem/fat/fs.rs b/kernel/src/filesystem/fat/fs.rs index b042cf30..15236597 100644 --- a/kernel/src/filesystem/fat/fs.rs +++ b/kernel/src/filesystem/fat/fs.rs @@ -140,7 +140,6 @@ impl FATInode { // 在磁盘查找 let fat_entry: FATDirEntry = d.find_entry(name, None, None, self.fs.upgrade().unwrap())?; - // kdebug!("find entry from disk ok, entry={fat_entry:?}"); // 创建新的inode let entry_inode: Arc = LockedFATInode::new( self.fs.upgrade().unwrap(), @@ -248,6 +247,10 @@ impl FileSystem for FATFileSystem { fn as_any_ref(&self) -> &dyn Any { self } + + fn name(&self) -> &str { + "fat" + } } impl FATFileSystem { diff --git a/kernel/src/filesystem/kernfs/mod.rs b/kernel/src/filesystem/kernfs/mod.rs index 23c45b70..df7715aa 100644 --- a/kernel/src/filesystem/kernfs/mod.rs +++ b/kernel/src/filesystem/kernfs/mod.rs @@ -47,6 +47,10 @@ impl FileSystem for KernFS { fn root_inode(&self) -> Arc { return self.root_inode.clone(); } + + fn name(&self) -> &str { + "kernfs" + } } impl KernFS { diff --git a/kernel/src/filesystem/procfs/mod.rs b/kernel/src/filesystem/procfs/mod.rs index 0c5517c3..6967836a 100644 --- a/kernel/src/filesystem/procfs/mod.rs +++ b/kernel/src/filesystem/procfs/mod.rs @@ -281,6 +281,9 @@ impl FileSystem for ProcFS { fn as_any_ref(&self) -> &dyn core::any::Any { self } + fn name(&self) -> &str { + "procfs" + } } impl ProcFS { diff --git a/kernel/src/filesystem/ramfs/mod.rs b/kernel/src/filesystem/ramfs/mod.rs index ba3f3c17..b3209bde 100644 --- a/kernel/src/filesystem/ramfs/mod.rs +++ b/kernel/src/filesystem/ramfs/mod.rs @@ -1,6 +1,14 @@ use core::any::Any; use core::intrinsics::unlikely; +use crate::filesystem::vfs::FSMAKER; +use crate::{ + driver::base::device::device_number::DeviceNumber, + filesystem::vfs::{core::generate_inode_id, FileType}, + ipc::pipe::LockedPipeInode, + libs::spinlock::{SpinLock, SpinLockGuard}, + time::TimeSpec, +}; use alloc::{ collections::BTreeMap, string::String, @@ -9,17 +17,9 @@ use alloc::{ }; use system_error::SystemError; -use crate::{ - driver::base::device::device_number::DeviceNumber, - filesystem::vfs::{core::generate_inode_id, FileType}, - ipc::pipe::LockedPipeInode, - libs::spinlock::{SpinLock, SpinLockGuard}, - time::TimeSpec, -}; - use super::vfs::{ - file::FilePrivateData, syscall::ModeType, FileSystem, FsInfo, IndexNode, InodeId, Metadata, - SpecialNodeData, + file::FilePrivateData, syscall::ModeType, FileSystem, FileSystemMaker, FsInfo, IndexNode, + InodeId, Metadata, SpecialNodeData, }; /// RamFS的inode名称的最大长度 @@ -76,6 +76,10 @@ impl FileSystem for RamFS { fn as_any_ref(&self) -> &dyn Any { self } + + fn name(&self) -> &str { + "ramfs" + } } impl RamFS { @@ -118,8 +122,19 @@ impl RamFS { return result; } + + pub fn make_ramfs() -> Result, SystemError> { + let fs = RamFS::new(); + return Ok(fs); + } } +#[distributed_slice(FSMAKER)] +static RAMFSMAKER: FileSystemMaker = FileSystemMaker::new( + "ramfs", + &(RamFS::make_ramfs as fn() -> Result, SystemError>), +); + impl IndexNode for LockedRamFSInode { fn truncate(&self, len: usize) -> Result<(), SystemError> { let mut inode = self.0.lock(); diff --git a/kernel/src/filesystem/vfs/core.rs b/kernel/src/filesystem/vfs/core.rs index 10aacdd1..a2326cc8 100644 --- a/kernel/src/filesystem/vfs/core.rs +++ b/kernel/src/filesystem/vfs/core.rs @@ -273,3 +273,11 @@ pub fn do_unlink_at(dirfd: i32, path: &str) -> Result { return Ok(0); } + +// @brief mount filesystem +pub fn do_mount(fs: Arc, mount_point: &str) -> Result { + ROOT_INODE() + .lookup_follow_symlink(&mount_point, VFS_MAX_FOLLOW_SYMLINK_TIMES)? + .mount(fs)?; + Ok(0) +} diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index 4288ca82..be978231 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -7,7 +7,6 @@ pub mod syscall; mod utils; use ::core::{any::Any, fmt::Debug, sync::atomic::AtomicUsize}; - use alloc::{string::String, sync::Arc, vec::Vec}; use system_error::SystemError; @@ -596,6 +595,8 @@ pub trait FileSystem: Any + Sync + Send + Debug { /// @brief 本函数用于实现动态转换。 /// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self fn as_any_ref(&self) -> &dyn Any; + + fn name(&self) -> &str; } impl DowncastArc for dyn FileSystem { @@ -643,3 +644,49 @@ impl Metadata { } } } +pub struct FileSystemMaker { + function: &'static FileSystemNewFunction, + name: &'static str, +} + +impl FileSystemMaker { + pub const fn new( + name: &'static str, + function: &'static FileSystemNewFunction, + ) -> FileSystemMaker { + FileSystemMaker { function, name } + } + + pub fn call(&self) -> Result, SystemError> { + (self.function)() + } +} + +pub type FileSystemNewFunction = fn() -> Result, SystemError>; + +#[macro_export] +macro_rules! define_filesystem_maker_slice { + ($name:ident) => { + #[::linkme::distributed_slice] + pub static $name: [FileSystemMaker] = [..]; + }; + () => { + compile_error!("define_filesystem_maker_slice! requires at least one argument: slice_name"); + }; +} + +/// 调用指定数组中的所有初始化器 +#[macro_export] +macro_rules! producefs { + ($initializer_slice:ident,$filesystem:ident) => { + match $initializer_slice.iter().find(|&m| m.name == $filesystem) { + Some(maker) => maker.call(), + None => { + kerror!("mismatch filesystem type : {}", $filesystem); + Err(SystemError::EINVAL) + } + } + }; +} + +define_filesystem_maker_slice!(FSMAKER); diff --git a/kernel/src/filesystem/vfs/mount.rs b/kernel/src/filesystem/vfs/mount.rs index c3fd7d57..ab58a25e 100644 --- a/kernel/src/filesystem/vfs/mount.rs +++ b/kernel/src/filesystem/vfs/mount.rs @@ -394,4 +394,8 @@ impl FileSystem for MountFS { fn as_any_ref(&self) -> &dyn Any { self } + + fn name(&self) -> &str { + "mountfs" + } } diff --git a/kernel/src/filesystem/vfs/syscall.rs b/kernel/src/filesystem/vfs/syscall.rs index 44ce7f80..8642fd72 100644 --- a/kernel/src/filesystem/vfs/syscall.rs +++ b/kernel/src/filesystem/vfs/syscall.rs @@ -1,16 +1,19 @@ +use core::ffi::c_void; use core::mem::size_of; use alloc::{string::String, sync::Arc, vec::Vec}; use system_error::SystemError; +use crate::producefs; use crate::{ driver::base::{block::SeekFrom, device::device_number::DeviceNumber}, - filesystem::vfs::file::FileDescriptorVec, + filesystem::vfs::{core as Vcore, file::FileDescriptorVec}, + kerror, libs::rwlock::RwLockWriteGuard, mm::{verify_area, VirtAddr}, process::ProcessManager, syscall::{ - user_access::{check_and_clone_cstr, UserBufferWriter}, + user_access::{self, check_and_clone_cstr, UserBufferWriter}, Syscall, }, time::TimeSpec, @@ -22,7 +25,7 @@ use super::{ file::{File, FileMode}, open::{do_faccessat, do_fchmodat, do_sys_open}, utils::{rsplit_path, user_path_at}, - Dirent, FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES, + Dirent, FileType, IndexNode, FSMAKER, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES, }; // use crate::kdebug; @@ -1060,6 +1063,41 @@ impl Syscall { kwarn!("fchmod not fully implemented"); return Ok(0); } + /// #挂载文件系统 + /// + /// 用于挂载文件系统,目前仅支持ramfs挂载 + /// + /// ## 参数: + /// + /// - source 挂载设备(暂时不支持) + /// - target 挂载目录 + /// - filesystemtype 文件系统 + /// - mountflags 挂载选项(暂未实现) + /// - data 带数据挂载 + /// + /// ## 返回值 + /// - Ok(0): 挂载成功 + /// - Err(SystemError) :挂载过程中出错 + pub fn mount( + _source: *const u8, + target: *const u8, + filesystemtype: *const u8, + _mountflags: usize, + _data: *const c_void, + ) -> Result { + let target = user_access::check_and_clone_cstr(target, Some(MAX_PATHLEN))?; + + let filesystemtype = user_access::check_and_clone_cstr(filesystemtype, Some(MAX_PATHLEN))?; + + let filesystemtype = producefs!(FSMAKER, filesystemtype)?; + + return Vcore::do_mount(filesystemtype, (format!("{target}")).as_str()); + } + + // 想法:可以在VFS中实现一个文件系统分发器,流程如下: + // 1. 接受从上方传来的文件类型字符串 + // 2. 将传入值与启动时准备好的字符串数组逐个比较(probe) + // 3. 直接在函数内调用构造方法并直接返回文件系统对象 } #[repr(C)] diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index f62678bf..1396d3b4 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -1,5 +1,6 @@ use core::{ ffi::{c_int, c_void}, + ptr::null, sync::atomic::{AtomicBool, Ordering}, }; @@ -942,6 +943,13 @@ impl Syscall { Err(SystemError::ENOSYS) } + + SYS_MOUNT => { + let source = args[0] as *const u8; + let target = args[1] as *const u8; + let filesystemtype = args[2] as *const u8; + return Self::mount(source, target, filesystemtype, 0, null()); + } SYS_NEWFSTATAT => { // todo: 这个系统调用还没有实现 @@ -953,6 +961,7 @@ impl Syscall { let name = args[0] as *mut PosixOldUtsName; Self::uname(name) } + _ => panic!("Unsupported syscall ID: {}", syscall_num), }; diff --git a/kernel/src/syscall/syscall_num.h b/kernel/src/syscall/syscall_num.h index 6babe955..1f75dab0 100644 --- a/kernel/src/syscall/syscall_num.h +++ b/kernel/src/syscall/syscall_num.h @@ -72,6 +72,7 @@ #define SYS_ARCH_PRCTL 158 +#define SYS_MOUNT 165 #define SYS_REBOOT 169 #define SYS_GETPPID 110 diff --git a/user/apps/test-mount/.gitignore b/user/apps/test-mount/.gitignore new file mode 100644 index 00000000..1ac35461 --- /dev/null +++ b/user/apps/test-mount/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +/install/ \ No newline at end of file diff --git a/user/apps/test-mount/Cargo.toml b/user/apps/test-mount/Cargo.toml new file mode 100644 index 00000000..a379b060 --- /dev/null +++ b/user/apps/test-mount/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "test-mount" +version = "0.1.0" +edition = "2021" +description = "test the new mount syscall" +authors = [ "xiaolin2004 <1553367438@qq.com>" ] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +libc="0.2" \ No newline at end of file diff --git a/user/apps/test-mount/Makefile b/user/apps/test-mount/Makefile new file mode 100644 index 00000000..1b0274d2 --- /dev/null +++ b/user/apps/test-mount/Makefile @@ -0,0 +1,56 @@ +TOOLCHAIN="+nightly-2023-08-15-x86_64-unknown-linux-gnu" +RUSTFLAGS+="" + +ifdef DADK_CURRENT_BUILD_DIR +# 如果是在dadk中编译,那么安装到dadk的安装目录中 + INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR) +else +# 如果是在本地编译,那么安装到当前目录下的install目录中 + INSTALL_DIR = ./install +endif + +ifeq ($(ARCH), x86_64) + export RUST_TARGET=x86_64-unknown-linux-musl +else ifeq ($(ARCH), riscv64) + export RUST_TARGET=riscv64gc-unknown-linux-gnu +else +# 默认为x86_86,用于本地编译 + export RUST_TARGET=x86_64-unknown-linux-musl +endif + +run: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) + +build: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) + +clean: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) + +test: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) + +doc: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc --target $(RUST_TARGET) + +fmt: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt + +fmt-check: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check + +run-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --release + +build-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release + +clean-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release + +test-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) --release + +.PHONY: install +install: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force diff --git a/user/apps/test-mount/README.md b/user/apps/test-mount/README.md new file mode 100644 index 00000000..d792bd32 --- /dev/null +++ b/user/apps/test-mount/README.md @@ -0,0 +1,3 @@ +# test-mount + +用于测试mount系统调用的用户程序 diff --git a/user/apps/test-mount/src/main.rs b/user/apps/test-mount/src/main.rs new file mode 100644 index 00000000..70b588a8 --- /dev/null +++ b/user/apps/test-mount/src/main.rs @@ -0,0 +1,17 @@ +use core::ffi::{c_char, c_void}; +use libc::{mount, MS_BIND}; + +fn main() { + let source = b"\0".as_ptr() as *const c_char; + let target = b"/mnt/tmp\0".as_ptr() as *const c_char; + let fstype = b"ramfs\0".as_ptr() as *const c_char; + let flags = MS_BIND; + let data = std::ptr::null() as *const c_void; + let result = unsafe { mount(source, target, fstype, flags, data) }; + + if result == 0 { + println!("Mount successful"); + } else { + println!("Mount failed"); + } +} diff --git a/user/dadk/config/test_mount_1_0_0.dadk b/user/dadk/config/test_mount_1_0_0.dadk new file mode 100644 index 00000000..dde08dec --- /dev/null +++ b/user/dadk/config/test_mount_1_0_0.dadk @@ -0,0 +1,22 @@ +{ + "name": "test-mount", + "version": "1.0.0", + "description": "to test user mode mount", + "task_type": { + "BuildFromSource": { + "Local": { + "path": "apps/test-mount" + } + } + }, + "depends": [], + "build": { + "build_command": "make install" + }, + "install": { + "in_dragonos_path": "/" + }, + "clean": { + "clean_command": "make clean" + } +}