Implement dummy NamedPipe

This commit is contained in:
Yuke Peng 2024-08-16 17:29:01 +08:00 committed by Tate, Hongliang Tian
parent ea64ddfde5
commit 715733f551
9 changed files with 174 additions and 68 deletions

View File

@ -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)
{

View File

@ -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;

View File

@ -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<PipeReader>,
writer: Arc<PipeWriter>,
}
impl NamedPipe {
pub fn new() -> Result<Self> {
let (reader, writer) = pipe::new_pair()?;
Ok(Self { reader, writer })
}
pub fn with_capacity(capacity: usize) -> Result<Self> {
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<usize> {
self.reader.read(writer)
}
fn write(&self, reader: &mut VmReader) -> Result<usize> {
self.writer.write(reader)
}
fn access_mode(&self) -> AccessMode {
AccessMode::O_RDWR
}
fn metadata(&self) -> Metadata {
self.reader.metadata()
}
}

View File

@ -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<PipeReader>, Arc<PipeWriter>)> {
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<PipeReader>, Arc<PipeWriter>)> {
let (producer, consumer) = Channel::with_capacity(capacity).split();
Ok((
PipeReader::new(consumer, StatusFlags::empty())?,
PipeWriter::new(producer, StatusFlags::empty())?,
))
}
pub struct PipeReader {
consumer: Consumer<u8>,
status_flags: AtomicU32,
@ -228,7 +248,7 @@ mod test {
W: Fn(Arc<PipeWriter>) + Sync + Send + 'static,
R: Fn(Arc<PipeReader>) + 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();

View File

@ -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<dyn Device>),
Socket,
NamedPipe(NamedPipe),
}
impl Inner {
@ -472,6 +482,17 @@ impl RamInode {
})
}
fn new_named_pipe(fs: &Arc<RamFS>, mode: InodeMode, uid: Uid, gid: Gid) -> Arc<Self> {
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<Arc<Self>> {
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();

View File

@ -25,7 +25,7 @@ impl<T> Channel<T> {
/// # 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<usize>);
let channel = Channel::new(16);
let channel = Channel::with_capacity(16);
let (producer, consumer) = channel.split();
let data = NonCopy(Arc::new(99));

View File

@ -20,8 +20,8 @@ impl Connected {
addr: Option<UnixSocketAddrBound>,
peer_addr: Option<UnixSocketAddrBound>,
) -> (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(),

View File

@ -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"),

View File

@ -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<SyscallReturn> {
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;