Add trait FileIo and refactor current devices

This commit is contained in:
Jianfeng Jiang 2023-11-16 17:26:42 +08:00 committed by Tate, Hongliang Tian
parent 43fd1a52fa
commit 001326110e
15 changed files with 147 additions and 153 deletions

View File

@ -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")?;

View File

@ -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<usize> {
Ok(0)
}
@ -20,4 +25,9 @@ impl Device for Null {
fn write(&self, buf: &[u8]) -> Result<usize> {
Ok(buf.len())
}
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
let events = IoEvents::IN | IoEvents::OUT;
events & mask
}
}

View File

@ -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<usize> {
Self::getrandom(buf)
}
@ -27,6 +32,11 @@ impl Device for Random {
fn write(&self, buf: &[u8]) -> Result<usize> {
Ok(buf.len())
}
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
let events = IoEvents::IN | IoEvents::OUT;
events & mask
}
}
impl From<getrandom::Error> for Error {

View File

@ -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<usize> {
Self::getrandom(buf)
}
@ -27,4 +32,9 @@ impl Device for Urandom {
fn write(&self, buf: &[u8]) -> Result<usize> {
Ok(buf.len())
}
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
let events = IoEvents::IN | IoEvents::OUT;
events & mask
}
}

View File

@ -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<usize> {
for byte in buf.iter_mut() {
*byte = 0;
@ -23,4 +28,9 @@ impl Device for Zero {
fn write(&self, buf: &[u8]) -> Result<usize> {
Ok(buf.len())
}
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
let events = IoEvents::IN | IoEvents::OUT;
events & mask
}
}

View File

@ -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<usize>;
/// Write to the device.
fn write(&self, buf: &[u8]) -> Result<usize>;
/// 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<i32> {
return_errno_with_message!(Errno::EINVAL, "ioctl is not supported");
/// Open a device.
fn open(&self) -> Result<Option<Arc<dyn FileIo>>> {
Ok(None)
}
}

View File

@ -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<PtyMaster>);
impl PtyMasterInode {
pub fn new(device: Arc<PtyMaster>) -> Arc<Self> {
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::<DevPts>().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<usize> {
self.0.read(buf)
}
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
self.0.read(buf)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.0.write(buf)
}
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.0.write(buf)
}
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
self.0.ioctl(cmd, arg)
}
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
self.0.poll(mask, poller)
}
fn fs(&self) -> Arc<dyn FileSystem> {
self.0.ptmx().fs()
}
}

View File

@ -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<PtyMasterInode>, Arc<PtySlaveInode>)> {
fn create_master_slave_pair(&self) -> Result<(Arc<PtyMaster>, Arc<PtySlaveInode>)> {
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<Arc<PtySlaveInode>> {
pub fn remove_slave(&self, index: u32) -> Option<Arc<PtySlaveInode>> {
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()

View File

@ -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<DevPts>,
}
#[derive(Clone)]
struct Inner(Weak<DevPts>);
impl Ptmx {
pub fn new(sb: &SuperBlock, fs: Weak<DevPts>) -> Arc<Self> {
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<Arc<PtyMasterInode>> {
pub fn open(&self) -> Result<Arc<PtyMaster>> {
let (master, _) = self.devpts().create_master_slave_pair()?;
Ok(master)
}
pub fn devpts(&self) -> Arc<DevPts> {
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<Arc<dyn Device>> {
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<Option<Arc<dyn FileIo>>> {
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<usize> {
// do nothing because it should not be used to read.
Ok(0)
unreachable!()
}
fn write(&self, buf: &[u8]) -> Result<usize> {
// do nothing because it should not be used to write.
Ok(buf.len())
unreachable!()
}
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
unreachable!()
}
}

View File

@ -1,4 +1,5 @@
use crate::events::IoEvents;
use crate::fs::inode_handle::FileIo;
use crate::prelude::*;
use crate::process::signal::Poller;

View File

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

View File

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

View File

@ -21,8 +21,16 @@ impl InodeHandle<Rights> {
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<Rights> {
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<Rights> {
}
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<i32> {
self.dentry().inode().ioctl(cmd, arg)
self.0.ioctl(cmd, arg)
}
fn metadata(&self) -> Metadata {
@ -109,6 +118,6 @@ impl FileLike for InodeHandle<Rights> {
}
fn as_device(&self) -> Option<Arc<dyn Device>> {
self.dentry().vnode().as_device()
self.dentry().inode().as_device()
}
}

View File

@ -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<R = Rights>(Arc<InodeHandle_>, R);
struct InodeHandle_ {
dentry: Arc<Dentry>,
/// `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<Arc<dyn FileIo>>,
offset: Mutex<usize>,
access_mode: AccessMode,
status_flags: AtomicU32,
@ -26,6 +32,11 @@ struct InodeHandle_ {
impl InodeHandle_ {
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
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<usize> {
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<u8>) -> Result<usize> {
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<i32> {
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<R> InodeHandle<R> {
&self.0.dentry
}
}
pub trait FileIo: Send + Sync + 'static {
fn read(&self, buf: &mut [u8]) -> Result<usize>;
fn write(&self, buf: &[u8]) -> Result<usize>;
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents;
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
return_errno_with_message!(Errno::EINVAL, "ioctl is not supported");
}
}

View File

@ -91,7 +91,7 @@ impl DirOps for RootDirOps {
SelfSymOps::new_inode(this_ptr.clone())
} else if let Ok(pid) = name.parse::<Pid>() {
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);