diff --git a/kernel/src/filesystem/vfs/syscall.rs b/kernel/src/filesystem/vfs/syscall.rs index d7ad96e3..50732103 100644 --- a/kernel/src/filesystem/vfs/syscall.rs +++ b/kernel/src/filesystem/vfs/syscall.rs @@ -679,6 +679,7 @@ impl Syscall { let metadata = inode.metadata()?; if metadata.file_type == FileType::Dir { proc.basic_mut().set_cwd(new_path); + proc.fs_struct_mut().set_pwd(inode); return Ok(0); } else { return Err(SystemError::ENOTDIR); @@ -698,6 +699,7 @@ impl Syscall { } let path = inode.absolute_path()?; pcb.basic_mut().set_cwd(path); + pcb.fs_struct_mut().set_pwd(inode); return Ok(0); } diff --git a/kernel/src/namespaces/mnt_namespace.rs b/kernel/src/namespaces/mnt_namespace.rs index 15d3efda..721cc519 100644 --- a/kernel/src/namespaces/mnt_namespace.rs +++ b/kernel/src/namespaces/mnt_namespace.rs @@ -16,11 +16,13 @@ use super::ucount::Ucount::MntNamespaces; use super::{namespace::NsCommon, ucount::UCounts, user_namespace::UserNamespace}; use crate::container_of; use crate::filesystem::vfs::mount::MountFSInode; +use crate::filesystem::vfs::syscall::ModeType; use crate::filesystem::vfs::IndexNode; use crate::filesystem::vfs::InodeId; use crate::filesystem::vfs::MountFS; use crate::filesystem::vfs::ROOT_INODE; use crate::libs::rbtree::RBTree; +use crate::libs::rwlock::RwLock; use crate::libs::wait_queue::WaitQueue; use crate::process::fork::CloneFlags; use crate::process::ProcessManager; @@ -60,13 +62,36 @@ struct MntNsOperations { clone_flags: CloneFlags, } -/// 使用该结构体的时候加spinlock -#[derive(Clone, Debug)] -pub struct FsStruct { - umask: u32, //文件权限掩码 - pub root: Arc, - pub pwd: Arc, +#[derive(Debug, Clone)] +struct PathContext { + root: Arc, + pwd: Arc, } + +impl PathContext { + pub fn new() -> Self { + Self { + root: ROOT_INODE(), + pwd: ROOT_INODE(), + } + } +} + +#[derive(Debug)] +pub struct FsStruct { + umask: ModeType, //文件权限掩码 + path_context: RwLock, +} + +impl Clone for FsStruct { + fn clone(&self) -> Self { + Self { + umask: self.umask, + path_context: RwLock::new(self.path_context.read().clone()), + } + } +} + impl Default for FsStruct { fn default() -> Self { Self::new() @@ -76,16 +101,25 @@ impl Default for FsStruct { impl FsStruct { pub fn new() -> Self { Self { - umask: 0o22, - root: ROOT_INODE(), - pwd: ROOT_INODE(), + umask: ModeType::S_IWUGO, + path_context: RwLock::new(PathContext::new()), } } - pub fn set_root(&mut self, inode: Arc) { - self.root = inode; + + pub fn set_root(&self, inode: Arc) { + self.path_context.write().root = inode; } - pub fn set_pwd(&mut self, inode: Arc) { - self.pwd = inode; + + pub fn set_pwd(&self, inode: Arc) { + self.path_context.write().pwd = inode; + } + + pub fn pwd(&self) -> Arc { + self.path_context.read().pwd.clone() + } + + pub fn root(&self) -> Arc { + self.path_context.read().root.clone() } } @@ -127,8 +161,10 @@ impl NsOperations for MntNsOperations { } nsproxy.mnt_namespace = mnt_ns; - nsset.fs.lock().set_pwd(ROOT_INODE()); - nsset.fs.lock().set_root(ROOT_INODE()); + let guard = nsset.fs.write(); + guard.set_pwd(ROOT_INODE()); + guard.set_root(ROOT_INODE()); + Ok(()) } fn owner(&self, ns_common: Arc) -> Arc { diff --git a/kernel/src/namespaces/mod.rs b/kernel/src/namespaces/mod.rs index a9043a12..51ead2c6 100644 --- a/kernel/src/namespaces/mod.rs +++ b/kernel/src/namespaces/mod.rs @@ -5,7 +5,7 @@ use system_error::SystemError; use user_namespace::UserNamespace; use crate::{ - libs::spinlock::SpinLock, + libs::rwlock::RwLock, process::{fork::CloneFlags, ProcessControlBlock}, }; @@ -17,12 +17,12 @@ pub mod ucount; pub mod user_namespace; /// 管理 namespace,包含了所有namespace的信息 -#[derive(Clone)] pub struct NsSet { flags: u64, nsproxy: NsProxy, - pub fs: Arc>, + pub fs: RwLock>, } + #[derive(Debug, Clone)] pub struct NsProxy { pub pid_namespace: Arc, diff --git a/kernel/src/namespaces/namespace.rs b/kernel/src/namespaces/namespace.rs index 06b0e6ac..f4b77880 100644 --- a/kernel/src/namespaces/namespace.rs +++ b/kernel/src/namespaces/namespace.rs @@ -3,6 +3,7 @@ use core::fmt::Debug; use crate::filesystem::procfs::ProcFSInode; use crate::filesystem::vfs::{IndexNode, ROOT_INODE}; +use crate::libs::rwlock::RwLock; use crate::namespaces::user_namespace::UserNamespace; use crate::process::fork::CloneFlags; use crate::process::{Pid, ProcessControlBlock, ProcessManager}; @@ -101,7 +102,7 @@ pub fn prepare_nsset(flags: u64) -> Result { let current = ProcessManager::current_pcb(); Ok(NsSet { flags, - fs: current.fs_struct(), + fs: RwLock::new(current.fs_struct()), nsproxy: create_new_namespaces(flags, ¤t, USER_NS.clone())?, }) } @@ -110,10 +111,10 @@ pub fn commit_nsset(nsset: NsSet) { let flags = CloneFlags::from_bits_truncate(nsset.flags); let current = ProcessManager::current_pcb(); if flags.contains(CloneFlags::CLONE_NEWNS) { - let fs = current.fs_struct(); - let nsset_fs = nsset.fs.lock(); - fs.lock().set_pwd(nsset_fs.pwd.clone()); - fs.lock().set_root(nsset_fs.root.clone()); + let nsset_fs = nsset.fs.read(); + let fs = current.fs_struct_mut(); + fs.set_pwd(nsset_fs.pwd()); + fs.set_root(nsset_fs.root()); } switch_task_namespace(current, nsset.nsproxy); // 转移所有权 } diff --git a/kernel/src/process/exec.rs b/kernel/src/process/exec.rs index 12af4c33..0dac0529 100644 --- a/kernel/src/process/exec.rs +++ b/kernel/src/process/exec.rs @@ -5,10 +5,7 @@ use system_error::SystemError; use crate::{ driver::base::block::SeekFrom, - filesystem::vfs::{ - file::{File, FileMode}, - ROOT_INODE, - }, + filesystem::vfs::file::{File, FileMode}, libs::elf::ELF_LOADER, mm::{ ucontext::{AddressSpace, UserStack}, @@ -118,7 +115,8 @@ impl ExecParam { vm: Arc, flags: ExecParamFlags, ) -> Result { - let inode = ROOT_INODE().lookup(file_path)?; + let pwd = ProcessManager::current_pcb().pwd_inode(); + let inode = pwd.lookup(file_path)?; // 读取文件头部,用于判断文件类型 let file = File::new(inode, FileMode::O_RDONLY)?; diff --git a/kernel/src/process/fork.rs b/kernel/src/process/fork.rs index 431e6432..c150af89 100644 --- a/kernel/src/process/fork.rs +++ b/kernel/src/process/fork.rs @@ -549,6 +549,13 @@ impl ProcessManager { ) }); + Self::copy_fs(&clone_flags, current_pcb, pcb).unwrap_or_else(|e| { + panic!( + "fork: Failed to copy fs from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}", + current_pcb.pid(), pcb.pid(), e + ) + }); + sched_cgroup_fork(pcb); Ok(()) @@ -597,4 +604,20 @@ impl ProcessManager { Ok(()) } + + fn copy_fs( + clone_flags: &CloneFlags, + parent_pcb: &Arc, + child_pcb: &Arc, + ) -> Result<(), SystemError> { + let fs = parent_pcb.fs_struct(); + let mut guard = child_pcb.fs_struct_mut(); + if clone_flags.contains(CloneFlags::CLONE_FS) { + *guard = fs.clone(); + } else { + let new_fs = (*fs).clone(); + *guard = Arc::new(new_fs); + } + Ok(()) + } } diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 1d568abe..77741b5e 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -31,7 +31,7 @@ use crate::{ exception::InterruptArch, filesystem::{ procfs::procfs_unregister_pid, - vfs::{file::FileDescriptorVec, FileType}, + vfs::{file::FileDescriptorVec, FileType, IndexNode}, }, ipc::{ signal::RestartBlock, @@ -718,7 +718,7 @@ pub struct ProcessControlBlock { thread: RwLock, /// 进程文件系统的状态 - fs: Arc>, + fs: RwLock>, ///闹钟定时器 alarm_timer: SpinLock>, @@ -821,7 +821,7 @@ impl ProcessControlBlock { children: RwLock::new(Vec::new()), wait_queue: WaitQueue::default(), thread: RwLock::new(ThreadInfo::new()), - fs: Arc::new(SpinLock::new(FsStruct::new())), + fs: RwLock::new(Arc::new(FsStruct::new())), alarm_timer: SpinLock::new(None), robust_list: RwLock::new(None), nsproxy: Arc::new(RwLock::new(NsProxy::new())), @@ -1012,8 +1012,16 @@ impl ProcessControlBlock { } #[inline(always)] - pub fn fs_struct(&self) -> Arc> { - self.fs.clone() + pub fn fs_struct(&self) -> Arc { + self.fs.read().clone() + } + + pub fn fs_struct_mut(&self) -> RwLockWriteGuard> { + self.fs.write() + } + + pub fn pwd_inode(&self) -> Arc { + self.fs.read().pwd() } /// 获取文件描述符表的Arc指针 diff --git a/tools/run-qemu.sh b/tools/run-qemu.sh index a97a34f0..cc15c10d 100755 --- a/tools/run-qemu.sh +++ b/tools/run-qemu.sh @@ -169,6 +169,19 @@ while true;do esac done +setup_kernel_init_program() { + if [ ${ARCH} == "x86_64" ]; then + # KERNEL_CMDLINE+=" init=/bin/busybox init " + KERNEL_CMDLINE+=" init=/bin/dragonreach " + elif [ ${ARCH} == "riscv64" ]; then + KERNEL_CMDLINE+=" init=/bin/riscv_rust_init " + fi +} + +# 设置内核init程序 +setup_kernel_init_program + + if [ ${QEMU_NOGRAPHIC} == true ]; then QEMU_SERIAL=" -serial chardev:mux -monitor chardev:mux -chardev stdio,id=mux,mux=on,signal=off,logfile=${QEMU_SERIAL_LOG_FILE} " @@ -181,27 +194,21 @@ if [ ${QEMU_NOGRAPHIC} == true ]; then QEMU_DEVICES+=" -device virtio-serial-device -device virtconsole,chardev=mux " fi - KERNEL_CMDLINE+=" console=/dev/hvc0 " + KERNEL_CMDLINE=" console=/dev/hvc0 ${KERNEL_CMDLINE}" QEMU_MONITOR="" QEMU_ARGUMENT+=" --nographic " + KERNEL_CMDLINE=$(echo "${KERNEL_CMDLINE}" | sed 's/^[ \t]*//;s/[ \t]*$//') + if [ ${ARCH} == "x86_64" ]; then - QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf " + QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf -append \"${KERNEL_CMDLINE}\" " elif [ ${ARCH} == "loongarch64" ]; then - QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf " + QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf -append \"${KERNEL_CMDLINE}\" " + elif [ ${ARCH} == "riscv64" ]; then + QEMU_ARGUMENT+=" -append \"${KERNEL_CMDLINE}\" " fi fi -setup_kernel_init_program() { - if [ ${ARCH} == "x86_64" ]; then - KERNEL_CMDLINE+=" init=/bin/dragonreach " - elif [ ${ARCH} == "riscv64" ]; then - KERNEL_CMDLINE+=" init=/bin/riscv_rust_init " - fi -} - -# 设置内核init程序 -setup_kernel_init_program # ps: 下面这条使用tap的方式,无法dhcp获取到ip,暂时不知道为什么 # QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -net nic,netdev=nic0 -netdev tap,id=nic0,model=virtio-net-pci,script=qemu/ifup-nat,downscript=qemu/ifdown-nat -usb -device qemu-xhci,id=xhci,p2=8,p3=4 " @@ -252,25 +259,25 @@ sudo rm -rf ${QEMU_MEMORY_BACKEND_PATH_PREFIX}/${QEMU_MEMORY_BACKEND} if [ ${BIOS_TYPE} == uefi ] ;then if [ ${ARCH} == x86_64 ] ;then - sudo ${QEMU} -bios arch/x86_64/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT} + sh -c "sudo ${QEMU} -bios arch/x86_64/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT}" elif [ ${ARCH} == i386 ] ;then - sudo ${QEMU} -bios arch/i386/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT} + sh -c "sudo ${QEMU} -bios arch/i386/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT}" elif [ ${ARCH} == riscv64 ] ;then install_riscv_uboot - sudo ${QEMU} -kernel ${RISCV64_UBOOT_PATH}/u-boot.bin ${QEMU_ARGUMENT} + sh -c "sudo ${QEMU} -kernel ${RISCV64_UBOOT_PATH}/u-boot.bin ${QEMU_ARGUMENT}" else echo "不支持的架构: ${ARCH}" fi else # 如果是i386架构或者x86_64架构,就直接启动 if [ ${ARCH} == x86_64 ] || [ ${ARCH} == i386 ] ;then - sudo ${QEMU} ${QEMU_ARGUMENT} + sh -c "sudo ${QEMU} ${QEMU_ARGUMENT}" elif [ ${ARCH} == riscv64 ] ;then # 如果是riscv64架构,就与efi启动一样 install_riscv_uboot - sudo ${QEMU} -kernel ${RISCV64_UBOOT_PATH}/u-boot.bin ${QEMU_ARGUMENT} -append "${KERNEL_CMDLINE}" + sh -c "sudo ${QEMU} -kernel ${RISCV64_UBOOT_PATH}/u-boot.bin ${QEMU_ARGUMENT}" elif [ ${ARCH} == loongarch64 ] ;then - sudo ${QEMU} ${QEMU_ARGUMENT} + sh -c "sudo ${QEMU} ${QEMU_ARGUMENT}" else echo "不支持的架构: ${ARCH}" fi