Browse Source

添加mount系统调用 (#561)

* 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
Donkey Kane 11 months ago
parent
commit
1d37ca6d17

+ 1 - 0
.gitignore

@@ -20,3 +20,4 @@ Cargo.lock
 .cache
 compile_commands.json
 /logs/
+.vscode

+ 1 - 1
.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",
         
     ],
-    
 }

+ 4 - 0
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 {

+ 4 - 1
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> = 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 {

+ 4 - 0
kernel/src/filesystem/kernfs/mod.rs

@@ -47,6 +47,10 @@ impl FileSystem for KernFS {
     fn root_inode(&self) -> Arc<dyn IndexNode> {
         return self.root_inode.clone();
     }
+
+    fn name(&self) -> &str {
+        "kernfs"
+    }
 }
 
 impl KernFS {

+ 3 - 0
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 {

+ 25 - 10
kernel/src/filesystem/ramfs/mod.rs

@@ -1,14 +1,7 @@
 use core::any::Any;
 use core::intrinsics::unlikely;
 
-use alloc::{
-    collections::BTreeMap,
-    string::String,
-    sync::{Arc, Weak},
-    vec::Vec,
-};
-use system_error::SystemError;
-
+use crate::filesystem::vfs::FSMAKER;
 use crate::{
     driver::base::device::device_number::DeviceNumber,
     filesystem::vfs::{core::generate_inode_id, FileType},
@@ -16,10 +9,17 @@ use crate::{
     libs::spinlock::{SpinLock, SpinLockGuard},
     time::TimeSpec,
 };
+use alloc::{
+    collections::BTreeMap,
+    string::String,
+    sync::{Arc, Weak},
+    vec::Vec,
+};
+use system_error::SystemError;
 
 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<Arc<dyn FileSystem + 'static>, SystemError> {
+        let fs = RamFS::new();
+        return Ok(fs);
+    }
 }
 
+#[distributed_slice(FSMAKER)]
+static RAMFSMAKER: FileSystemMaker = FileSystemMaker::new(
+    "ramfs",
+    &(RamFS::make_ramfs as fn() -> Result<Arc<dyn FileSystem + 'static>, SystemError>),
+);
+
 impl IndexNode for LockedRamFSInode {
     fn truncate(&self, len: usize) -> Result<(), SystemError> {
         let mut inode = self.0.lock();

+ 8 - 0
kernel/src/filesystem/vfs/core.rs

@@ -273,3 +273,11 @@ pub fn do_unlink_at(dirfd: i32, path: &str) -> Result<u64, SystemError> {
 
     return Ok(0);
 }
+
+// @brief mount filesystem
+pub fn do_mount(fs: Arc<dyn FileSystem>, mount_point: &str) -> Result<usize, SystemError> {
+    ROOT_INODE()
+        .lookup_follow_symlink(&mount_point, VFS_MAX_FOLLOW_SYMLINK_TIMES)?
+        .mount(fs)?;
+    Ok(0)
+}

+ 48 - 1
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<Arc<dyn FileSystem>, SystemError> {
+        (self.function)()
+    }
+}
+
+pub type FileSystemNewFunction = fn() -> Result<Arc<dyn FileSystem>, 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);

+ 4 - 0
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"
+    }
 }

+ 41 - 3
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<usize, SystemError> {
+        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)]

+ 9 - 0
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),
         };
 

+ 1 - 0
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

+ 3 - 0
user/apps/test-mount/.gitignore

@@ -0,0 +1,3 @@
+/target
+Cargo.lock
+/install/

+ 11 - 0
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 <[email protected]>" ]
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+libc="0.2"

+ 56 - 0
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

+ 3 - 0
user/apps/test-mount/README.md

@@ -0,0 +1,3 @@
+# test-mount
+
+用于测试mount系统调用的用户程序

+ 17 - 0
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");
+    }
+}

+ 22 - 0
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"
+  }
+}