diff --git a/kernel/aster-nix/src/fs/fs_resolver.rs b/kernel/aster-nix/src/fs/fs_resolver.rs index ec6f6f38d..39363d7e0 100644 --- a/kernel/aster-nix/src/fs/fs_resolver.rs +++ b/kernel/aster-nix/src/fs/fs_resolver.rs @@ -73,12 +73,21 @@ impl FsResolver { let inode_handle = match self.lookup_inner(path, follow_tail_link) { Ok(dentry) => { let inode = dentry.inode(); - if inode.type_() == InodeType::SymLink - && creation_flags.contains(CreationFlags::O_NOFOLLOW) - && !status_flags.contains(StatusFlags::O_PATH) - { - return_errno_with_message!(Errno::ELOOP, "file is a symlink"); + match inode.type_() { + InodeType::NamedPipe => { + warn!("NamedPipe doesn't support additional operation when opening."); + debug!("Open NamedPipe. creation_flags:{:?}, status_flags:{:?}, access_mode:{:?}, inode_mode:{:?}",creation_flags,status_flags,access_mode,inode_mode); + } + InodeType::SymLink => { + if creation_flags.contains(CreationFlags::O_NOFOLLOW) + && !status_flags.contains(StatusFlags::O_PATH) + { + return_errno_with_message!(Errno::ELOOP, "file is a symlink"); + } + } + _ => {} } + if creation_flags.contains(CreationFlags::O_CREAT) && creation_flags.contains(CreationFlags::O_EXCL) { diff --git a/kernel/aster-nix/src/fs/mod.rs b/kernel/aster-nix/src/fs/mod.rs index 32114b732..3cdd46d8b 100644 --- a/kernel/aster-nix/src/fs/mod.rs +++ b/kernel/aster-nix/src/fs/mod.rs @@ -8,6 +8,7 @@ pub mod file_handle; pub mod file_table; pub mod fs_resolver; pub mod inode_handle; +pub mod named_pipe; pub mod path; pub mod pipe; pub mod procfs; diff --git a/kernel/aster-nix/src/fs/named_pipe.rs b/kernel/aster-nix/src/fs/named_pipe.rs new file mode 100644 index 000000000..4b6f7cb8d --- /dev/null +++ b/kernel/aster-nix/src/fs/named_pipe.rs @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MPL-2.0 + +use super::{ + file_handle::FileLike, + pipe::{self, PipeReader, PipeWriter}, + utils::{AccessMode, Metadata}, +}; +use crate::{ + events::IoEvents, + prelude::*, + process::signal::{Pollable, Poller}, +}; + +pub struct NamedPipe { + reader: Arc, + writer: Arc, +} + +impl NamedPipe { + pub fn new() -> Result { + let (reader, writer) = pipe::new_pair()?; + + Ok(Self { reader, writer }) + } + + pub fn with_capacity(capacity: usize) -> Result { + let (reader, writer) = pipe::new_pair_with_capacity(capacity)?; + + Ok(Self { reader, writer }) + } +} + +impl Pollable for NamedPipe { + fn poll(&self, _mask: IoEvents, _poller: Option<&mut Poller>) -> IoEvents { + warn!("Named pipe doesn't support poll now, return IoEvents::empty for now."); + IoEvents::empty() + } +} + +impl FileLike for NamedPipe { + fn read(&self, writer: &mut VmWriter) -> Result { + self.reader.read(writer) + } + + fn write(&self, reader: &mut VmReader) -> Result { + self.writer.write(reader) + } + + fn access_mode(&self) -> AccessMode { + AccessMode::O_RDWR + } + + fn metadata(&self) -> Metadata { + self.reader.metadata() + } +} diff --git a/kernel/aster-nix/src/fs/pipe.rs b/kernel/aster-nix/src/fs/pipe.rs index e6ad0a422..234043772 100644 --- a/kernel/aster-nix/src/fs/pipe.rs +++ b/kernel/aster-nix/src/fs/pipe.rs @@ -6,7 +6,7 @@ use atomic::Ordering; use super::{ file_handle::FileLike, - utils::{AccessMode, Consumer, InodeMode, InodeType, Metadata, Producer, StatusFlags}, + utils::{AccessMode, Channel, Consumer, InodeMode, InodeType, Metadata, Producer, StatusFlags}, }; use crate::{ events::{IoEvents, Observer}, @@ -18,6 +18,26 @@ use crate::{ time::clocks::RealTimeCoarseClock, }; +const DEFAULT_PIPE_BUF_SIZE: usize = 65536; + +pub fn new_pair() -> Result<(Arc, Arc)> { + let (producer, consumer) = Channel::with_capacity(DEFAULT_PIPE_BUF_SIZE).split(); + + Ok(( + PipeReader::new(consumer, StatusFlags::empty())?, + PipeWriter::new(producer, StatusFlags::empty())?, + )) +} + +pub fn new_pair_with_capacity(capacity: usize) -> Result<(Arc, Arc)> { + let (producer, consumer) = Channel::with_capacity(capacity).split(); + + Ok(( + PipeReader::new(consumer, StatusFlags::empty())?, + PipeWriter::new(producer, StatusFlags::empty())?, + )) +} + pub struct PipeReader { consumer: Consumer, status_flags: AtomicU32, @@ -228,7 +248,7 @@ mod test { W: Fn(Arc) + Sync + Send + 'static, R: Fn(Arc) + Sync + Send + 'static, { - let channel = Channel::new(1); + let channel = Channel::with_capacity(1); let (writer, readr) = channel.split(); let writer = PipeWriter::new(writer, StatusFlags::empty()).unwrap(); diff --git a/kernel/aster-nix/src/fs/ramfs/fs.rs b/kernel/aster-nix/src/fs/ramfs/fs.rs index d20540e08..343f3d957 100644 --- a/kernel/aster-nix/src/fs/ramfs/fs.rs +++ b/kernel/aster-nix/src/fs/ramfs/fs.rs @@ -18,6 +18,8 @@ use crate::{ events::IoEvents, fs::{ device::Device, + file_handle::FileLike, + named_pipe::NamedPipe, utils::{ CStr256, DirentVisitor, Extension, FallocMode, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata, MknodType, PageCache, PageCacheBackend, SuperBlock, @@ -151,6 +153,13 @@ impl Node { } } + pub fn new_named_pipe(mode: InodeMode, uid: Uid, gid: Gid) -> Self { + Self { + inner: Inner::NamedPipe(NamedPipe::new().unwrap()), + metadata: InodeMeta::new(mode, uid, gid), + } + } + pub fn inc_size(&mut self) { self.metadata.size += 1; self.metadata.blocks = (self.metadata.size + BLOCK_SIZE - 1) / BLOCK_SIZE; @@ -253,6 +262,7 @@ enum Inner { SymLink(String), Device(Arc), Socket, + NamedPipe(NamedPipe), } impl Inner { @@ -472,6 +482,17 @@ impl RamInode { }) } + fn new_named_pipe(fs: &Arc, mode: InodeMode, uid: Uid, gid: Gid) -> Arc { + Arc::new_cyclic(|weak_self| RamInode { + node: RwMutex::new(Node::new_named_pipe(mode, uid, gid)), + ino: fs.alloc_id(), + typ: InodeType::NamedPipe, + this: weak_self.clone(), + fs: Arc::downgrade(fs), + extension: Extension::new(), + }) + } + fn find(&self, name: &str) -> Result> { if self.typ != InodeType::Dir { return_errno_with_message!(Errno::ENOTDIR, "self is not dir"); @@ -518,20 +539,20 @@ impl Inode for RamInode { let read_len = { let self_inode = self.node.read(); - if let Some(device) = self_inode.inner.as_device() { - device.read(writer)? - } else { - let Some(page_cache) = self_inode.inner.as_file() else { - return_errno_with_message!(Errno::EISDIR, "read is not supported"); - }; - let (offset, read_len) = { - let file_size = self_inode.metadata.size; - let start = file_size.min(offset); - let end = file_size.min(offset + writer.avail()); - (start, end - start) - }; - page_cache.pages().read(offset, writer)?; - read_len + match &self_inode.inner { + Inner::File(page_cache) => { + let (offset, read_len) = { + let file_size = self_inode.metadata.size; + let start = file_size.min(offset); + let end = file_size.min(offset + writer.avail()); + (start, end - start) + }; + page_cache.pages().read(offset, writer)?; + read_len + } + Inner::Device(device) => device.read(writer)?, + Inner::NamedPipe(named_pipe) => named_pipe.read(writer)?, + _ => return_errno_with_message!(Errno::EISDIR, "read is not supported"), } }; @@ -548,34 +569,36 @@ impl Inode for RamInode { let write_len = reader.remain(); let self_inode = self.node.upread(); - if let Some(device) = self_inode.inner.as_device() { - let device_written_len = device.write(reader)?; - let mut self_inode = self_inode.upgrade(); - let now = now(); - self_inode.set_mtime(now); - self_inode.set_ctime(now); - return Ok(device_written_len); - } + match &self_inode.inner { + Inner::File(page_cache) => { + let file_size = self_inode.metadata.size; + let new_size = offset + write_len; + let should_expand_size = new_size > file_size; + if should_expand_size { + page_cache.resize(new_size)?; + } + page_cache.pages().write(offset, reader)?; - let Some(page_cache) = self_inode.inner.as_file() else { - return_errno_with_message!(Errno::EISDIR, "write is not supported"); + let mut self_inode = self_inode.upgrade(); + let now = now(); + self_inode.set_mtime(now); + self_inode.set_ctime(now); + if should_expand_size { + self_inode.resize(new_size); + } + } + Inner::Device(device) => { + device.write(reader)?; + let mut self_inode = self_inode.upgrade(); + let now = now(); + self_inode.set_mtime(now); + self_inode.set_ctime(now); + } + Inner::NamedPipe(named_pipe) => { + named_pipe.write(reader)?; + } + _ => return_errno_with_message!(Errno::EISDIR, "write is not supported"), }; - let file_size = self_inode.metadata.size; - let new_size = offset + write_len; - let should_expand_size = new_size > file_size; - if should_expand_size { - page_cache.resize(new_size)?; - } - page_cache.pages().write(offset, reader)?; - - let mut self_inode = self_inode.upgrade(); - let now = now(); - self_inode.set_mtime(now); - self_inode.set_ctime(now); - if should_expand_size { - self_inode.resize(new_size); - } - Ok(write_len) } @@ -698,7 +721,12 @@ impl Inode for RamInode { device, ) } - _ => return_errno_with_message!(Errno::EPERM, "unimplemented file types"), + MknodType::NamedPipeNode => RamInode::new_named_pipe( + &self.fs.upgrade().unwrap(), + mode, + Uid::new_root(), + Gid::new_root(), + ), }; let mut self_inode = self_inode.upgrade(); diff --git a/kernel/aster-nix/src/fs/utils/channel.rs b/kernel/aster-nix/src/fs/utils/channel.rs index 9fcabca1f..1e04acc80 100644 --- a/kernel/aster-nix/src/fs/utils/channel.rs +++ b/kernel/aster-nix/src/fs/utils/channel.rs @@ -25,7 +25,7 @@ impl Channel { /// # Panics /// /// This method will panic if the given capacity is zero. - pub fn new(capacity: usize) -> Self { + pub fn with_capacity(capacity: usize) -> Self { let common = Arc::new(Common::new(capacity)); let producer = Producer(Fifo::new(common.clone())); @@ -391,7 +391,7 @@ mod test { #[derive(Clone, Debug, PartialEq, Eq)] struct NonCopy(Arc); - let channel = Channel::new(16); + let channel = Channel::with_capacity(16); let (producer, consumer) = channel.split(); let data = NonCopy(Arc::new(99)); diff --git a/kernel/aster-nix/src/net/socket/unix/stream/connected.rs b/kernel/aster-nix/src/net/socket/unix/stream/connected.rs index ab740d6af..ceb62344b 100644 --- a/kernel/aster-nix/src/net/socket/unix/stream/connected.rs +++ b/kernel/aster-nix/src/net/socket/unix/stream/connected.rs @@ -20,8 +20,8 @@ impl Connected { addr: Option, peer_addr: Option, ) -> (Connected, Connected) { - let (writer_this, reader_peer) = Channel::new(DAFAULT_BUF_SIZE).split(); - let (writer_peer, reader_this) = Channel::new(DAFAULT_BUF_SIZE).split(); + let (writer_this, reader_peer) = Channel::with_capacity(DAFAULT_BUF_SIZE).split(); + let (writer_peer, reader_this) = Channel::with_capacity(DAFAULT_BUF_SIZE).split(); let this = Connected { addr: addr.clone(), diff --git a/kernel/aster-nix/src/syscall/mknod.rs b/kernel/aster-nix/src/syscall/mknod.rs index c3c7e245d..5299baa4d 100644 --- a/kernel/aster-nix/src/syscall/mknod.rs +++ b/kernel/aster-nix/src/syscall/mknod.rs @@ -6,7 +6,7 @@ use crate::{ fs::{ file_table::FileDesc, fs_resolver::{FsPath, AT_FDCWD}, - utils::{InodeMode, InodeType}, + utils::{InodeMode, InodeType, MknodType}, }, prelude::*, syscall::constants::MAX_FILENAME_LEN, @@ -53,7 +53,10 @@ pub fn sys_mknodat( let device_inode = get_device(dev)?; let _ = dir_dentry.mknod(&name, inode_mode, device_inode.into())?; } - InodeType::NamedPipe | InodeType::Socket => { + InodeType::NamedPipe => { + let _ = dir_dentry.mknod(&name, inode_mode, MknodType::NamedPipeNode)?; + } + InodeType::Socket => { return_errno_with_message!(Errno::EINVAL, "unsupported file types") } _ => return_errno_with_message!(Errno::EPERM, "unimplemented file types"), diff --git a/kernel/aster-nix/src/syscall/pipe.rs b/kernel/aster-nix/src/syscall/pipe.rs index f5c3b5735..710038646 100644 --- a/kernel/aster-nix/src/syscall/pipe.rs +++ b/kernel/aster-nix/src/syscall/pipe.rs @@ -4,8 +4,8 @@ use super::SyscallReturn; use crate::{ fs::{ file_table::{FdFlags, FileDesc}, - pipe::{PipeReader, PipeWriter}, - utils::{Channel, CreationFlags, StatusFlags}, + pipe, + utils::CreationFlags, }, prelude::*, }; @@ -13,16 +13,7 @@ use crate::{ pub fn sys_pipe2(fds: Vaddr, flags: u32, ctx: &Context) -> Result { debug!("flags: {:?}", flags); - let (pipe_reader, pipe_writer) = { - let (producer, consumer) = Channel::new(PIPE_BUF_SIZE).split(); - - let status_flags = StatusFlags::from_bits_truncate(flags); - - ( - PipeReader::new(consumer, status_flags)?, - PipeWriter::new(producer, status_flags)?, - ) - }; + let (pipe_reader, pipe_writer) = pipe::new_pair()?; let fd_flags = if CreationFlags::from_bits_truncate(flags).contains(CreationFlags::O_CLOEXEC) { FdFlags::CLOEXEC @@ -57,5 +48,3 @@ struct PipeFds { reader_fd: FileDesc, writer_fd: FileDesc, } - -const PIPE_BUF_SIZE: usize = 65536;