Parcourir la source

fix: 修复无法执行当前目录下程序的bug (#1154)

* 更改pcb中的fs以及fNsSet结构体,以便从fs中获取pwd inode

* fmt

* 更改run-qemu.sh,为x86_64传入KERNEL_CMDLINE参数

* 提取FsStruct中的root和pwd信息

* chore(run-qemu.sh): 重构内核启动参数处理逻辑

- 优化KERNEL_CMDLINE拼接逻辑,确保参数顺序正确
- 统一使用sh -c执行QEMU命令

Signed-off-by: longjin <longjin@DragonOS.org>

* refactor(mnt_namespace): 重构FsStruct使用ModeType并移除Arc包装

- 将umask类型从u32改为ModeType
- 移除path_context的Arc包装,改为直接使用RwLock
- 实现Clone trait替代自动derive
- 更新默认umask值为ModeType::S_IWUGO

Signed-off-by: longjin <longjin@DragonOS.org>

* fix(run-qemu): 修改x86_64架构的init程序路径

将x86_64架构的init程序从/bin/busybox改为/bin/dragonreach

Signed-off-by: longjin <longjin@DragonOS.org>

---------

Signed-off-by: longjin <longjin@DragonOS.org>
Co-authored-by: longjin <longjin@DragonOS.org>
火花 il y a 14 heures
Parent
commit
5422256d63

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

+ 50 - 14
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)]
+#[derive(Debug, Clone)]
+struct PathContext {
+    root: Arc<dyn IndexNode>,
+    pwd: Arc<dyn IndexNode>,
+}
+
+impl PathContext {
+    pub fn new() -> Self {
+        Self {
+            root: ROOT_INODE(),
+            pwd: ROOT_INODE(),
+        }
+    }
+}
+
+#[derive(Debug)]
 pub struct FsStruct {
-    umask: u32, //文件权限掩码
-    pub root: Arc<dyn IndexNode>,
-    pub pwd: Arc<dyn IndexNode>,
+    umask: ModeType, //文件权限掩码
+    path_context: RwLock<PathContext>,
+}
+
+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<dyn IndexNode>) {
-        self.root = inode;
+
+    pub fn set_root(&self, inode: Arc<dyn IndexNode>) {
+        self.path_context.write().root = inode;
     }
-    pub fn set_pwd(&mut self, inode: Arc<dyn IndexNode>) {
-        self.pwd = inode;
+
+    pub fn set_pwd(&self, inode: Arc<dyn IndexNode>) {
+        self.path_context.write().pwd = inode;
+    }
+
+    pub fn pwd(&self) -> Arc<dyn IndexNode> {
+        self.path_context.read().pwd.clone()
+    }
+
+    pub fn root(&self) -> Arc<dyn IndexNode> {
+        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<NsCommon>) -> Arc<UserNamespace> {

+ 3 - 3
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<SpinLock<FsStruct>>,
+    pub fs: RwLock<Arc<FsStruct>>,
 }
+
 #[derive(Debug, Clone)]
 pub struct NsProxy {
     pub pid_namespace: Arc<PidNamespace>,

+ 6 - 5
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<NsSet, SystemError> {
     let current = ProcessManager::current_pcb();
     Ok(NsSet {
         flags,
-        fs: current.fs_struct(),
+        fs: RwLock::new(current.fs_struct()),
         nsproxy: create_new_namespaces(flags, &current, 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); // 转移所有权
 }

+ 3 - 5
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<AddressSpace>,
         flags: ExecParamFlags,
     ) -> Result<Self, SystemError> {
-        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)?;

+ 23 - 0
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<ProcessControlBlock>,
+        child_pcb: &Arc<ProcessControlBlock>,
+    ) -> 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(())
+    }
 }

+ 13 - 5
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<ThreadInfo>,
 
     /// 进程文件系统的状态
-    fs: Arc<SpinLock<FsStruct>>,
+    fs: RwLock<Arc<FsStruct>>,
 
     ///闹钟定时器
     alarm_timer: SpinLock<Option<AlarmTimer>>,
@@ -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<SpinLock<FsStruct>> {
-        self.fs.clone()
+    pub fn fs_struct(&self) -> Arc<FsStruct> {
+        self.fs.read().clone()
+    }
+
+    pub fn fs_struct_mut(&self) -> RwLockWriteGuard<Arc<FsStruct>> {
+        self.fs.write()
+    }
+
+    pub fn pwd_inode(&self) -> Arc<dyn IndexNode> {
+        self.fs.read().pwd()
     }
 
     /// 获取文件描述符表的Arc指针

+ 26 - 19
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 "
 
-    if [ ${ARCH} == "x86_64" ]; then
-      QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf "
-    elif [ ${ARCH} == "loongarch64" ]; then
-      QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf "
-    fi
-fi
+    KERNEL_CMDLINE=$(echo "${KERNEL_CMDLINE}" | sed 's/^[ \t]*//;s/[ \t]*$//')
 
-setup_kernel_init_program() {
     if [ ${ARCH} == "x86_64" ]; then
-        KERNEL_CMDLINE+=" init=/bin/dragonreach "
+      QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf -append \"${KERNEL_CMDLINE}\" "
+    elif [ ${ARCH} == "loongarch64" ]; then
+      QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf -append \"${KERNEL_CMDLINE}\" "
     elif [ ${ARCH} == "riscv64" ]; then
-        KERNEL_CMDLINE+=" init=/bin/riscv_rust_init "
+      QEMU_ARGUMENT+=" -append \"${KERNEL_CMDLINE}\" "
     fi
-}
+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