Browse Source

命名管道系统调用以及文件系统兼容特殊文件类型的接口 (#397)

* 修复pipe2在读端或写端关闭后还阻塞问题。

* 实现命名管道机制,增加特殊文件类型兼容普通文件系统的接口。

* 普通文件系统能够适配特殊文件(命名管道等)
GnoCiYeH 1 year ago
parent
commit
2dbef7859f

+ 2 - 0
.github/workflows/cache-toolchain.yml

@@ -45,6 +45,8 @@ jobs:
             sudo sh -c "apt update && apt install -y llvm-dev libclang-dev clang gcc-multilib libssl-dev pkg-config"
             cargo install cargo-binutils
             rustup toolchain install nightly
+            rustup toolchain install nightly-2023-01-21-x86_64-unknown-linux-gnu
+            rustup toolchain install nightly-2023-08-15-x86_64-unknown-linux-gnu
             rustup default nightly
             rustup component add rust-src
             rustup component add llvm-tools-preview

+ 9 - 1
.github/workflows/rustfmt.yml

@@ -1,6 +1,14 @@
 name: Rust format check
 
-on: [push, pull_request]
+on:
+  workflow_run:
+    workflows: [Build Check]
+    types:
+      - completed
+  
+  push:
+
+  pull_request:
 
 jobs:
     # ensure the toolchain is cached

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

@@ -1,4 +1,5 @@
 #![allow(dead_code)]
+use core::intrinsics::unlikely;
 use core::{any::Any, fmt::Debug};
 
 use alloc::{
@@ -8,6 +9,8 @@ use alloc::{
     vec::Vec,
 };
 
+use crate::filesystem::vfs::SpecialNodeData;
+use crate::ipc::pipe::LockedPipeInode;
 use crate::{
     driver::base::block::{block_device::LBA_SIZE, disk_info::Partition, SeekFrom},
     filesystem::vfs::{
@@ -25,6 +28,7 @@ use crate::{
     time::TimeSpec,
 };
 
+use super::entry::FATFile;
 use super::{
     bpb::{BiosParameterBlock, FATType},
     entry::{FATDir, FATDirEntry, FATDirIter, FATEntry},
@@ -102,6 +106,9 @@ pub struct FATInode {
 
     /// 根据不同的Inode类型,创建不同的私有字段
     inode_type: FATDirEntry,
+
+    /// 若该节点是特殊文件节点,该字段则为真正的文件节点
+    special_node: Option<SpecialNodeData>,
 }
 
 impl FATInode {
@@ -196,6 +203,7 @@ impl LockedFATInode {
                 gid: 0,
                 raw_dev: 0,
             },
+            special_node: None,
         })));
 
         inode.0.lock().self_ref = Arc::downgrade(&inode);
@@ -315,6 +323,7 @@ impl FATFileSystem {
                 gid: 0,
                 raw_dev: 0,
             },
+            special_node: None,
         })));
 
         let result: Arc<FATFileSystem> = Arc::new(FATFileSystem {
@@ -1565,7 +1574,15 @@ impl IndexNode for LockedFATInode {
         // 对目标inode上锁,以防更改
         let target_guard: SpinLockGuard<FATInode> = target.0.lock();
         // 先从缓存删除
-        guard.children.remove(&name.to_uppercase());
+        let nod = guard.children.remove(&name.to_uppercase());
+
+        // 若删除缓存中为管道的文件,则不需要再到磁盘删除
+        if let Some(_) = nod {
+            let file_type = target_guard.metadata.file_type;
+            if file_type == FileType::Pipe {
+                return Ok(());
+            }
+        }
 
         let dir = match &guard.inode_type {
             FATDirEntry::File(_) | FATDirEntry::VolId(_) => {
@@ -1663,6 +1680,53 @@ impl IndexNode for LockedFATInode {
             }
         }
     }
+
+    fn mknod(
+        &self,
+        filename: &str,
+        mode: ModeType,
+        _dev_t: crate::driver::base::device::DeviceNumber,
+    ) -> Result<Arc<dyn IndexNode>, SystemError> {
+        let mut inode = self.0.lock();
+        if inode.metadata.file_type != FileType::Dir {
+            return Err(SystemError::ENOTDIR);
+        }
+
+        // 判断需要创建的类型
+        if unlikely(mode.contains(ModeType::S_IFREG)) {
+            // 普通文件
+            return Ok(self.create(filename, FileType::File, mode)?);
+        }
+
+        let nod = LockedFATInode::new(
+            inode.fs.upgrade().unwrap(),
+            inode.self_ref.clone(),
+            FATDirEntry::File(FATFile::default()),
+        );
+
+        if mode.contains(ModeType::S_IFIFO) {
+            nod.0.lock().metadata.file_type = FileType::Pipe;
+            // 创建pipe文件
+            let pipe_inode = LockedPipeInode::new();
+            // 设置special_node
+            nod.0.lock().special_node = Some(SpecialNodeData::Pipe(pipe_inode));
+        } else if mode.contains(ModeType::S_IFBLK) {
+            nod.0.lock().metadata.file_type = FileType::BlockDevice;
+            unimplemented!()
+        } else if mode.contains(ModeType::S_IFCHR) {
+            nod.0.lock().metadata.file_type = FileType::CharDevice;
+            unimplemented!()
+        }
+
+        inode
+            .children
+            .insert(String::from(filename).to_uppercase(), nod.clone());
+        Ok(nod)
+    }
+
+    fn special_node(&self) -> Option<SpecialNodeData> {
+        self.0.lock().special_node.clone()
+    }
 }
 
 impl Default for FATFsInfo {

+ 75 - 1
kernel/src/filesystem/ramfs/mod.rs

@@ -1,4 +1,5 @@
 use core::any::Any;
+use core::intrinsics::unlikely;
 
 use alloc::{
     collections::BTreeMap,
@@ -9,6 +10,7 @@ use alloc::{
 
 use crate::{
     filesystem::vfs::{core::generate_inode_id, FileType},
+    ipc::pipe::LockedPipeInode,
     libs::spinlock::{SpinLock, SpinLockGuard},
     syscall::SystemError,
     time::TimeSpec,
@@ -16,7 +18,7 @@ use crate::{
 
 use super::vfs::{
     file::FilePrivateData, syscall::ModeType, FileSystem, FsInfo, IndexNode, InodeId, Metadata,
-    PollStatus,
+    PollStatus, SpecialNodeData,
 };
 
 /// RamFS的inode名称的最大长度
@@ -52,6 +54,8 @@ pub struct RamFSInode {
     metadata: Metadata,
     /// 指向inode所在的文件系统对象的指针
     fs: Weak<RamFS>,
+    /// 指向特殊节点
+    special_node: Option<SpecialNodeData>,
 }
 
 impl FileSystem for RamFS {
@@ -98,6 +102,7 @@ impl RamFS {
                 raw_dev: 0,
             },
             fs: Weak::default(),
+            special_node: None,
         })));
 
         let result: Arc<RamFS> = Arc::new(RamFS { root_inode: root });
@@ -296,6 +301,7 @@ impl IndexNode for LockedRamFSInode {
                 raw_dev: data,
             },
             fs: inode.fs.clone(),
+            special_node: None,
         })));
 
         // 初始化inode的自引用的weak指针
