Prechádzať zdrojové kódy

fix: epoll drop deadlock and open AT_FDCWD with empty relative path panic (#1203)

* fix(epoll): 解决进程持有epoll_inode的时候exit导致的死锁问题

解决由于进程在进入exit流程之前,没有关闭epoll inode导致exit流程死锁的bug

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

* fix(vfs): 解决AT_FDCWD时,传入path为空导致内核panic的问题

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

* chore: 更新Held项目的git revision

将Held项目的git revision从f192df4更新为5163c56。

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

---------

Signed-off-by: longjin <longjin@DragonOS.org>
LoGin 2 dní pred
rodič
commit
8471e4173e

+ 10 - 1
kernel/src/driver/tty/tty_device.rs

@@ -1,3 +1,5 @@
+use core::fmt::Debug;
+
 use alloc::{
     string::{String, ToString},
     sync::{Arc, Weak},
@@ -97,7 +99,6 @@ pub enum PtyType {
     Pts,
 }
 
-#[derive(Debug)]
 #[cast_to([sync] Device)]
 pub struct TtyDevice {
     name: String,
@@ -144,6 +145,14 @@ impl TtyDevice {
     }
 }
 
+impl Debug for TtyDevice {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        f.debug_struct("TtyDevice")
+            .field("name", &self.name)
+            .finish()
+    }
+}
+
 impl PollableInode for TtyDevice {
     fn poll(&self, private_data: &FilePrivateData) -> Result<usize, SystemError> {
         let tty = TtyDevice::tty_core(private_data)?;

+ 8 - 6
kernel/src/filesystem/epoll/event_poll.rs

@@ -68,16 +68,13 @@ impl EventPoll {
         let fds: Vec<i32> = self.ep_items.keys().cloned().collect::<Vec<_>>();
         // 清理红黑树里面的epitems
         for fd in fds {
-            let file = ProcessManager::current_pcb()
-                .fd_table()
-                .read()
-                .get_file_by_fd(fd);
+            let fdtable = ProcessManager::current_pcb().basic().try_fd_table().clone();
+            let file = fdtable.and_then(|fdtable| fdtable.read().get_file_by_fd(fd));
 
             if let Some(file) = file {
                 let epitm = self.ep_items.get(&fd).unwrap();
                 file.remove_epitem(epitm)?;
             }
-
             self.ep_items.remove(&fd);
         }
 
@@ -644,7 +641,12 @@ impl EventPoll {
         let epitems_guard = epitems.try_lock_irqsave()?;
         for epitem in epitems_guard.iter() {
             // The upgrade is safe because EventPoll always exists when the epitem is in the list
-            let epoll = epitem.epoll().upgrade().unwrap();
+            let epoll = epitem.epoll().upgrade();
+            if epoll.is_none() {
+                // 如果epoll已经被释放,则直接跳过
+                continue;
+            }
+            let epoll = epoll.unwrap();
             let mut epoll_guard = epoll.try_lock()?;
             let binding = epitem.clone();
             let event_guard = binding.event().read();

+ 8 - 1
kernel/src/filesystem/fat/fs.rs

@@ -101,7 +101,6 @@ impl LockedFATFsInfo {
     }
 }
 
-#[derive(Debug)]
 pub struct FATInode {
     /// 指向父Inode的弱引用
     parent: Weak<LockedFATInode>,
@@ -128,6 +127,14 @@ pub struct FATInode {
     page_cache: Option<Arc<PageCache>>,
 }
 
+impl Debug for FATInode {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        f.debug_struct("FATInode")
+            .field("inode_id", &self.metadata.inode_id)
+            .finish()
+    }
+}
+
 impl FATInode {
     /// 将inode的元数据与磁盘同步
     pub fn synchronize_metadata(&mut self) {

+ 1 - 1
kernel/src/filesystem/vfs/utils.rs

@@ -45,7 +45,7 @@ pub fn user_path_at(
     let mut inode = ROOT_INODE();
     let ret_path;
     // 如果path不是绝对路径,则需要拼接
-    if path.as_bytes()[0] != b'/' {
+    if path.is_empty() || path.as_bytes()[0] != b'/' {
         // 如果dirfd不是AT_FDCWD,则需要检查dirfd是否是目录
         if dirfd != AtFlags::AT_FDCWD.bits() {
             let binding = pcb.fd_table();

+ 2 - 2
kernel/src/process/fork.rs

@@ -291,14 +291,14 @@ impl ProcessManager {
     ) -> Result<(), SystemError> {
         // 如果不共享文件描述符表,则拷贝文件描述符表
         if !clone_flags.contains(CloneFlags::CLONE_FILES) {
-            let new_fd_table = current_pcb.basic().fd_table().unwrap().read().clone();
+            let new_fd_table = current_pcb.basic().try_fd_table().unwrap().read().clone();
             let new_fd_table = Arc::new(RwLock::new(new_fd_table));
             new_pcb.basic_mut().set_fd_table(Some(new_fd_table));
         } else {
             // 如果共享文件描述符表,则直接拷贝指针
             new_pcb
                 .basic_mut()
-                .set_fd_table(current_pcb.basic().fd_table().clone());
+                .set_fd_table(current_pcb.basic().try_fd_table().clone());
         }
 
         return Ok(());

+ 15 - 6
kernel/src/process/mod.rs

@@ -427,6 +427,7 @@ impl ProcessManager {
 
         // 关中断
         let _irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
+
         let pid: Pid;
         {
             let pcb = ProcessManager::current_pcb();
@@ -472,7 +473,6 @@ impl ProcessManager {
             drop(thread);
             unsafe { pcb.basic_mut().set_user_vm(None) };
             pcb.exit_files();
-
             // TODO 由于未实现进程组,tty记录的前台进程组等于当前进程,故退出前要置空
             // 后续相关逻辑需要在SYS_EXIT_GROUP系统调用中实现
             if let Some(tty) = pcb.sig_info_irqsave().tty() {
@@ -483,7 +483,6 @@ impl ProcessManager {
                 }
             }
             pcb.sig_info_mut().set_tty(None);
-
             pcb.clear_pg_and_session_reference();
             drop(pcb);
             ProcessManager::exit_notify();
@@ -1048,7 +1047,7 @@ impl ProcessControlBlock {
     /// 获取文件描述符表的Arc指针
     #[inline(always)]
     pub fn fd_table(&self) -> Arc<RwLock<FileDescriptorVec>> {
-        return self.basic.read().fd_table().unwrap();
+        return self.basic.read().try_fd_table().unwrap();
     }
 
     #[inline(always)]
@@ -1218,7 +1217,12 @@ impl ProcessControlBlock {
 
     /// Exit fd table when process exit
     fn exit_files(&self) {
-        self.basic.write_irqsave().set_fd_table(None);
+        // 关闭文件描述符表
+        // 这里这样写的原因是避免某些inode在关闭时需要访问当前进程的basic,导致死锁
+        let mut guard = self.basic.write_irqsave();
+        let old = guard.set_fd_table(None);
+        drop(guard);
+        drop(old)
     }
 
     pub fn children_read_irqsave(&self) -> RwLockReadGuard<Vec<Pid>> {
@@ -1369,12 +1373,17 @@ impl ProcessBasicInfo {
         self.user_vm = user_vm;
     }
 
-    pub fn fd_table(&self) -> Option<Arc<RwLock<FileDescriptorVec>>> {
+    pub fn try_fd_table(&self) -> Option<Arc<RwLock<FileDescriptorVec>>> {
         return self.fd_table.clone();
     }
 
-    pub fn set_fd_table(&mut self, fd_table: Option<Arc<RwLock<FileDescriptorVec>>>) {
+    pub fn set_fd_table(
+        &mut self,
+        fd_table: Option<Arc<RwLock<FileDescriptorVec>>>,
+    ) -> Option<Arc<RwLock<FileDescriptorVec>>> {
+        let old = self.fd_table.take();
         self.fd_table = fd_table;
+        return old;
     }
 }
 

+ 1 - 1
user/dadk/config/held-0.1.0.toml

@@ -25,7 +25,7 @@ source = "git"
 source-path = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/Held.git"
 # git标签或分支
 # 注意: branch和revision只能二选一,且source要设置为"git"
-revision = "f192df4"
+revision = "5163c56"
 
 # 构建相关信息
 [build]