diff --git a/services/libs/jinux-std/src/device/mod.rs b/services/libs/jinux-std/src/device/mod.rs new file mode 100644 index 000000000..2f1887c58 --- /dev/null +++ b/services/libs/jinux-std/src/device/mod.rs @@ -0,0 +1,17 @@ +mod null; +pub mod tty; +mod zero; + +use crate::fs::device::{add_node, Device, DeviceId, DeviceType}; +use crate::prelude::*; + +/// Init the device node in fs, must be called after mounting rootfs. +pub fn init() -> Result<()> { + let null = Arc::new(null::Null); + add_node(null, "null")?; + let zero = Arc::new(zero::Zero); + add_node(zero, "zero")?; + let tty = tty::get_n_tty().clone(); + add_node(tty, "tty")?; + Ok(()) +} diff --git a/services/libs/jinux-std/src/device/null.rs b/services/libs/jinux-std/src/device/null.rs new file mode 100644 index 000000000..dd64aa1aa --- /dev/null +++ b/services/libs/jinux-std/src/device/null.rs @@ -0,0 +1,23 @@ +use super::*; +use crate::prelude::*; + +pub struct Null; + +impl Device for Null { + fn type_(&self) -> DeviceType { + DeviceType::CharDevice + } + + fn id(&self) -> DeviceId { + // Same value with Linux + DeviceId::new(1, 3) + } + + fn read(&self, _buf: &mut [u8]) -> Result { + Ok(0) + } + + fn write(&self, buf: &[u8]) -> Result { + Ok(buf.len()) + } +} diff --git a/services/libs/jinux-std/src/tty/line_discipline.rs b/services/libs/jinux-std/src/device/tty/line_discipline.rs similarity index 100% rename from services/libs/jinux-std/src/tty/line_discipline.rs rename to services/libs/jinux-std/src/device/tty/line_discipline.rs diff --git a/services/libs/jinux-std/src/tty/mod.rs b/services/libs/jinux-std/src/device/tty/mod.rs similarity index 83% rename from services/libs/jinux-std/src/tty/mod.rs rename to services/libs/jinux-std/src/device/tty/mod.rs index 8bc8573da..b590efc82 100644 --- a/services/libs/jinux-std/src/tty/mod.rs +++ b/services/libs/jinux-std/src/device/tty/mod.rs @@ -1,10 +1,7 @@ use self::line_discipline::LineDiscipline; +use super::*; use crate::driver::tty::TtyDriver; -use crate::fs::utils::{InodeMode, InodeType, IoEvents, Metadata}; -use crate::fs::{ - file_handle::FileLike, - utils::{IoctlCmd, Poller}, -}; +use crate::fs::utils::{IoEvents, IoctlCmd, Poller}; use crate::prelude::*; use crate::process::Pgid; use crate::util::{read_val_from_user, write_val_to_user}; @@ -51,7 +48,16 @@ impl Tty { } } -impl FileLike for Tty { +impl Device for Tty { + fn type_(&self) -> DeviceType { + DeviceType::CharDevice + } + + fn id(&self) -> DeviceId { + // Same value with Linux + DeviceId::new(5, 0) + } + fn read(&self, buf: &mut [u8]) -> Result { self.ldisc.read(buf) } @@ -110,25 +116,6 @@ impl FileLike for Tty { _ => todo!(), } } - - fn metadata(&self) -> Metadata { - Metadata { - dev: 0, - ino: 0, - size: 0, - blk_size: 1024, - blocks: 0, - atime: Default::default(), - mtime: Default::default(), - ctime: Default::default(), - type_: InodeType::CharDevice, - mode: InodeMode::from_bits_truncate(0o666), - nlinks: 1, - uid: 0, - gid: 0, - rdev: 0, - } - } } /// FIXME: should we maintain a static console? diff --git a/services/libs/jinux-std/src/tty/termio.rs b/services/libs/jinux-std/src/device/tty/termio.rs similarity index 100% rename from services/libs/jinux-std/src/tty/termio.rs rename to services/libs/jinux-std/src/device/tty/termio.rs diff --git a/services/libs/jinux-std/src/device/zero.rs b/services/libs/jinux-std/src/device/zero.rs new file mode 100644 index 000000000..7d5f1f22d --- /dev/null +++ b/services/libs/jinux-std/src/device/zero.rs @@ -0,0 +1,26 @@ +use super::*; +use crate::prelude::*; + +pub struct Zero; + +impl Device for Zero { + fn type_(&self) -> DeviceType { + DeviceType::CharDevice + } + + fn id(&self) -> DeviceId { + // Same value with Linux + DeviceId::new(1, 5) + } + + fn read(&self, buf: &mut [u8]) -> Result { + for byte in buf.iter_mut() { + *byte = 0; + } + Ok(buf.len()) + } + + fn write(&self, buf: &[u8]) -> Result { + Ok(buf.len()) + } +} diff --git a/services/libs/jinux-std/src/driver/tty.rs b/services/libs/jinux-std/src/driver/tty.rs index 1b177ab6e..7256466cd 100644 --- a/services/libs/jinux-std/src/driver/tty.rs +++ b/services/libs/jinux-std/src/driver/tty.rs @@ -1,8 +1,8 @@ pub use jinux_frame::arch::x86::device::serial::register_serial_input_callback; use crate::{ + device::tty::{get_n_tty, Tty}, prelude::*, - tty::{get_n_tty, Tty}, }; lazy_static! { diff --git a/services/libs/jinux-std/src/fs/device.rs b/services/libs/jinux-std/src/fs/device.rs new file mode 100644 index 000000000..e62b6918b --- /dev/null +++ b/services/libs/jinux-std/src/fs/device.rs @@ -0,0 +1,143 @@ +use crate::fs::fs_resolver::{FsPath, FsResolver}; +use crate::fs::utils::Dentry; +use crate::fs::utils::{InodeMode, InodeType, IoEvents, IoctlCmd, Poller}; +use crate::prelude::*; + +/// The abstract of device +pub trait Device: Sync + Send { + /// 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"); + } +} + +/// Device type +pub enum DeviceType { + CharDevice, + BlockDevice, +} + +/// Device Id +pub struct DeviceId(u64); + +impl DeviceId { + pub fn new(major: u32, minor: u32) -> Self { + let major = major as u64; + let minor = minor as u64; + Self( + (major & 0xffff_f000) << 32 + | (major & 0x0000_0fff) << 8 + | (minor & 0xffff_ff00) << 12 + | (minor & 0x0000_00ff), + ) + } + + pub fn major(&self) -> u32 { + ((self.0 >> 32) & 0xffff_f000 | (self.0 >> 8) & 0x0000_0fff) as u32 + } + + pub fn minor(&self) -> u32 { + ((self.0 >> 12) & 0xffff_ff00 | self.0 & 0x0000_00ff) as u32 + } +} + +impl Into for DeviceId { + fn into(self) -> u64 { + self.0 + } +} + +/// Add a device node to FS for the device. +/// +/// If the parent path is not existing, `mkdir -p` the parent path. +/// This function is used in registering device. +pub fn add_node(device: Arc, path: &str) -> Result> { + let mut dentry = { + let fs_resolver = FsResolver::new(); + fs_resolver.lookup(&FsPath::try_from("/dev").unwrap())? + }; + let mut relative_path = { + let relative_path = path.trim_start_matches('/'); + if relative_path.is_empty() { + return_errno_with_message!(Errno::EINVAL, "invalid device path"); + } + relative_path + }; + + while !relative_path.is_empty() { + let (next_name, path_remain) = if let Some((prefix, suffix)) = relative_path.split_once('/') + { + (prefix, suffix.trim_start_matches('/')) + } else { + (relative_path, "") + }; + + match dentry.lookup(next_name) { + Ok(next_dentry) => { + if path_remain.is_empty() { + return_errno_with_message!(Errno::EEXIST, "device node is existing"); + } + dentry = next_dentry; + } + Err(_) => { + if path_remain.is_empty() { + // Create the device node + dentry = dentry.mknod( + next_name, + InodeMode::from_bits_truncate(0o666), + device.clone(), + )?; + } else { + // Mkdir parent path + dentry = dentry.create( + next_name, + InodeType::Dir, + InodeMode::from_bits_truncate(0o755), + )?; + } + } + } + relative_path = path_remain; + } + + Ok(dentry) +} + +/// Delete the device node from FS for the device. +/// +/// This function is used in unregistering device. +pub fn delete_node(path: &str) -> Result<()> { + let abs_path = { + let device_path = path.trim_start_matches('/'); + if device_path.is_empty() { + return_errno_with_message!(Errno::EINVAL, "invalid device path"); + } + String::from("/dev") + "/" + device_path + }; + + let (parent_dentry, name) = { + let fs_resolver = FsResolver::new(); + fs_resolver.lookup_dir_and_base_name(&FsPath::try_from(abs_path.as_str()).unwrap())? + }; + + parent_dentry.unlink(&name)?; + Ok(()) +} diff --git a/services/libs/jinux-std/src/fs/file_handle.rs b/services/libs/jinux-std/src/fs/file_handle.rs index b4aedaf3e..2596c39c1 100644 --- a/services/libs/jinux-std/src/fs/file_handle.rs +++ b/services/libs/jinux-std/src/fs/file_handle.rs @@ -3,7 +3,6 @@ use crate::events::Observer; use crate::fs::utils::{AccessMode, IoEvents, IoctlCmd, Metadata, Poller, SeekFrom, StatusFlags}; use crate::prelude::*; -use crate::tty::get_n_tty; use core::any::Any; @@ -18,14 +17,7 @@ pub trait FileLike: Send + Sync + Any { } fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { - match cmd { - IoctlCmd::TCGETS => { - // FIXME: only a work around - let tty = get_n_tty(); - tty.ioctl(cmd, arg) - } - _ => panic!("Ioctl unsupported"), - } + return_errno_with_message!(Errno::EINVAL, "ioctl is not supported"); } fn poll(&self, _mask: IoEvents, _poller: Option<&Poller>) -> IoEvents { diff --git a/services/libs/jinux-std/src/fs/fs_resolver.rs b/services/libs/jinux-std/src/fs/fs_resolver.rs index 76a6a3f88..e89f04ae7 100644 --- a/services/libs/jinux-std/src/fs/fs_resolver.rs +++ b/services/libs/jinux-std/src/fs/fs_resolver.rs @@ -1,6 +1,5 @@ use crate::prelude::*; use alloc::str; -use alloc::string::String; use super::file_table::FileDescripter; use super::inode_handle::InodeHandle; @@ -12,19 +11,21 @@ use super::utils::{ }; lazy_static! { - static ref RAM_FS: Arc = RamFS::new(); + static ref ROOT_FS: Arc = RamFS::new(true); static ref ROOT_DENTRY: Arc = { - fn init() -> Result> { - let root_vnode = Vnode::new(RAM_FS.root_inode())?; - Ok(Dentry::new_root(root_vnode)) - } - init().unwrap() + let vnode = Vnode::new(ROOT_FS.root_inode()).unwrap(); + Dentry::new_root(vnode) }; static ref PROC_FS: Arc = ProcFS::new(); static ref PROC_DENTRY: Arc = { let vnode = Vnode::new(PROC_FS.root_inode()).unwrap(); Dentry::new_root(vnode) }; + static ref DEV_FS: Arc = RamFS::new(false); + static ref DEV_DENTRY: Arc = { + let vnode = Vnode::new(DEV_FS.root_inode()).unwrap(); + Dentry::new_root(vnode) + }; } pub struct FsResolver { @@ -141,6 +142,13 @@ impl FsResolver { path.trim_start_matches('/'), follow_tail_link, )? + } else if path.starts_with("/dev") { + let path = path.strip_prefix("/dev").unwrap(); + self.lookup_from_parent( + &DEV_DENTRY, + path.trim_start_matches('/'), + follow_tail_link, + )? } else { self.lookup_from_parent( &self.root, 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 9e6ca4c44..ed67bbc7d 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 @@ -76,6 +76,10 @@ impl FileLike for InodeHandle { self.dentry().vnode().poll(mask, poller) } + fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { + self.dentry().vnode().ioctl(cmd, arg) + } + fn metadata(&self) -> Metadata { self.dentry().vnode().metadata() } 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 41e272e4b..721601548 100644 --- a/services/libs/jinux-std/src/fs/inode_handle/mod.rs +++ b/services/libs/jinux-std/src/fs/inode_handle/mod.rs @@ -7,7 +7,8 @@ use core::sync::atomic::{AtomicU32, Ordering}; use crate::fs::file_handle::FileLike; use crate::fs::utils::{ - AccessMode, Dentry, DirentVisitor, InodeType, IoEvents, Metadata, Poller, SeekFrom, StatusFlags, + AccessMode, Dentry, DirentVisitor, InodeType, IoEvents, IoctlCmd, Metadata, Poller, SeekFrom, + StatusFlags, }; use crate::prelude::*; use crate::rights::Rights; diff --git a/services/libs/jinux-std/src/fs/mod.rs b/services/libs/jinux-std/src/fs/mod.rs index e5bb7d21f..6d119ab41 100644 --- a/services/libs/jinux-std/src/fs/mod.rs +++ b/services/libs/jinux-std/src/fs/mod.rs @@ -1,3 +1,4 @@ +pub mod device; pub mod epoll; pub mod file_handle; pub mod file_table; diff --git a/services/libs/jinux-std/src/fs/procfs/template/dir.rs b/services/libs/jinux-std/src/fs/procfs/template/dir.rs index 8e2cc3271..831d23d80 100644 --- a/services/libs/jinux-std/src/fs/procfs/template/dir.rs +++ b/services/libs/jinux-std/src/fs/procfs/template/dir.rs @@ -1,10 +1,8 @@ use core::time::Duration; -use jinux_frame::vm::VmFrame; use jinux_util::slot_vec::SlotVec; -use crate::fs::utils::{ - DirentVisitor, FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata, -}; +use crate::fs::device::Device; +use crate::fs::utils::{DirentVisitor, FileSystem, Inode, InodeMode, InodeType, Metadata}; use crate::prelude::*; use super::{ProcFS, ProcInodeInfo}; @@ -78,23 +76,16 @@ impl Inode for ProcDir { fn set_mtime(&self, _time: Duration) {} - fn read_page(&self, _idx: usize, _frame: &VmFrame) -> Result<()> { - Err(Error::new(Errno::EISDIR)) + fn create(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result> { + Err(Error::new(Errno::EPERM)) } - fn write_page(&self, _idx: usize, _frame: &VmFrame) -> Result<()> { - Err(Error::new(Errno::EISDIR)) - } - - fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { - Err(Error::new(Errno::EISDIR)) - } - - fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { - Err(Error::new(Errno::EISDIR)) - } - - fn mknod(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result> { + fn mknod( + &self, + _name: &str, + _mode: InodeMode, + _device: Arc, + ) -> Result> { Err(Error::new(Errno::EPERM)) } @@ -186,18 +177,6 @@ impl Inode for ProcDir { Err(Error::new(Errno::EPERM)) } - fn read_link(&self) -> Result { - Err(Error::new(Errno::EISDIR)) - } - - fn write_link(&self, _target: &str) -> Result<()> { - Err(Error::new(Errno::EISDIR)) - } - - fn ioctl(&self, _cmd: &IoctlCmd) -> Result<()> { - Err(Error::new(Errno::EISDIR)) - } - fn sync(&self) -> Result<()> { Ok(()) } diff --git a/services/libs/jinux-std/src/fs/procfs/template/file.rs b/services/libs/jinux-std/src/fs/procfs/template/file.rs index bc88acfa9..e15a0d897 100644 --- a/services/libs/jinux-std/src/fs/procfs/template/file.rs +++ b/services/libs/jinux-std/src/fs/procfs/template/file.rs @@ -1,9 +1,7 @@ use core::time::Duration; use jinux_frame::vm::VmFrame; -use crate::fs::utils::{ - DirentVisitor, FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata, -}; +use crate::fs::utils::{FileSystem, Inode, InodeMode, IoctlCmd, Metadata}; use crate::prelude::*; use super::{ProcFS, ProcInodeInfo}; @@ -72,34 +70,6 @@ impl Inode for ProcFile { Err(Error::new(Errno::EPERM)) } - fn mknod(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result> { - Err(Error::new(Errno::ENOTDIR)) - } - - fn readdir_at(&self, _offset: usize, _visitor: &mut dyn DirentVisitor) -> Result { - Err(Error::new(Errno::ENOTDIR)) - } - - fn link(&self, _old: &Arc, _name: &str) -> Result<()> { - Err(Error::new(Errno::ENOTDIR)) - } - - fn unlink(&self, _name: &str) -> Result<()> { - Err(Error::new(Errno::ENOTDIR)) - } - - fn rmdir(&self, _name: &str) -> Result<()> { - Err(Error::new(Errno::ENOTDIR)) - } - - fn lookup(&self, _name: &str) -> Result> { - Err(Error::new(Errno::ENOTDIR)) - } - - fn rename(&self, _old_name: &str, _target: &Arc, _new_name: &str) -> Result<()> { - Err(Error::new(Errno::ENOTDIR)) - } - fn read_link(&self) -> Result { Err(Error::new(Errno::EINVAL)) } @@ -108,7 +78,7 @@ impl Inode for ProcFile { Err(Error::new(Errno::EINVAL)) } - fn ioctl(&self, _cmd: &IoctlCmd) -> Result<()> { + fn ioctl(&self, _cmd: IoctlCmd, _arg: usize) -> Result { Err(Error::new(Errno::EPERM)) } diff --git a/services/libs/jinux-std/src/fs/procfs/template/sym.rs b/services/libs/jinux-std/src/fs/procfs/template/sym.rs index 17d279c98..d26a185d7 100644 --- a/services/libs/jinux-std/src/fs/procfs/template/sym.rs +++ b/services/libs/jinux-std/src/fs/procfs/template/sym.rs @@ -1,9 +1,7 @@ use core::time::Duration; use jinux_frame::vm::VmFrame; -use crate::fs::utils::{ - DirentVisitor, FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata, -}; +use crate::fs::utils::{FileSystem, Inode, InodeMode, IoctlCmd, Metadata}; use crate::prelude::*; use super::{ProcFS, ProcInodeInfo}; @@ -67,34 +65,6 @@ impl Inode for ProcSym { Err(Error::new(Errno::EPERM)) } - fn mknod(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result> { - Err(Error::new(Errno::ENOTDIR)) - } - - fn readdir_at(&self, _offset: usize, _visitor: &mut dyn DirentVisitor) -> Result { - Err(Error::new(Errno::ENOTDIR)) - } - - fn link(&self, _old: &Arc, _name: &str) -> Result<()> { - Err(Error::new(Errno::ENOTDIR)) - } - - fn unlink(&self, _name: &str) -> Result<()> { - Err(Error::new(Errno::ENOTDIR)) - } - - fn rmdir(&self, _name: &str) -> Result<()> { - Err(Error::new(Errno::ENOTDIR)) - } - - fn lookup(&self, _name: &str) -> Result> { - Err(Error::new(Errno::ENOTDIR)) - } - - fn rename(&self, _old_name: &str, _target: &Arc, _new_name: &str) -> Result<()> { - Err(Error::new(Errno::ENOTDIR)) - } - fn read_link(&self) -> Result { self.inner.read_link() } @@ -103,7 +73,7 @@ impl Inode for ProcSym { Err(Error::new(Errno::EPERM)) } - fn ioctl(&self, _cmd: &IoctlCmd) -> Result<()> { + fn ioctl(&self, _cmd: IoctlCmd, _arg: usize) -> Result { Err(Error::new(Errno::EPERM)) } diff --git a/services/libs/jinux-std/src/fs/ramfs/fs.rs b/services/libs/jinux-std/src/fs/ramfs/fs.rs index 2d301194d..fe3d763ab 100644 --- a/services/libs/jinux-std/src/fs/ramfs/fs.rs +++ b/services/libs/jinux-std/src/fs/ramfs/fs.rs @@ -8,28 +8,40 @@ use jinux_util::slot_vec::SlotVec; use spin::{RwLock, RwLockWriteGuard}; use super::*; +use crate::fs::device::Device; use crate::fs::utils::{ - DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata, SuperBlock, + DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoEvents, IoctlCmd, Metadata, + Poller, SuperBlock, }; +/// A volatile file system whose data and metadata exists only in memory. pub struct RamFS { metadata: RwLock, root: Arc, inode_allocator: AtomicUsize, + flags: FsFlags, } impl RamFS { - pub fn new() -> Arc { + pub fn new(use_pagecache: bool) -> Arc { let sb = SuperBlock::new(RAMFS_MAGIC, BLOCK_SIZE, NAME_MAX); let root = Arc::new(RamInode(RwLock::new(Inode_::new_dir( ROOT_INO, InodeMode::from_bits_truncate(0o755), &sb, )))); + let flags = { + let mut flags = FsFlags::DENTRY_UNEVICTABLE; + if !use_pagecache { + flags |= FsFlags::NO_PAGECACHE; + } + flags + }; let ramfs = Arc::new(Self { metadata: RwLock::new(sb), root, inode_allocator: AtomicUsize::new(ROOT_INO + 1), + flags, }); let mut root = ramfs.root.0.write(); root.inner @@ -64,7 +76,7 @@ impl FileSystem for RamFS { } fn flags(&self) -> FsFlags { - FsFlags::DENTRY_UNEVICTABLE + self.flags } } @@ -105,6 +117,22 @@ impl Inode_ { } } + pub fn new_device( + ino: usize, + mode: InodeMode, + sb: &SuperBlock, + device: Arc, + ) -> Self { + let type_ = device.type_(); + let rdev = device.id().into(); + Self { + inner: Inner::Device(device), + metadata: Metadata::new_device(ino, mode, sb, type_, rdev), + this: Weak::default(), + fs: Weak::default(), + } + } + pub fn inc_size(&mut self) { self.metadata.size += 1; self.metadata.blocks = (self.metadata.size + BLOCK_SIZE - 1) / BLOCK_SIZE; @@ -126,6 +154,7 @@ enum Inner { Dir(DirEntry), File, SymLink(Str256), + Device(Arc), } impl Inner { @@ -156,6 +185,13 @@ impl Inner { _ => None, } } + + fn as_device(&self) -> Option<&Arc> { + match self { + Inner::Device(device) => Some(device), + _ => None, + } + } } struct DirEntry { @@ -320,11 +356,17 @@ impl Inode for RamInode { Ok(()) } - fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result { + if let Some(device) = self.0.read().inner.as_device() { + return device.read(buf); + } return_errno_with_message!(Errno::EOPNOTSUPP, "direct read is not supported"); } - fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + fn write_at(&self, _offset: usize, buf: &[u8]) -> Result { + if let Some(device) = self.0.read().inner.as_device() { + return device.write(buf); + } return_errno_with_message!(Errno::EOPNOTSUPP, "direct write is not supported"); } @@ -352,7 +394,41 @@ impl Inode for RamInode { self.0.write().metadata.mtime = time; } - fn mknod(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result> { + fn mknod( + &self, + name: &str, + mode: InodeMode, + device: Arc, + ) -> Result> { + if self.0.read().metadata.type_ != InodeType::Dir { + return_errno_with_message!(Errno::ENOTDIR, "self is not dir"); + } + let mut self_inode = self.0.write(); + if self_inode.inner.as_direntry().unwrap().contains_entry(name) { + return_errno_with_message!(Errno::EEXIST, "entry exists"); + } + let device_inode = { + let fs = self_inode.fs.upgrade().unwrap(); + let device_inode = Arc::new(RamInode(RwLock::new(Inode_::new_device( + fs.alloc_id(), + mode, + &fs.sb(), + device, + )))); + device_inode.0.write().fs = self_inode.fs.clone(); + device_inode.0.write().this = Arc::downgrade(&device_inode); + device_inode + }; + self_inode + .inner + .as_direntry_mut() + .unwrap() + .append_entry(name, device_inode.clone()); + self_inode.inc_size(); + Ok(device_inode) + } + + fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result> { if self.0.read().metadata.type_ != InodeType::Dir { return_errno_with_message!(Errno::ENOTDIR, "self is not dir"); } @@ -631,12 +707,24 @@ impl Inode for RamInode { Ok(()) } + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + if let Some(device) = self.0.read().inner.as_device() { + device.poll(mask, poller) + } else { + let events = IoEvents::IN | IoEvents::OUT; + events & mask + } + } + fn fs(&self) -> Arc { Weak::upgrade(&self.0.read().fs).unwrap() } - fn ioctl(&self, cmd: &IoctlCmd) -> Result<()> { - return_errno!(Errno::ENOSYS); + fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { + if let Some(device) = self.0.read().inner.as_device() { + return device.ioctl(cmd, arg); + } + return_errno_with_message!(Errno::EINVAL, "ioctl is not supported"); } } diff --git a/services/libs/jinux-std/src/fs/stdio.rs b/services/libs/jinux-std/src/fs/stdio.rs index 16ece7905..792bd12ce 100644 --- a/services/libs/jinux-std/src/fs/stdio.rs +++ b/services/libs/jinux-std/src/fs/stdio.rs @@ -1,6 +1,7 @@ +use crate::device::tty::{get_n_tty, Tty}; use crate::prelude::*; -use crate::tty::{get_n_tty, Tty}; +use super::device::Device; use super::file_handle::FileLike; use super::file_table::FileDescripter; use super::utils::{InodeMode, InodeType, IoEvents, Metadata, Poller, SeekFrom}; diff --git a/services/libs/jinux-std/src/fs/utils/dentry_cache.rs b/services/libs/jinux-std/src/fs/utils/dentry_cache.rs index 4b354c783..afdfb6f3f 100644 --- a/services/libs/jinux-std/src/fs/utils/dentry_cache.rs +++ b/services/libs/jinux-std/src/fs/utils/dentry_cache.rs @@ -1,4 +1,6 @@ +use crate::fs::device::Device; use crate::prelude::*; + use alloc::string::String; use core::time::Duration; @@ -76,7 +78,26 @@ impl Dentry { } let child = { - let vnode = self.vnode.mknod(name, type_, mode)?; + let vnode = self.vnode.create(name, type_, mode)?; + let dentry = Dentry::new(name, Some(self.this()), vnode); + children.insert_dentry(&dentry); + dentry + }; + Ok(child) + } + + /// Create a dentry by making a device inode. + pub fn mknod(&self, name: &str, mode: InodeMode, device: Arc) -> Result> { + if self.vnode.inode_type() != InodeType::Dir { + return_errno!(Errno::ENOTDIR); + } + let mut children = self.children.lock(); + if children.find_dentry(name).is_some() { + return_errno!(Errno::EEXIST); + } + + let child = { + let vnode = self.vnode.mknod(name, mode, device)?; let dentry = Dentry::new(name, Some(self.this()), vnode); children.insert_dentry(&dentry); dentry diff --git a/services/libs/jinux-std/src/fs/utils/inode.rs b/services/libs/jinux-std/src/fs/utils/inode.rs index 814ce3094..eef2abce0 100644 --- a/services/libs/jinux-std/src/fs/utils/inode.rs +++ b/services/libs/jinux-std/src/fs/utils/inode.rs @@ -6,6 +6,7 @@ use core::time::Duration; use jinux_frame::vm::VmFrame; use super::{DirentVisitor, FileSystem, IoEvents, IoctlCmd, Poller, SuperBlock}; +use crate::fs::device::{Device, DeviceType}; use crate::prelude::*; #[repr(u32)] @@ -20,6 +21,15 @@ pub enum InodeType { Socket = 0o140000, } +impl From for InodeType { + fn from(type_: DeviceType) -> InodeType { + match type_ { + DeviceType::CharDevice => InodeType::CharDevice, + DeviceType::BlockDevice => InodeType::BlockDevice, + } + } +} + bitflags! { pub struct InodeMode: u16 { /// set-user-ID @@ -77,7 +87,7 @@ impl InodeMode { #[derive(Debug, Clone)] pub struct Metadata { - pub dev: usize, + pub dev: u64, pub ino: usize, pub size: usize, pub blk_size: usize, @@ -90,7 +100,7 @@ pub struct Metadata { pub nlinks: usize, pub uid: usize, pub gid: usize, - pub rdev: usize, + pub rdev: u64, } impl Metadata { @@ -150,6 +160,30 @@ impl Metadata { rdev: 0, } } + pub fn new_device( + ino: usize, + mode: InodeMode, + sb: &SuperBlock, + type_: DeviceType, + rdev: u64, + ) -> Self { + Self { + dev: 0, + ino, + size: 0, + blk_size: sb.bsize, + blocks: 0, + atime: Default::default(), + mtime: Default::default(), + ctime: Default::default(), + type_: InodeType::from(type_), + mode, + nlinks: 1, + uid: 0, + gid: 0, + rdev, + } + } } pub trait Inode: Any + Sync + Send { @@ -167,33 +201,65 @@ pub trait Inode: Any + Sync + Send { fn set_mtime(&self, time: Duration); - fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()>; + fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> { + Err(Error::new(Errno::EISDIR)) + } - fn write_page(&self, idx: usize, frame: &VmFrame) -> Result<()>; + fn write_page(&self, idx: usize, frame: &VmFrame) -> Result<()> { + Err(Error::new(Errno::EISDIR)) + } - fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result; + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + Err(Error::new(Errno::EISDIR)) + } - fn write_at(&self, offset: usize, buf: &[u8]) -> Result; + fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + Err(Error::new(Errno::EISDIR)) + } - fn mknod(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result>; + fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result> { + Err(Error::new(Errno::ENOTDIR)) + } - fn readdir_at(&self, offset: usize, visitor: &mut dyn DirentVisitor) -> Result; + fn mknod(&self, name: &str, mode: InodeMode, dev: Arc) -> Result> { + Err(Error::new(Errno::ENOTDIR)) + } - fn link(&self, old: &Arc, name: &str) -> Result<()>; + fn readdir_at(&self, offset: usize, visitor: &mut dyn DirentVisitor) -> Result { + Err(Error::new(Errno::ENOTDIR)) + } - fn unlink(&self, name: &str) -> Result<()>; + fn link(&self, old: &Arc, name: &str) -> Result<()> { + Err(Error::new(Errno::ENOTDIR)) + } - fn rmdir(&self, name: &str) -> Result<()>; + fn unlink(&self, name: &str) -> Result<()> { + Err(Error::new(Errno::ENOTDIR)) + } - fn lookup(&self, name: &str) -> Result>; + fn rmdir(&self, name: &str) -> Result<()> { + Err(Error::new(Errno::ENOTDIR)) + } - fn rename(&self, old_name: &str, target: &Arc, new_name: &str) -> Result<()>; + fn lookup(&self, name: &str) -> Result> { + Err(Error::new(Errno::ENOTDIR)) + } - fn read_link(&self) -> Result; + fn rename(&self, old_name: &str, target: &Arc, new_name: &str) -> Result<()> { + Err(Error::new(Errno::ENOTDIR)) + } - fn write_link(&self, target: &str) -> Result<()>; + fn read_link(&self) -> Result { + Err(Error::new(Errno::EISDIR)) + } - fn ioctl(&self, cmd: &IoctlCmd) -> Result<()>; + fn write_link(&self, target: &str) -> Result<()> { + Err(Error::new(Errno::EISDIR)) + } + + fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { + Err(Error::new(Errno::EISDIR)) + } fn sync(&self) -> Result<()>; diff --git a/services/libs/jinux-std/src/fs/utils/vnode.rs b/services/libs/jinux-std/src/fs/utils/vnode.rs index 6168979d1..e4b947c97 100644 --- a/services/libs/jinux-std/src/fs/utils/vnode.rs +++ b/services/libs/jinux-std/src/fs/utils/vnode.rs @@ -1,9 +1,12 @@ use super::{ - DirentVisitor, FsFlags, Inode, InodeMode, InodeType, IoEvents, Metadata, PageCache, Poller, + DirentVisitor, FsFlags, Inode, InodeMode, InodeType, IoEvents, IoctlCmd, Metadata, PageCache, + Poller, }; +use crate::fs::device::Device; use crate::prelude::*; use crate::rights::Full; use crate::vm::vmo::Vmo; + use alloc::string::String; use core::time::Duration; use jinux_frame::vm::VmIo; @@ -145,8 +148,13 @@ impl Vnode { inner.inode.read_at(0, &mut buf[..file_len]) } - pub fn mknod(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result { - let inode = self.inner.read().inode.mknod(name, type_, mode)?; + pub fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result { + let inode = self.inner.read().inode.create(name, type_, mode)?; + Self::new(inode) + } + + pub fn mknod(&self, name: &str, mode: InodeMode, device: Arc) -> Result { + let inode = self.inner.read().inode.mknod(name, mode, device)?; Self::new(inode) } @@ -190,6 +198,10 @@ impl Vnode { self.inner.read().inode.poll(mask, poller) } + pub fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { + self.inner.read().inode.ioctl(cmd, arg) + } + pub fn metadata(&self) -> Metadata { self.inner.read().inode.metadata() } diff --git a/services/libs/jinux-std/src/lib.rs b/services/libs/jinux-std/src/lib.rs index 562eba47a..598e97fad 100644 --- a/services/libs/jinux-std/src/lib.rs +++ b/services/libs/jinux-std/src/lib.rs @@ -31,6 +31,7 @@ extern crate lru; #[macro_use] extern crate controlled; +pub mod device; pub mod driver; pub mod error; pub mod events; @@ -41,7 +42,6 @@ pub mod rights; pub mod syscall; pub mod thread; pub mod time; -pub mod tty; mod util; pub mod vm; @@ -49,6 +49,7 @@ pub fn init(ramdisk: &[u8]) { driver::init(); process::fifo_scheduler::init(); fs::initramfs::init(ramdisk).unwrap(); + device::init().unwrap(); } fn init_thread() { diff --git a/services/libs/jinux-std/src/process/mod.rs b/services/libs/jinux-std/src/process/mod.rs index 1b9849d17..db89a4e4c 100644 --- a/services/libs/jinux-std/src/process/mod.rs +++ b/services/libs/jinux-std/src/process/mod.rs @@ -11,13 +11,13 @@ use self::signal::sig_queues::SigQueues; use self::signal::signals::kernel::KernelSignal; use self::signal::signals::Signal; use self::status::ProcessStatus; +use crate::device::tty::get_n_tty; use crate::fs::file_table::FileTable; use crate::fs::fs_resolver::FsResolver; use crate::fs::utils::FileCreationMask; use crate::prelude::*; use crate::rights::Full; use crate::thread::{allocate_tid, thread_table, Thread}; -use crate::tty::get_n_tty; use crate::vm::vmar::Vmar; use jinux_frame::sync::WaitQueue; diff --git a/services/libs/jinux-std/src/syscall/open.rs b/services/libs/jinux-std/src/syscall/open.rs index 66f9daa66..9cab7a563 100644 --- a/services/libs/jinux-std/src/syscall/open.rs +++ b/services/libs/jinux-std/src/syscall/open.rs @@ -6,7 +6,6 @@ use crate::fs::{ use crate::log_syscall_entry; use crate::prelude::*; use crate::syscall::constants::MAX_FILENAME_LEN; -use crate::tty::get_n_tty; use crate::util::read_cstring_from_user; use super::SyscallReturn; @@ -46,14 +45,6 @@ pub fn sys_openat( return Ok(SyscallReturn::Return(fd as _)); } - if dirfd == AT_FDCWD && pathname == CString::new("/dev/tty")? { - let tty_file = get_n_tty().clone(); - let current = current!(); - let mut file_table = current.file_table().lock(); - let fd = file_table.insert(tty_file); - return Ok(SyscallReturn::Return(fd as _)); - } - // The common path let current = current!(); let file_handle = { diff --git a/services/libs/jinux-std/src/syscall/stat.rs b/services/libs/jinux-std/src/syscall/stat.rs index 042340faa..7dc19d990 100644 --- a/services/libs/jinux-std/src/syscall/stat.rs +++ b/services/libs/jinux-std/src/syscall/stat.rs @@ -81,7 +81,7 @@ pub const S_IFLNK: u32 = 0o120000; #[repr(C)] pub struct Stat { /// ID of device containing file - st_dev: usize, + st_dev: u64, /// Inode number st_ino: usize, /// Number of hard links @@ -95,7 +95,7 @@ pub struct Stat { /// Padding bytes __pad0: u32, /// Device ID (if special file) - st_rdev: usize, + st_rdev: u64, /// Total size, in bytes st_size: isize, /// Block size for filesystem I/O @@ -122,7 +122,7 @@ impl From for Stat { st_uid: info.uid as u32, st_gid: info.gid as u32, __pad0: 0, - st_rdev: 0, + st_rdev: info.rdev, st_size: info.size as isize, st_blksize: info.blk_size as isize, st_blocks: (info.blocks * (info.blk_size / 512)) as isize, // Number of 512B blocks