@@ -476,4 +482,72 @@ impl IndexNode for LockedRamFSInode {
 
         return Ok(keys);
     }
+
+    fn mknod(
+        &self,
+        filename: &str,
+        mode: ModeType,
+        _dev_t: crate::driver::base::device::DeviceNumber,
+    ) -> Result<Arc<dyn IndexNode>, SystemError> {
+        let mut inode = self.0.lock();
+        if inode.metadata.file_type != FileType::Dir {
+            return Err(SystemError::ENOTDIR);
+        }
+
+        // 判断需要创建的类型
+        if unlikely(mode.contains(ModeType::S_IFREG)) {
+            // 普通文件
+            return Ok(self.create(filename, FileType::File, mode)?);
+        }
+
+        let nod = Arc::new(LockedRamFSInode(SpinLock::new(RamFSInode {
+            parent: inode.self_ref.clone(),
+            self_ref: Weak::default(),
+            children: BTreeMap::new(),
+            data: Vec::new(),
+            metadata: Metadata {
+                dev_id: 0,
+                inode_id: generate_inode_id(),
+                size: 0,
+                blk_size: 0,
+                blocks: 0,
+                atime: TimeSpec::default(),
+                mtime: TimeSpec::default(),
+                ctime: TimeSpec::default(),
+                file_type: FileType::Pipe,
+                mode: mode,
+                nlinks: 1,
+                uid: 0,
+                gid: 0,
+                raw_dev: 0,
+            },
+            fs: inode.fs.clone(),
+            special_node: None,
+        })));
+
+        nod.0.lock().self_ref = Arc::downgrade(&nod);
+
+        if mode.contains(ModeType::S_IFIFO) {
+            nod.0.lock().metadata.file_type = FileType::Pipe;
+            // 创建pipe文件
+            let pipe_inode = LockedPipeInode::new();
+            // 设置special_node
+            nod.0.lock().special_node = Some(SpecialNodeData::Pipe(pipe_inode));
+        } else if mode.contains(ModeType::S_IFBLK) {
+            nod.0.lock().metadata.file_type = FileType::BlockDevice;
+            unimplemented!()
+        } else if mode.contains(ModeType::S_IFCHR) {
+            nod.0.lock().metadata.file_type = FileType::CharDevice;
+            unimplemented!()
+        }
+
+        inode
+            .children
+            .insert(String::from(filename).to_uppercase(), nod.clone());
+        Ok(nod)
+    }
+
+    fn special_node(&self) -> Option<super::vfs::SpecialNodeData> {
+        return self.0.lock().special_node.clone();
+    }
 }

