From 001326110ec48be7173f70427acb45eec884e0a3 Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Thu, 16 Nov 2023 17:26:42 +0800 Subject: [PATCH] Add trait FileIo and refactor current devices --- services/libs/jinux-std/src/device/mod.rs | 6 +- services/libs/jinux-std/src/device/null.rs | 10 ++ services/libs/jinux-std/src/device/random.rs | 10 ++ services/libs/jinux-std/src/device/urandom.rs | 10 ++ services/libs/jinux-std/src/device/zero.rs | 10 ++ services/libs/jinux-std/src/fs/device.rs | 26 ++--- .../libs/jinux-std/src/fs/devpts/master.rs | 106 ------------------ services/libs/jinux-std/src/fs/devpts/mod.rs | 12 +- services/libs/jinux-std/src/fs/devpts/ptmx.rs | 38 ++++--- .../libs/jinux-std/src/fs/devpts/slave.rs | 1 + services/libs/jinux-std/src/fs/file_handle.rs | 4 +- services/libs/jinux-std/src/fs/file_table.rs | 2 +- .../jinux-std/src/fs/inode_handle/dyn_cap.rs | 15 ++- .../libs/jinux-std/src/fs/inode_handle/mod.rs | 48 ++++++++ services/libs/jinux-std/src/fs/procfs/mod.rs | 2 +- 15 files changed, 147 insertions(+), 153 deletions(-) delete mode 100644 services/libs/jinux-std/src/fs/devpts/master.rs diff --git a/services/libs/jinux-std/src/device/mod.rs b/services/libs/jinux-std/src/device/mod.rs index fa9e6a0d..2fc391ee 100644 --- a/services/libs/jinux-std/src/device/mod.rs +++ b/services/libs/jinux-std/src/device/mod.rs @@ -12,6 +12,8 @@ pub use pty::{PtyMaster, PtySlave}; pub use random::Random; pub use urandom::Urandom; +use self::tty::get_n_tty; + /// Init the device node in fs, must be called after mounting rootfs. pub fn init() -> Result<()> { let null = Arc::new(null::Null); @@ -19,7 +21,9 @@ pub fn init() -> Result<()> { let zero = Arc::new(zero::Zero); add_node(zero, "zero")?; tty::init(); - let tty = tty::get_n_tty().clone(); + let console = get_n_tty().clone(); + add_node(console, "console")?; + let tty = Arc::new(tty::TtyDevice); add_node(tty, "tty")?; let random = Arc::new(random::Random); add_node(random, "random")?; diff --git a/services/libs/jinux-std/src/device/null.rs b/services/libs/jinux-std/src/device/null.rs index dd64aa1a..7137a64e 100644 --- a/services/libs/jinux-std/src/device/null.rs +++ b/services/libs/jinux-std/src/device/null.rs @@ -1,5 +1,8 @@ use super::*; +use crate::events::IoEvents; +use crate::fs::inode_handle::FileIo; use crate::prelude::*; +use crate::process::signal::Poller; pub struct Null; @@ -12,7 +15,9 @@ impl Device for Null { // Same value with Linux DeviceId::new(1, 3) } +} +impl FileIo for Null { fn read(&self, _buf: &mut [u8]) -> Result { Ok(0) } @@ -20,4 +25,9 @@ impl Device for Null { fn write(&self, buf: &[u8]) -> Result { Ok(buf.len()) } + + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + let events = IoEvents::IN | IoEvents::OUT; + events & mask + } } diff --git a/services/libs/jinux-std/src/device/random.rs b/services/libs/jinux-std/src/device/random.rs index 91a0567c..4ed22a5e 100644 --- a/services/libs/jinux-std/src/device/random.rs +++ b/services/libs/jinux-std/src/device/random.rs @@ -1,5 +1,8 @@ +use crate::events::IoEvents; use crate::fs::device::{Device, DeviceId, DeviceType}; +use crate::fs::inode_handle::FileIo; use crate::prelude::*; +use crate::process::signal::Poller; pub struct Random; @@ -19,7 +22,9 @@ impl Device for Random { // The same value as Linux DeviceId::new(1, 8) } +} +impl FileIo for Random { fn read(&self, buf: &mut [u8]) -> Result { Self::getrandom(buf) } @@ -27,6 +32,11 @@ impl Device for Random { fn write(&self, buf: &[u8]) -> Result { Ok(buf.len()) } + + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + let events = IoEvents::IN | IoEvents::OUT; + events & mask + } } impl From for Error { diff --git a/services/libs/jinux-std/src/device/urandom.rs b/services/libs/jinux-std/src/device/urandom.rs index 529b3c8d..687ecb76 100644 --- a/services/libs/jinux-std/src/device/urandom.rs +++ b/services/libs/jinux-std/src/device/urandom.rs @@ -1,5 +1,8 @@ +use crate::events::IoEvents; use crate::fs::device::{Device, DeviceId, DeviceType}; +use crate::fs::inode_handle::FileIo; use crate::prelude::*; +use crate::process::signal::Poller; pub struct Urandom; @@ -19,7 +22,9 @@ impl Device for Urandom { // The same value as Linux DeviceId::new(1, 9) } +} +impl FileIo for Urandom { fn read(&self, buf: &mut [u8]) -> Result { Self::getrandom(buf) } @@ -27,4 +32,9 @@ impl Device for Urandom { fn write(&self, buf: &[u8]) -> Result { Ok(buf.len()) } + + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + let events = IoEvents::IN | IoEvents::OUT; + events & mask + } } diff --git a/services/libs/jinux-std/src/device/zero.rs b/services/libs/jinux-std/src/device/zero.rs index 7d5f1f22..e3b695cd 100644 --- a/services/libs/jinux-std/src/device/zero.rs +++ b/services/libs/jinux-std/src/device/zero.rs @@ -1,5 +1,8 @@ use super::*; +use crate::events::IoEvents; +use crate::fs::inode_handle::FileIo; use crate::prelude::*; +use crate::process::signal::Poller; pub struct Zero; @@ -12,7 +15,9 @@ impl Device for Zero { // Same value with Linux DeviceId::new(1, 5) } +} +impl FileIo for Zero { fn read(&self, buf: &mut [u8]) -> Result { for byte in buf.iter_mut() { *byte = 0; @@ -23,4 +28,9 @@ impl Device for Zero { fn write(&self, buf: &[u8]) -> Result { Ok(buf.len()) } + + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + let events = IoEvents::IN | IoEvents::OUT; + events & mask + } } diff --git a/services/libs/jinux-std/src/fs/device.rs b/services/libs/jinux-std/src/fs/device.rs index c85c74eb..b85c577d 100644 --- a/services/libs/jinux-std/src/fs/device.rs +++ b/services/libs/jinux-std/src/fs/device.rs @@ -1,33 +1,21 @@ -use crate::events::IoEvents; use crate::fs::fs_resolver::{FsPath, FsResolver}; use crate::fs::utils::Dentry; -use crate::fs::utils::{InodeMode, InodeType, IoctlCmd}; +use crate::fs::utils::{InodeMode, InodeType}; use crate::prelude::*; -use crate::process::signal::Poller; + +use super::inode_handle::FileIo; /// The abstract of device -pub trait Device: Sync + Send { +pub trait Device: Sync + Send + FileIo { /// Return the device type. fn type_(&self) -> DeviceType; /// Return the device ID. fn id(&self) -> DeviceId; - /// Read from the device. - fn read(&self, buf: &mut [u8]) -> Result; - - /// Write to the device. - fn write(&self, buf: &[u8]) -> Result; - - /// Poll on the device. - fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - let events = IoEvents::IN | IoEvents::OUT; - events & mask - } - - /// Ioctl on the device. - fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { - return_errno_with_message!(Errno::EINVAL, "ioctl is not supported"); + /// Open a device. + fn open(&self) -> Result>> { + Ok(None) } } diff --git a/services/libs/jinux-std/src/fs/devpts/master.rs b/services/libs/jinux-std/src/fs/devpts/master.rs deleted file mode 100644 index bfddebfc..00000000 --- a/services/libs/jinux-std/src/fs/devpts/master.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::events::IoEvents; -use crate::fs::file_handle::FileLike; -use crate::prelude::*; -use crate::process::signal::Poller; - -use super::*; - -use crate::device::PtyMaster; - -/// Pty master inode for the master device. -pub struct PtyMasterInode(Arc); - -impl PtyMasterInode { - pub fn new(device: Arc) -> Arc { - Arc::new(Self(device)) - } -} - -impl Drop for PtyMasterInode { - fn drop(&mut self) { - // Remove the slave from fs. - let fs = self.0.ptmx().fs(); - let devpts = fs.downcast_ref::().unwrap(); - - let index = self.0.index(); - devpts.remove_slave(index); - } -} - -impl Inode for PtyMasterInode { - /// Do not cache dentry in DCACHE. - /// - /// Each file descriptor obtained by opening "/dev/ptmx" is an independent pty master - /// with its own associated pty slave. - fn is_dentry_cacheable(&self) -> bool { - false - } - - fn len(&self) -> usize { - self.0.ptmx().metadata().size - } - - fn resize(&self, new_size: usize) {} - - fn metadata(&self) -> Metadata { - self.0.ptmx().metadata() - } - - fn type_(&self) -> InodeType { - self.0.ptmx().metadata().type_ - } - - fn mode(&self) -> InodeMode { - self.0.ptmx().metadata().mode - } - - fn set_mode(&self, mode: InodeMode) {} - - fn atime(&self) -> Duration { - self.0.ptmx().metadata().atime - } - - fn set_atime(&self, time: Duration) {} - - fn mtime(&self) -> Duration { - self.0.ptmx().metadata().mtime - } - - fn set_mtime(&self, time: Duration) {} - - fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> { - Ok(()) - } - - fn write_page(&self, idx: usize, frame: &VmFrame) -> Result<()> { - Ok(()) - } - - fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { - self.0.read(buf) - } - - fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result { - self.0.read(buf) - } - - fn write_at(&self, offset: usize, buf: &[u8]) -> Result { - self.0.write(buf) - } - - fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result { - self.0.write(buf) - } - - fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { - self.0.ioctl(cmd, arg) - } - - fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - self.0.poll(mask, poller) - } - - fn fs(&self) -> Arc { - self.0.ptmx().fs() - } -} diff --git a/services/libs/jinux-std/src/fs/devpts/mod.rs b/services/libs/jinux-std/src/fs/devpts/mod.rs index f960872e..25d115d4 100644 --- a/services/libs/jinux-std/src/fs/devpts/mod.rs +++ b/services/libs/jinux-std/src/fs/devpts/mod.rs @@ -1,3 +1,4 @@ +use crate::device::PtyMaster; use crate::fs::device::{Device, DeviceId, DeviceType}; use crate::fs::utils::{ DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata, @@ -9,11 +10,9 @@ use core::time::Duration; use jinux_frame::vm::VmFrame; use jinux_util::{id_allocator::IdAlloc, slot_vec::SlotVec}; -use self::master::PtyMasterInode; use self::ptmx::Ptmx; use self::slave::PtySlaveInode; -mod master; mod ptmx; mod slave; @@ -52,7 +51,7 @@ impl DevPts { } /// Create the master and slave pair. - fn create_master_slave_pair(&self) -> Result<(Arc, Arc)> { + fn create_master_slave_pair(&self) -> Result<(Arc, Arc)> { let index = self .index_alloc .lock() @@ -61,17 +60,16 @@ impl DevPts { let (master, slave) = crate::device::new_pty_pair(index as u32, self.root.ptmx.clone())?; - let master_inode = PtyMasterInode::new(master); let slave_inode = PtySlaveInode::new(slave, self.this.clone()); self.root.add_slave(index.to_string(), slave_inode.clone()); - Ok((master_inode, slave_inode)) + Ok((master, slave_inode)) } /// Remove the slave from fs. /// /// This is called when the master is being dropped. - fn remove_slave(&self, index: u32) -> Option> { + pub fn remove_slave(&self, index: u32) -> Option> { let removed_slave = self.root.remove_slave(&index.to_string()); if removed_slave.is_some() { self.index_alloc.lock().free(index as usize); @@ -241,7 +239,7 @@ impl Inode for RootInode { let inode = match name { "." | ".." => self.fs().root_inode(), // Call the "open" method of ptmx to create a master and slave pair. - "ptmx" => self.ptmx.open()?, + "ptmx" => self.ptmx.clone(), slave => self .slaves .read() diff --git a/services/libs/jinux-std/src/fs/devpts/ptmx.rs b/services/libs/jinux-std/src/fs/devpts/ptmx.rs index 148db47e..ba7ed482 100644 --- a/services/libs/jinux-std/src/fs/devpts/ptmx.rs +++ b/services/libs/jinux-std/src/fs/devpts/ptmx.rs @@ -1,4 +1,8 @@ +use crate::device::PtyMaster; +use crate::events::IoEvents; +use crate::fs::inode_handle::FileIo; use crate::prelude::*; +use crate::process::signal::Poller; use super::*; @@ -14,12 +18,14 @@ const PTMX_MINOR_NUM: u32 = 2; pub struct Ptmx { inner: Inner, metadata: Metadata, - fs: Weak, } +#[derive(Clone)] +struct Inner(Weak); + impl Ptmx { pub fn new(sb: &SuperBlock, fs: Weak) -> Arc { - let inner = Inner; + let inner = Inner(fs); Arc::new(Self { metadata: Metadata::new_device( PTMX_INO, @@ -28,20 +34,19 @@ impl Ptmx { &inner, ), inner, - fs, }) } /// The open method for ptmx. /// /// Creates a master and slave pair and returns the master inode. - pub fn open(&self) -> Result> { + pub fn open(&self) -> Result> { let (master, _) = self.devpts().create_master_slave_pair()?; Ok(master) } pub fn devpts(&self) -> Arc { - self.fs.upgrade().unwrap() + self.inner.0.upgrade().unwrap() } pub fn device_type(&self) -> DeviceType { @@ -121,13 +126,10 @@ impl Inode for Ptmx { } fn as_device(&self) -> Option> { - Some(Arc::new(self.inner)) + Some(Arc::new(self.inner.clone())) } } -#[derive(Clone, Copy)] -struct Inner; - impl Device for Inner { fn type_(&self) -> DeviceType { DeviceType::CharDevice @@ -137,13 +139,23 @@ impl Device for Inner { DeviceId::new(PTMX_MAJOR_NUM, PTMX_MINOR_NUM) } + fn open(&self) -> Result>> { + let devpts = self.0.upgrade().unwrap(); + let (master, _) = devpts.create_master_slave_pair()?; + Ok(Some(master as _)) + } +} + +impl FileIo for Inner { fn read(&self, buf: &mut [u8]) -> Result { - // do nothing because it should not be used to read. - Ok(0) + unreachable!() } fn write(&self, buf: &[u8]) -> Result { - // do nothing because it should not be used to write. - Ok(buf.len()) + unreachable!() + } + + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + unreachable!() } } diff --git a/services/libs/jinux-std/src/fs/devpts/slave.rs b/services/libs/jinux-std/src/fs/devpts/slave.rs index 86f474b0..408bdb15 100644 --- a/services/libs/jinux-std/src/fs/devpts/slave.rs +++ b/services/libs/jinux-std/src/fs/devpts/slave.rs @@ -1,4 +1,5 @@ use crate::events::IoEvents; +use crate::fs::inode_handle::FileIo; use crate::prelude::*; use crate::process::signal::Poller; diff --git a/services/libs/jinux-std/src/fs/file_handle.rs b/services/libs/jinux-std/src/fs/file_handle.rs index 76ed8d00..05dbe218 100644 --- a/services/libs/jinux-std/src/fs/file_handle.rs +++ b/services/libs/jinux-std/src/fs/file_handle.rs @@ -1,8 +1,8 @@ //! Opend File Handle -use crate::events::Observer; +use crate::events::{IoEvents, Observer}; use crate::fs::device::Device; -use crate::fs::utils::{AccessMode, IoEvents, IoctlCmd, Metadata, Poller, SeekFrom, StatusFlags}; +use crate::fs::utils::{AccessMode, IoctlCmd, Metadata, SeekFrom, StatusFlags}; use crate::net::socket::Socket; use crate::prelude::*; use crate::process::signal::Poller; diff --git a/services/libs/jinux-std/src/fs/file_table.rs b/services/libs/jinux-std/src/fs/file_table.rs index 39d3ef46..93e622df 100644 --- a/services/libs/jinux-std/src/fs/file_table.rs +++ b/services/libs/jinux-std/src/fs/file_table.rs @@ -27,7 +27,7 @@ impl FileTable { pub fn new_with_stdio() -> Self { let mut table = SlotVec::new(); let fs_resolver = FsResolver::new(); - let tty_path = FsPath::new(AT_FDCWD, "/dev/tty").expect("cannot find tty"); + let tty_path = FsPath::new(AT_FDCWD, "/dev/console").expect("cannot find tty"); let stdin = { let flags = AccessMode::O_RDONLY as u32; let mode = InodeMode::S_IRUSR; diff --git a/services/libs/jinux-std/src/fs/inode_handle/dyn_cap.rs b/services/libs/jinux-std/src/fs/inode_handle/dyn_cap.rs index 0e397e28..fae4407c 100644 --- a/services/libs/jinux-std/src/fs/inode_handle/dyn_cap.rs +++ b/services/libs/jinux-std/src/fs/inode_handle/dyn_cap.rs @@ -21,8 +21,16 @@ impl InodeHandle { if access_mode.is_writable() && inode.type_() == InodeType::Dir { return_errno_with_message!(Errno::EISDIR, "Directory cannot open to write"); } + + let file_io = if let Some(device) = inode.as_device() { + device.open()? + } else { + None + }; + let inner = Arc::new(InodeHandle_ { dentry, + file_io, offset: Mutex::new(0), access_mode, status_flags: AtomicU32::new(status_flags.bits()), @@ -42,6 +50,7 @@ impl InodeHandle { if !self.1.contains(Rights::READ) { return_errno_with_message!(Errno::EBADF, "File is not readable"); } + self.0.read_to_end(buf) } @@ -75,11 +84,11 @@ impl FileLike for InodeHandle { } fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - self.dentry().inode().poll(mask, poller) + self.0.poll(mask, poller) } fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { - self.dentry().inode().ioctl(cmd, arg) + self.0.ioctl(cmd, arg) } fn metadata(&self) -> Metadata { @@ -109,6 +118,6 @@ impl FileLike for InodeHandle { } fn as_device(&self) -> Option> { - self.dentry().vnode().as_device() + self.dentry().inode().as_device() } } diff --git a/services/libs/jinux-std/src/fs/inode_handle/mod.rs b/services/libs/jinux-std/src/fs/inode_handle/mod.rs index e3e778d0..665d6f49 100644 --- a/services/libs/jinux-std/src/fs/inode_handle/mod.rs +++ b/services/libs/jinux-std/src/fs/inode_handle/mod.rs @@ -5,12 +5,14 @@ mod static_cap; use core::sync::atomic::{AtomicU32, Ordering}; +use crate::events::IoEvents; use crate::fs::device::Device; use crate::fs::file_handle::FileLike; use crate::fs::utils::{ AccessMode, Dentry, DirentVisitor, InodeType, IoctlCmd, Metadata, SeekFrom, StatusFlags, }; use crate::prelude::*; +use crate::process::signal::Poller; use jinux_rights::Rights; #[derive(Debug)] @@ -18,6 +20,10 @@ pub struct InodeHandle(Arc, R); struct InodeHandle_ { dentry: Arc, + /// `file_io` is Similar to `file_private` field in `file` structure in linux. If + /// `file_io` is Some, typical file operations including `read`, `write`, `poll`, + /// `ioctl` will be provided by `file_io`, instead of `dentry`. + file_io: Option>, offset: Mutex, access_mode: AccessMode, status_flags: AtomicU32, @@ -26,6 +32,11 @@ struct InodeHandle_ { impl InodeHandle_ { pub fn read(&self, buf: &mut [u8]) -> Result { let mut offset = self.offset.lock(); + + if let Some(ref file_io) = self.file_io { + return file_io.read(buf); + } + let len = if self.status_flags().contains(StatusFlags::O_DIRECT) { self.dentry.inode().read_direct_at(*offset, buf)? } else { @@ -38,6 +49,11 @@ impl InodeHandle_ { pub fn write(&self, buf: &[u8]) -> Result { let mut offset = self.offset.lock(); + + if let Some(ref file_io) = self.file_io { + return file_io.write(buf); + } + if self.status_flags().contains(StatusFlags::O_APPEND) { *offset = self.dentry.inode_len(); } @@ -52,6 +68,10 @@ impl InodeHandle_ { } pub fn read_to_end(&self, buf: &mut Vec) -> Result { + if self.file_io.is_some() { + return_errno_with_message!(Errno::EINVAL, "file io does not support read to end"); + } + let len = if self.status_flags().contains(StatusFlags::O_DIRECT) { self.dentry.inode().read_direct_to_end(buf)? } else { @@ -118,6 +138,22 @@ impl InodeHandle_ { *offset += read_cnt; Ok(read_cnt) } + + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + if let Some(ref file_io) = self.file_io { + return file_io.poll(mask, poller); + } + + self.dentry.inode().poll(mask, poller) + } + + fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { + if let Some(ref file_io) = self.file_io { + return file_io.ioctl(cmd, arg); + } + + self.dentry.inode().ioctl(cmd, arg) + } } impl Debug for InodeHandle_ { @@ -137,3 +173,15 @@ impl InodeHandle { &self.0.dentry } } + +pub trait FileIo: Send + Sync + 'static { + fn read(&self, buf: &mut [u8]) -> Result; + + fn write(&self, buf: &[u8]) -> Result; + + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents; + + fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { + return_errno_with_message!(Errno::EINVAL, "ioctl is not supported"); + } +} diff --git a/services/libs/jinux-std/src/fs/procfs/mod.rs b/services/libs/jinux-std/src/fs/procfs/mod.rs index 2614b307..f1fec834 100644 --- a/services/libs/jinux-std/src/fs/procfs/mod.rs +++ b/services/libs/jinux-std/src/fs/procfs/mod.rs @@ -91,7 +91,7 @@ impl DirOps for RootDirOps { SelfSymOps::new_inode(this_ptr.clone()) } else if let Ok(pid) = name.parse::() { let process_ref = - process_table::pid_to_process(pid).ok_or_else(|| Error::new(Errno::ENOENT))?; + process_table::get_process(&pid).ok_or_else(|| Error::new(Errno::ENOENT))?; PidDirOps::new_inode(process_ref, this_ptr.clone()) } else { return_errno!(Errno::ENOENT);