+ 4 - 5
kernel/src/filesystem/vfs/core.rs

@@ -15,12 +15,11 @@ use crate::{
         sysfs::sysfs_init,
         vfs::{mount::MountFS, syscall::ModeType, AtomicInodeId, FileSystem, FileType},
     },
-    include::bindings::bindings::PAGE_4K_SIZE,
     kdebug, kerror, kinfo,
     syscall::SystemError,
 };
 
-use super::{file::FileMode, utils::rsplit_path, IndexNode, InodeId};
+use super::{file::FileMode, utils::rsplit_path, IndexNode, InodeId, MAX_PATHLEN};
 
 /// @brief 原子地生成新的Inode号。
 /// 请注意,所有的inode号都需要通过该函数来生成.全局的inode号,除了以下两个特殊的以外,都是唯一的
@@ -177,7 +176,7 @@ pub fn mount_root_fs() -> Result<(), SystemError> {
 /// @brief 创建文件/文件夹
 pub fn do_mkdir(path: &str, _mode: FileMode) -> Result<u64, SystemError> {
     // 文件名过长
-    if path.len() > PAGE_4K_SIZE as usize {
+    if path.len() > MAX_PATHLEN as usize {
         return Err(SystemError::ENAMETOOLONG);
     }
 
@@ -209,7 +208,7 @@ pub fn do_mkdir(path: &str, _mode: FileMode) -> Result<u64, SystemError> {
 /// @brief 删除文件夹
 pub fn do_remove_dir(path: &str) -> Result<u64, SystemError> {
     // 文件名过长
-    if path.len() > PAGE_4K_SIZE as usize {
+    if path.len() > MAX_PATHLEN as usize {
         return Err(SystemError::ENAMETOOLONG);
     }
 
@@ -245,7 +244,7 @@ pub fn do_remove_dir(path: &str) -> Result<u64, SystemError> {
 /// @brief 删除文件
 pub fn do_unlink_at(path: &str, _mode: FileMode) -> Result<u64, SystemError> {
     // 文件名过长
-    if path.len() > PAGE_4K_SIZE as usize {
+    if path.len() > MAX_PATHLEN as usize {
         return Err(SystemError::ENAMETOOLONG);
     }
 

+ 12 - 2
kernel/src/filesystem/vfs/file.rs

@@ -15,7 +15,7 @@ use crate::{
     syscall::SystemError,
 };
 
-use super::{Dirent, FileType, IndexNode, InodeId, Metadata};
+use super::{Dirent, FileType, IndexNode, InodeId, Metadata, SpecialNodeData};
 
 /// 文件私有信息的枚举类型
 #[derive(Debug, Clone)]
@@ -115,7 +115,17 @@ impl File {
     /// @param inode 文件对象对应的inode
     /// @param mode 文件的打开模式
     pub fn new(inode: Arc<dyn IndexNode>, mode: FileMode) -> Result<Self, SystemError> {
-        let file_type: FileType = inode.metadata()?.file_type;
+        let mut inode = inode;
+        let file_type = inode.metadata()?.file_type;
+        match file_type {
+            FileType::Pipe => {
+                if let Some(SpecialNodeData::Pipe(pipe_inode)) = inode.special_node() {
+                    inode = pipe_inode;
+                }
+            }
+            _ => {}
+        }
+
         let mut f = File {
             inode,
             offset: 0,

+ 34 - 1
kernel/src/filesystem/vfs/mod.rs

@@ -11,7 +11,13 @@ use ::core::{any::Any, fmt::Debug, sync::atomic::AtomicUsize};
 
 use alloc::{string::String, sync::Arc, vec::Vec};
 
-use crate::{libs::casting::DowncastArc, syscall::SystemError, time::TimeSpec};
+use crate::{
+    driver::base::{block::block_device::BlockDevice, char::CharDevice, device::DeviceNumber},
+    ipc::pipe::LockedPipeInode,
+    libs::casting::DowncastArc,
+    syscall::SystemError,
+    time::TimeSpec,
+};
 
 use self::{core::generate_inode_id, file::FileMode, syscall::ModeType};
 pub use self::{core::ROOT_INODE, file::FilePrivateData, mount::MountFS};
@@ -41,6 +47,16 @@ pub enum FileType {
     Socket,
 }
 
+#[derive(Debug, Clone)]
+pub enum SpecialNodeData {
+    /// 管道文件
+    Pipe(Arc<LockedPipeInode>),
+    /// 字符设备
+    CharDevice(Arc<dyn CharDevice>),
+    /// 块设备
+    BlockDevice(Arc<dyn BlockDevice>),
+}
+
 /* these are defined by POSIX and also present in glibc's dirent.h */
 /// 完整含义请见 http://www.gnu.org/software/libc/manual/html_node/Directory-Entries.html
 pub const DT_UNKNOWN: u16 = 0;
@@ -338,6 +354,23 @@ pub trait IndexNode: Any + Sync + Send + Debug {
     fn sync(&self) -> Result<(), SystemError> {
         return Ok(());
     }
+
+    /// ## 创建一个特殊文件节点
+    /// - _filename: 文件名
+    /// - _mode: 权限信息
+    fn mknod(
+        &self,
+        _filename: &str,
+        _mode: ModeType,
+        _dev_t: DeviceNumber,
+    ) -> Result<Arc<dyn IndexNode>, SystemError> {
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+
+    /// ## 返回特殊文件的inode
+    fn special_node(&self) -> Option<SpecialNodeData> {
+        None
+    }
 }
 
 impl DowncastArc for dyn IndexNode {

+ 21 - 1
kernel/src/filesystem/vfs/mount.rs

@@ -8,7 +8,7 @@ use alloc::{
     sync::{Arc, Weak},
 };
 
-use crate::{libs::spinlock::SpinLock, syscall::SystemError};
+use crate::{driver::base::device::DeviceNumber, libs::spinlock::SpinLock, syscall::SystemError};
 
 use super::{
     file::FileMode, syscall::ModeType, FilePrivateData, FileSystem, FileType, IndexNode, InodeId,
@@ -348,6 +348,26 @@ impl IndexNode for MountFSInode {
             .insert(metadata.inode_id, new_mount_fs.clone());
         return Ok(new_mount_fs);
     }
+
+    #[inline]
+    fn mknod(
+        &self,
+        filename: &str,
+        mode: ModeType,
+        dev_t: DeviceNumber,
+    ) -> Result<Arc<dyn IndexNode>, SystemError> {
+        return Ok(MountFSInode {
+            inner_inode: self.inner_inode.mknod(filename, mode, dev_t)?,
+            mount_fs: self.mount_fs.clone(),
+            self_ref: Weak::default(),
+        }
+        .wrap());
+    }
+
+    #[inline]
+    fn special_node(&self) -> Option<super::SpecialNodeData> {
+        self.inner_inode.special_node()
+    }
 }
 
 impl FileSystem for MountFS {

+ 39 - 5
kernel/src/filesystem/vfs/syscall.rs

@@ -1,3 +1,5 @@
+use core::ffi::CStr;
+
 use alloc::{
     string::{String, ToString},
     sync::Arc,
@@ -5,14 +7,14 @@ use alloc::{
 };
 
 use crate::{
-    driver::base::block::SeekFrom,
+    driver::base::{block::SeekFrom, device::DeviceNumber},
     filesystem::vfs::file::FileDescriptorVec,
-    include::bindings::bindings::{verify_area, AT_REMOVEDIR, PAGE_4K_SIZE, PROC_MAX_FD_NUM},
+    include::bindings::bindings::{verify_area, AT_REMOVEDIR, PROC_MAX_FD_NUM},
     kerror,
     libs::rwlock::RwLockWriteGuard,
     mm::VirtAddr,
     process::ProcessManager,
-    syscall::{Syscall, SystemError},
+    syscall::{user_access::UserBufferReader, Syscall, SystemError},
     time::TimeSpec,
 };
 
@@ -21,7 +23,7 @@ use super::{
     fcntl::{FcntlCommand, FD_CLOEXEC},
     file::{File, FileMode},
     utils::rsplit_path,
-    Dirent, FileType, IndexNode, ROOT_INODE,
+    Dirent, FileType, IndexNode, MAX_PATHLEN, ROOT_INODE,
 };
 
 pub const SEEK_SET: u32 = 0;
@@ -137,7 +139,7 @@ impl Syscall {
         // kdebug!("open: path: {}, mode: {:?}", path, mode);
 
         // 文件名过长
-        if path.len() > PAGE_4K_SIZE as usize {
+        if path.len() > MAX_PATHLEN as usize {
             return Err(SystemError::ENAMETOOLONG);
         }
 
@@ -698,6 +700,38 @@ impl Syscall {
         }
         return Ok(0);
     }
+
+    pub fn mknod(
+        path_ptr: *const i8,
+        mode: ModeType,
+        dev_t: DeviceNumber,
+    ) -> Result<usize, SystemError> {
+        // 安全检验
+        let len = unsafe { CStr::from_ptr(path_ptr).to_bytes().len() };
+        let user_buffer = UserBufferReader::new(path_ptr, len, true)?;
+        let buf = user_buffer.read_from_user::<u8>(0)?;
+        let path = core::str::from_utf8(buf).map_err(|_| SystemError::EINVAL)?;
+
+        // 文件名过长
+        if path.len() > MAX_PATHLEN as usize {
+            return Err(SystemError::ENAMETOOLONG);
+        }
+
+        let inode: Result<Arc<dyn IndexNode>, SystemError> = ROOT_INODE().lookup(path);
+
+        if inode.is_ok() {
+            return Err(SystemError::EEXIST);
+        }
+
+        let (filename, parent_path) = rsplit_path(path);
+
+        // 查找父目录
+        let parent_inode: Arc<dyn IndexNode> = ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
+        // 创建nod
+        parent_inode.mknod(filename, mode, dev_t)?;
+
+        return Ok(0);
+    }
 }
 #[repr(C)]
 #[derive(Debug, Clone, Copy)]

+ 11 - 2
kernel/src/syscall/mod.rs

@@ -7,11 +7,11 @@ use num_traits::{FromPrimitive, ToPrimitive};
 
 use crate::{
     arch::{cpu::cpu_reset, interrupt::TrapFrame, MMArch},
-    driver::base::block::SeekFrom,
+    driver::base::{block::SeekFrom, device::DeviceNumber},
     filesystem::vfs::{
         fcntl::FcntlCommand,
         file::FileMode,
-        syscall::{PosixKstat, SEEK_CUR, SEEK_END, SEEK_MAX, SEEK_SET},
+        syscall::{ModeType, PosixKstat, SEEK_CUR, SEEK_END, SEEK_MAX, SEEK_SET},
         MAX_PATHLEN,
     },
     include::bindings::bindings::{PAGE_2M_SIZE, PAGE_4K_SIZE},
@@ -375,6 +375,7 @@ pub const SYS_GETPGID: usize = 50;
 
 pub const SYS_FCNTL: usize = 51;
 pub const SYS_FTRUNCATE: usize = 52;
+pub const SYS_MKNOD: usize = 53;
 
 #[derive(Debug)]
 pub struct Syscall;
@@ -973,6 +974,14 @@ impl Syscall {
                 res
             }
 
+            SYS_MKNOD => {
+                let path = args[0];
+                let flags = args[1];
+                let dev_t = args[2];
+                let flags: ModeType = ModeType::from_bits_truncate(flags as u32);
+                Self::mknod(path as *const i8, flags, DeviceNumber::from(dev_t))
+            }
+
             _ => panic!("Unsupported syscall ID: {}", syscall_num),
         };
 

+ 26 - 0
user/apps/test_mkfifo/Makefile

@@ -0,0 +1,26 @@
+CC=$(DragonOS_GCC)/x86_64-elf-gcc
+LD=ld
+OBJCOPY=objcopy
+# 修改这里,把它改为你的relibc的sysroot路径
+RELIBC_OPT=$(DADK_BUILD_CACHE_DIR_RELIBC_0_1_0)
+CFLAGS=-I $(RELIBC_OPT)/include -D__dragonos__
+
+tmp_output_dir=$(ROOT_PATH)/bin/tmp/user
+output_dir=$(DADK_BUILD_CACHE_DIR_TEST_MKFIFO_0_1_0)
+
+LIBC_OBJS:=$(shell find $(RELIBC_OPT)/lib -name "*.o" | sort )
+LIBC_OBJS+=$(RELIBC_OPT)/lib/libc.a
+
+all: main.o
+	mkdir -p $(tmp_output_dir)
+	
+	$(LD) -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/test_mkfifo  $(shell find . -name "*.o") $(LIBC_OBJS) -T link.lds
+
+	$(OBJCOPY) -I elf64-x86-64 -R ".eh_frame" -R ".comment" -O elf64-x86-64 $(tmp_output_dir)/test_mkfifo $(output_dir)/test_mkfifo.elf
+	
+	mv $(output_dir)/test_mkfifo.elf $(output_dir)/test_mkfifo
+main.o: main.c
+	$(CC) $(CFLAGS) -c main.c  -o main.o
+
+clean:
+	rm -f *.o

+ 239 - 0
user/apps/test_mkfifo/link.lds

@@ -0,0 +1,239 @@
+/* Script for -z combreloc */
+/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
+   Copying and distribution of this script, with or without modification,
+   are permitted in any medium without royalty provided the copyright
+   notice and this notice are preserved.  */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
+              "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(_start)
+
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .note.gnu.build-id  : { *(.note.gnu.build-id) }
+  .hash           : { *(.hash) }
+  .gnu.hash       : { *(.gnu.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rela.dyn       :
+    {
+      *(.rela.init)
+      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+      *(.rela.fini)
+      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+      *(.rela.ctors)
+      *(.rela.dtors)
+      *(.rela.got)
+      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+      *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
+      *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
+      *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
+      *(.rela.ifunc)
+    }
+  .rela.plt       :
+    {
+      *(.rela.plt)
+      PROVIDE_HIDDEN (__rela_iplt_start = .);
+      *(.rela.iplt)
+      PROVIDE_HIDDEN (__rela_iplt_end = .);
+    }
+  . = ALIGN(CONSTANT (MAXPAGESIZE));
+  .init           :
+  {
+    KEEP (*(SORT_NONE(.init)))
+  }
+  .plt            : { *(.plt) *(.iplt) }
+.plt.got        : { *(.plt.got) }
+.plt.sec        : { *(.plt.sec) }
+  .text           :
+  {
+    *(.text.unlikely .text.*_unlikely .text.unlikely.*)
+    *(.text.exit .text.exit.*)
+    *(.text.startup .text.startup.*)
+    *(.text.hot .text.hot.*)
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf.em.  */
+    *(.gnu.warning)
+  }
+  .fini           :
+  {
+    KEEP (*(SORT_NONE(.fini)))
+  }
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  . = ALIGN(CONSTANT (MAXPAGESIZE));
+  /* Adjust the address for the rodata segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .eh_frame_hdr   : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
+  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
+  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+  .gnu_extab   : ONLY_IF_RO { *(.gnu_extab*) }
+  /* These sections are generated by the Sun/Oracle C++ compiler.  */
+  .exception_ranges   : ONLY_IF_RO { *(.exception_ranges*) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
+  /* Exception handling  */
+  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
+  .gnu_extab      : ONLY_IF_RW { *(.gnu_extab) }
+  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  .exception_ranges   : ONLY_IF_RW { *(.exception_ranges*) }
+  /* Thread Local Storage sections  */
+  .tdata          :
+   {
+     PROVIDE_HIDDEN (__tdata_start = .);
+     *(.tdata .tdata.* .gnu.linkonce.td.*)
+   }
+  .tbss           : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .preinit_array    :
+  {
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+  }
+  .init_array    :
+  {
+    PROVIDE_HIDDEN (__init_array_start = .);
+    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+    KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
+    PROVIDE_HIDDEN (__init_array_end = .);
+  }
+  .fini_array    :
+  {
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+    KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
+    PROVIDE_HIDDEN (__fini_array_end = .);
+  }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin.o(.ctors))
+    KEEP (*crtbegin?.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*crtbegin?.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
+  .dynamic        : { *(.dynamic) }
+  .got            : { *(.got) *(.igot) }
+  . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
+  .got.plt        : { *(.got.plt) *(.igot.plt) }
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  _edata = .; PROVIDE (edata = .);
+  . = .;
+  __bss_start = .;
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we do not
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 64 / 8 : 1);
+  }
+  .lbss   :
+  {
+    *(.dynlbss)
+    *(.lbss .lbss.* .gnu.linkonce.lb.*)
+    *(LARGE_COMMON)
+  }
+  . = ALIGN(64 / 8);
+  . = SEGMENT_START("ldata-segment", .);
+  .lrodata   ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
+  {
+    *(.lrodata .lrodata.* .gnu.linkonce.lr.*)
+  }
+  .ldata   ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
+  {
+    *(.ldata .ldata.* .gnu.linkonce.l.*)
+    . = ALIGN(. != 0 ? 64 / 8 : 1);
+  }
+  . = ALIGN(64 / 8);
+  _end = .; PROVIDE (end = .);
+  . = DATA_SEGMENT_END (.);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges) }
+  /* DWARF Extension.  */
+  .debug_macro    0 : { *(.debug_macro) }
+  .debug_addr     0 : { *(.debug_addr) }
+  .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+  /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}

+ 78 - 0
user/apps/test_mkfifo/main.c

@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#define BUFFER_SIZE 256
+#define PIPE_NAME "/bin/fifo"
+
+int main()
+{
+    pid_t pid;
+    int pipe_fd;
+    char buffer[BUFFER_SIZE];
+    int bytes_read;
+    int status;
+
+    // 创建命名管道
+    mkfifo(PIPE_NAME, 0666);
+
+    // 创建子进程
+    pid = fork();
+
+    if (pid < 0)
+    {
+        fprintf(stderr, "Fork failed\n");
+        return 1;
+    }
+    else if (pid == 0)
+    {
+        // 子进程
+
+        // 打开管道以供读取
+        pipe_fd = open(PIPE_NAME, O_RDONLY);
+
+        // 从管道中读取数据
+        bytes_read = read(pipe_fd, buffer, BUFFER_SIZE);
+        if (bytes_read > 0)
+        {
+            printf("Child process received message: %s\n", buffer);
+        }
+
+        // 关闭管道文件描述符
+        close(pipe_fd);
+
+        // 删除命名管道
+        unlink(PIPE_NAME);
+
+        exit(0);
+    }
+    else
+    {
+        // 父进程
+
+        // 打开管道以供写入
+        pipe_fd = open(PIPE_NAME, O_WRONLY);
+
+        // 向管道写入数据
+        const char *message = "Hello from parent process";
+        write(pipe_fd, message, strlen(message) + 1);
+
+        // 关闭管道文件描述符
+        close(pipe_fd);
+
+        // 等待子进程结束
+        waitpid(pid, &status, 0);
+
+        if (WIFEXITED(status))
+        {
+            printf("Child process exited with status: %d\n", WEXITSTATUS(status));
+        }
+    }
+
+    return 0;
+}

+ 1 - 1
user/dadk/config/relibc-0.1.0.dadk

@@ -6,7 +6,7 @@
     "BuildFromSource": {
       "Git": {
         "url": "https://git.mirrors.dragonos.org/DragonOS-Community/relibc.git",
-        "revision": "26536e7fcd"
+        "revision": "66739c1b10"
       }
     }
   },

+ 33 - 0
user/dadk/config/test_mkfifo-0.1.0.dadk

@@ -0,0 +1,33 @@
+{
+  "name": "test_mkfifo",
+  "version": "0.1.0",
+  "description": "一个用来测试mkfifo能够正常运行的app",
+  "task_type": {
+    "BuildFromSource": {
+      "Local": {
+        "path": "apps/test_mkfifo"
+      }
+    }
+  },
+  "depends": [
+    {
+      "name": "relibc",
+      "version": "0.1.0"
+    }
+  ],
+  "build": {
+    "build_command": "make"
+  },
+  "install": {
+    "in_dragonos_path": "/bin"
+  },
+  "clean": {
+    "clean_command": "make clean"
+  },
+  "envs": [
+    {
+      "key": "__dragonos__",
+      "value": "__dragonos__"
+    }
+  ]
+}