Add support for DevFS

This commit is contained in:
LI Qing
2023-05-18 16:57:29 +08:00
committed by Tate, Hongliang Tian
parent cc2ab9d5d4
commit 6f321ad7b7
25 changed files with 482 additions and 181 deletions

View File

@ -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(())
}

View File

@ -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<usize> {
Ok(0)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
Ok(buf.len())
}
}

View File

@ -1,10 +1,7 @@
use self::line_discipline::LineDiscipline; use self::line_discipline::LineDiscipline;
use super::*;
use crate::driver::tty::TtyDriver; use crate::driver::tty::TtyDriver;
use crate::fs::utils::{InodeMode, InodeType, IoEvents, Metadata}; use crate::fs::utils::{IoEvents, IoctlCmd, Poller};
use crate::fs::{
file_handle::FileLike,
utils::{IoctlCmd, Poller},
};
use crate::prelude::*; use crate::prelude::*;
use crate::process::Pgid; use crate::process::Pgid;
use crate::util::{read_val_from_user, write_val_to_user}; 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<usize> { fn read(&self, buf: &mut [u8]) -> Result<usize> {
self.ldisc.read(buf) self.ldisc.read(buf)
} }
@ -110,25 +116,6 @@ impl FileLike for Tty {
_ => todo!(), _ => 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? /// FIXME: should we maintain a static console?

View File

@ -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<usize> {
for byte in buf.iter_mut() {
*byte = 0;
}
Ok(buf.len())
}
fn write(&self, buf: &[u8]) -> Result<usize> {
Ok(buf.len())
}
}

View File

@ -1,8 +1,8 @@
pub use jinux_frame::arch::x86::device::serial::register_serial_input_callback; pub use jinux_frame::arch::x86::device::serial::register_serial_input_callback;
use crate::{ use crate::{
device::tty::{get_n_tty, Tty},
prelude::*, prelude::*,
tty::{get_n_tty, Tty},
}; };
lazy_static! { lazy_static! {

View File

@ -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<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");
}
}
/// 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<u64> 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<dyn Device>, path: &str) -> Result<Arc<Dentry>> {
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(())
}

View File

@ -3,7 +3,6 @@
use crate::events::Observer; use crate::events::Observer;
use crate::fs::utils::{AccessMode, IoEvents, IoctlCmd, Metadata, Poller, SeekFrom, StatusFlags}; use crate::fs::utils::{AccessMode, IoEvents, IoctlCmd, Metadata, Poller, SeekFrom, StatusFlags};
use crate::prelude::*; use crate::prelude::*;
use crate::tty::get_n_tty;
use core::any::Any; use core::any::Any;
@ -18,14 +17,7 @@ pub trait FileLike: Send + Sync + Any {
} }
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> { fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
match cmd { return_errno_with_message!(Errno::EINVAL, "ioctl is not supported");
IoctlCmd::TCGETS => {
// FIXME: only a work around
let tty = get_n_tty();
tty.ioctl(cmd, arg)
}
_ => panic!("Ioctl unsupported"),
}
} }
fn poll(&self, _mask: IoEvents, _poller: Option<&Poller>) -> IoEvents { fn poll(&self, _mask: IoEvents, _poller: Option<&Poller>) -> IoEvents {

View File

@ -1,6 +1,5 @@
use crate::prelude::*; use crate::prelude::*;
use alloc::str; use alloc::str;
use alloc::string::String;
use super::file_table::FileDescripter; use super::file_table::FileDescripter;
use super::inode_handle::InodeHandle; use super::inode_handle::InodeHandle;
@ -12,19 +11,21 @@ use super::utils::{
}; };
lazy_static! { lazy_static! {
static ref RAM_FS: Arc<dyn FileSystem> = RamFS::new(); static ref ROOT_FS: Arc<dyn FileSystem> = RamFS::new(true);
static ref ROOT_DENTRY: Arc<Dentry> = { static ref ROOT_DENTRY: Arc<Dentry> = {
fn init() -> Result<Arc<Dentry>> { let vnode = Vnode::new(ROOT_FS.root_inode()).unwrap();
let root_vnode = Vnode::new(RAM_FS.root_inode())?; Dentry::new_root(vnode)
Ok(Dentry::new_root(root_vnode))
}
init().unwrap()
}; };
static ref PROC_FS: Arc<dyn FileSystem> = ProcFS::new(); static ref PROC_FS: Arc<dyn FileSystem> = ProcFS::new();
static ref PROC_DENTRY: Arc<Dentry> = { static ref PROC_DENTRY: Arc<Dentry> = {
let vnode = Vnode::new(PROC_FS.root_inode()).unwrap(); let vnode = Vnode::new(PROC_FS.root_inode()).unwrap();
Dentry::new_root(vnode) Dentry::new_root(vnode)
}; };
static ref DEV_FS: Arc<dyn FileSystem> = RamFS::new(false);
static ref DEV_DENTRY: Arc<Dentry> = {
let vnode = Vnode::new(DEV_FS.root_inode()).unwrap();
Dentry::new_root(vnode)
};
} }
pub struct FsResolver { pub struct FsResolver {
@ -141,6 +142,13 @@ impl FsResolver {
path.trim_start_matches('/'), path.trim_start_matches('/'),
follow_tail_link, 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 { } else {
self.lookup_from_parent( self.lookup_from_parent(
&self.root, &self.root,

View File

@ -76,6 +76,10 @@ impl FileLike for InodeHandle<Rights> {
self.dentry().vnode().poll(mask, poller) self.dentry().vnode().poll(mask, poller)
} }
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
self.dentry().vnode().ioctl(cmd, arg)
}
fn metadata(&self) -> Metadata { fn metadata(&self) -> Metadata {
self.dentry().vnode().metadata() self.dentry().vnode().metadata()
} }

View File

@ -7,7 +7,8 @@ use core::sync::atomic::{AtomicU32, Ordering};
use crate::fs::file_handle::FileLike; use crate::fs::file_handle::FileLike;
use crate::fs::utils::{ 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::prelude::*;
use crate::rights::Rights; use crate::rights::Rights;

View File

@ -1,3 +1,4 @@
pub mod device;
pub mod epoll; pub mod epoll;
pub mod file_handle; pub mod file_handle;
pub mod file_table; pub mod file_table;

View File

@ -1,10 +1,8 @@
use core::time::Duration; use core::time::Duration;
use jinux_frame::vm::VmFrame;
use jinux_util::slot_vec::SlotVec; use jinux_util::slot_vec::SlotVec;
use crate::fs::utils::{ use crate::fs::device::Device;
DirentVisitor, FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata, use crate::fs::utils::{DirentVisitor, FileSystem, Inode, InodeMode, InodeType, Metadata};
};
use crate::prelude::*; use crate::prelude::*;
use super::{ProcFS, ProcInodeInfo}; use super::{ProcFS, ProcInodeInfo};
@ -78,23 +76,16 @@ impl<D: DirOps + 'static> Inode for ProcDir<D> {
fn set_mtime(&self, _time: Duration) {} fn set_mtime(&self, _time: Duration) {}
fn read_page(&self, _idx: usize, _frame: &VmFrame) -> Result<()> { fn create(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result<Arc<dyn Inode>> {
Err(Error::new(Errno::EISDIR)) Err(Error::new(Errno::EPERM))
} }
fn write_page(&self, _idx: usize, _frame: &VmFrame) -> Result<()> { fn mknod(
Err(Error::new(Errno::EISDIR)) &self,
} _name: &str,
_mode: InodeMode,
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize> { _device: Arc<dyn Device>,
Err(Error::new(Errno::EISDIR)) ) -> Result<Arc<dyn Inode>> {
}
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
Err(Error::new(Errno::EISDIR))
}
fn mknod(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result<Arc<dyn Inode>> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))
} }
@ -186,18 +177,6 @@ impl<D: DirOps + 'static> Inode for ProcDir<D> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))
} }
fn read_link(&self) -> Result<String> {
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<()> { fn sync(&self) -> Result<()> {
Ok(()) Ok(())
} }

View File

@ -1,9 +1,7 @@
use core::time::Duration; use core::time::Duration;
use jinux_frame::vm::VmFrame; use jinux_frame::vm::VmFrame;
use crate::fs::utils::{ use crate::fs::utils::{FileSystem, Inode, InodeMode, IoctlCmd, Metadata};
DirentVisitor, FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata,
};
use crate::prelude::*; use crate::prelude::*;
use super::{ProcFS, ProcInodeInfo}; use super::{ProcFS, ProcInodeInfo};
@ -72,34 +70,6 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))
} }
fn mknod(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result<Arc<dyn Inode>> {
Err(Error::new(Errno::ENOTDIR))
}
fn readdir_at(&self, _offset: usize, _visitor: &mut dyn DirentVisitor) -> Result<usize> {
Err(Error::new(Errno::ENOTDIR))
}
fn link(&self, _old: &Arc<dyn Inode>, _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<Arc<dyn Inode>> {
Err(Error::new(Errno::ENOTDIR))
}
fn rename(&self, _old_name: &str, _target: &Arc<dyn Inode>, _new_name: &str) -> Result<()> {
Err(Error::new(Errno::ENOTDIR))
}
fn read_link(&self) -> Result<String> { fn read_link(&self) -> Result<String> {
Err(Error::new(Errno::EINVAL)) Err(Error::new(Errno::EINVAL))
} }
@ -108,7 +78,7 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
Err(Error::new(Errno::EINVAL)) Err(Error::new(Errno::EINVAL))
} }
fn ioctl(&self, _cmd: &IoctlCmd) -> Result<()> { fn ioctl(&self, _cmd: IoctlCmd, _arg: usize) -> Result<i32> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))
} }

View File

@ -1,9 +1,7 @@
use core::time::Duration; use core::time::Duration;
use jinux_frame::vm::VmFrame; use jinux_frame::vm::VmFrame;
use crate::fs::utils::{ use crate::fs::utils::{FileSystem, Inode, InodeMode, IoctlCmd, Metadata};
DirentVisitor, FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata,
};
use crate::prelude::*; use crate::prelude::*;
use super::{ProcFS, ProcInodeInfo}; use super::{ProcFS, ProcInodeInfo};
@ -67,34 +65,6 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))
} }
fn mknod(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result<Arc<dyn Inode>> {
Err(Error::new(Errno::ENOTDIR))
}
fn readdir_at(&self, _offset: usize, _visitor: &mut dyn DirentVisitor) -> Result<usize> {
Err(Error::new(Errno::ENOTDIR))
}
fn link(&self, _old: &Arc<dyn Inode>, _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<Arc<dyn Inode>> {
Err(Error::new(Errno::ENOTDIR))
}
fn rename(&self, _old_name: &str, _target: &Arc<dyn Inode>, _new_name: &str) -> Result<()> {
Err(Error::new(Errno::ENOTDIR))
}
fn read_link(&self) -> Result<String> { fn read_link(&self) -> Result<String> {
self.inner.read_link() self.inner.read_link()
} }
@ -103,7 +73,7 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))
} }
fn ioctl(&self, _cmd: &IoctlCmd) -> Result<()> { fn ioctl(&self, _cmd: IoctlCmd, _arg: usize) -> Result<i32> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))
} }

View File

@ -8,28 +8,40 @@ use jinux_util::slot_vec::SlotVec;
use spin::{RwLock, RwLockWriteGuard}; use spin::{RwLock, RwLockWriteGuard};
use super::*; use super::*;
use crate::fs::device::Device;
use crate::fs::utils::{ 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 { pub struct RamFS {
metadata: RwLock<SuperBlock>, metadata: RwLock<SuperBlock>,
root: Arc<RamInode>, root: Arc<RamInode>,
inode_allocator: AtomicUsize, inode_allocator: AtomicUsize,
flags: FsFlags,
} }
impl RamFS { impl RamFS {
pub fn new() -> Arc<Self> { pub fn new(use_pagecache: bool) -> Arc<Self> {
let sb = SuperBlock::new(RAMFS_MAGIC, BLOCK_SIZE, NAME_MAX); let sb = SuperBlock::new(RAMFS_MAGIC, BLOCK_SIZE, NAME_MAX);
let root = Arc::new(RamInode(RwLock::new(Inode_::new_dir( let root = Arc::new(RamInode(RwLock::new(Inode_::new_dir(
ROOT_INO, ROOT_INO,
InodeMode::from_bits_truncate(0o755), InodeMode::from_bits_truncate(0o755),
&sb, &sb,
)))); ))));
let flags = {
let mut flags = FsFlags::DENTRY_UNEVICTABLE;
if !use_pagecache {
flags |= FsFlags::NO_PAGECACHE;
}
flags
};
let ramfs = Arc::new(Self { let ramfs = Arc::new(Self {
metadata: RwLock::new(sb), metadata: RwLock::new(sb),
root, root,
inode_allocator: AtomicUsize::new(ROOT_INO + 1), inode_allocator: AtomicUsize::new(ROOT_INO + 1),
flags,
}); });
let mut root = ramfs.root.0.write(); let mut root = ramfs.root.0.write();
root.inner root.inner
@ -64,7 +76,7 @@ impl FileSystem for RamFS {
} }
fn flags(&self) -> FsFlags { 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<dyn Device>,
) -> 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) { pub fn inc_size(&mut self) {
self.metadata.size += 1; self.metadata.size += 1;
self.metadata.blocks = (self.metadata.size + BLOCK_SIZE - 1) / BLOCK_SIZE; self.metadata.blocks = (self.metadata.size + BLOCK_SIZE - 1) / BLOCK_SIZE;
@ -126,6 +154,7 @@ enum Inner {
Dir(DirEntry), Dir(DirEntry),
File, File,
SymLink(Str256), SymLink(Str256),
Device(Arc<dyn Device>),
} }
impl Inner { impl Inner {
@ -156,6 +185,13 @@ impl Inner {
_ => None, _ => None,
} }
} }
fn as_device(&self) -> Option<&Arc<dyn Device>> {
match self {
Inner::Device(device) => Some(device),
_ => None,
}
}
} }
struct DirEntry { struct DirEntry {
@ -320,11 +356,17 @@ impl Inode for RamInode {
Ok(()) Ok(())
} }
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> { fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result<usize> {
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"); return_errno_with_message!(Errno::EOPNOTSUPP, "direct read is not supported");
} }
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> { fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
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"); 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; self.0.write().metadata.mtime = time;
} }
fn mknod(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> { fn mknod(
&self,
name: &str,
mode: InodeMode,
device: Arc<dyn Device>,
) -> Result<Arc<dyn Inode>> {
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<Arc<dyn Inode>> {
if self.0.read().metadata.type_ != InodeType::Dir { if self.0.read().metadata.type_ != InodeType::Dir {
return_errno_with_message!(Errno::ENOTDIR, "self is not dir"); return_errno_with_message!(Errno::ENOTDIR, "self is not dir");
} }
@ -631,12 +707,24 @@ impl Inode for RamInode {
Ok(()) 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<dyn FileSystem> { fn fs(&self) -> Arc<dyn FileSystem> {
Weak::upgrade(&self.0.read().fs).unwrap() Weak::upgrade(&self.0.read().fs).unwrap()
} }
fn ioctl(&self, cmd: &IoctlCmd) -> Result<()> { fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
return_errno!(Errno::ENOSYS); 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");
} }
} }

View File

@ -1,6 +1,7 @@
use crate::device::tty::{get_n_tty, Tty};
use crate::prelude::*; use crate::prelude::*;
use crate::tty::{get_n_tty, Tty};
use super::device::Device;
use super::file_handle::FileLike; use super::file_handle::FileLike;
use super::file_table::FileDescripter; use super::file_table::FileDescripter;
use super::utils::{InodeMode, InodeType, IoEvents, Metadata, Poller, SeekFrom}; use super::utils::{InodeMode, InodeType, IoEvents, Metadata, Poller, SeekFrom};

View File

@ -1,4 +1,6 @@
use crate::fs::device::Device;
use crate::prelude::*; use crate::prelude::*;
use alloc::string::String; use alloc::string::String;
use core::time::Duration; use core::time::Duration;
@ -76,7 +78,26 @@ impl Dentry {
} }
let child = { 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<dyn Device>) -> Result<Arc<Self>> {
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); let dentry = Dentry::new(name, Some(self.this()), vnode);
children.insert_dentry(&dentry); children.insert_dentry(&dentry);
dentry dentry

View File

@ -6,6 +6,7 @@ use core::time::Duration;
use jinux_frame::vm::VmFrame; use jinux_frame::vm::VmFrame;
use super::{DirentVisitor, FileSystem, IoEvents, IoctlCmd, Poller, SuperBlock}; use super::{DirentVisitor, FileSystem, IoEvents, IoctlCmd, Poller, SuperBlock};
use crate::fs::device::{Device, DeviceType};
use crate::prelude::*; use crate::prelude::*;
#[repr(u32)] #[repr(u32)]
@ -20,6 +21,15 @@ pub enum InodeType {
Socket = 0o140000, Socket = 0o140000,
} }
impl From<DeviceType> for InodeType {
fn from(type_: DeviceType) -> InodeType {
match type_ {
DeviceType::CharDevice => InodeType::CharDevice,
DeviceType::BlockDevice => InodeType::BlockDevice,
}
}
}
bitflags! { bitflags! {
pub struct InodeMode: u16 { pub struct InodeMode: u16 {
/// set-user-ID /// set-user-ID
@ -77,7 +87,7 @@ impl InodeMode {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Metadata { pub struct Metadata {
pub dev: usize, pub dev: u64,
pub ino: usize, pub ino: usize,
pub size: usize, pub size: usize,
pub blk_size: usize, pub blk_size: usize,
@ -90,7 +100,7 @@ pub struct Metadata {
pub nlinks: usize, pub nlinks: usize,
pub uid: usize, pub uid: usize,
pub gid: usize, pub gid: usize,
pub rdev: usize, pub rdev: u64,
} }
impl Metadata { impl Metadata {
@ -150,6 +160,30 @@ impl Metadata {
rdev: 0, 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 { pub trait Inode: Any + Sync + Send {
@ -167,33 +201,65 @@ pub trait Inode: Any + Sync + Send {
fn set_mtime(&self, time: Duration); 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<usize>; fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
Err(Error::new(Errno::EISDIR))
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize>; fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
Err(Error::new(Errno::EISDIR))
}
fn mknod(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>>; fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> {
Err(Error::new(Errno::ENOTDIR))
}
fn readdir_at(&self, offset: usize, visitor: &mut dyn DirentVisitor) -> Result<usize>; fn mknod(&self, name: &str, mode: InodeMode, dev: Arc<dyn Device>) -> Result<Arc<dyn Inode>> {
Err(Error::new(Errno::ENOTDIR))
}
fn link(&self, old: &Arc<dyn Inode>, name: &str) -> Result<()>; fn readdir_at(&self, offset: usize, visitor: &mut dyn DirentVisitor) -> Result<usize> {
Err(Error::new(Errno::ENOTDIR))
}
fn unlink(&self, name: &str) -> Result<()>; fn link(&self, old: &Arc<dyn Inode>, 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<Arc<dyn Inode>>; fn rmdir(&self, name: &str) -> Result<()> {
Err(Error::new(Errno::ENOTDIR))
}
fn rename(&self, old_name: &str, target: &Arc<dyn Inode>, new_name: &str) -> Result<()>; fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>> {
Err(Error::new(Errno::ENOTDIR))
}
fn read_link(&self) -> Result<String>; fn rename(&self, old_name: &str, target: &Arc<dyn Inode>, new_name: &str) -> Result<()> {
Err(Error::new(Errno::ENOTDIR))
}
fn write_link(&self, target: &str) -> Result<()>; fn read_link(&self) -> Result<String> {
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<i32> {
Err(Error::new(Errno::EISDIR))
}
fn sync(&self) -> Result<()>; fn sync(&self) -> Result<()>;

View File

@ -1,9 +1,12 @@
use super::{ 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::prelude::*;
use crate::rights::Full; use crate::rights::Full;
use crate::vm::vmo::Vmo; use crate::vm::vmo::Vmo;
use alloc::string::String; use alloc::string::String;
use core::time::Duration; use core::time::Duration;
use jinux_frame::vm::VmIo; use jinux_frame::vm::VmIo;
@ -145,8 +148,13 @@ impl Vnode {
inner.inode.read_at(0, &mut buf[..file_len]) inner.inode.read_at(0, &mut buf[..file_len])
} }
pub fn mknod(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Self> { pub fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Self> {
let inode = self.inner.read().inode.mknod(name, type_, mode)?; let inode = self.inner.read().inode.create(name, type_, mode)?;
Self::new(inode)
}
pub fn mknod(&self, name: &str, mode: InodeMode, device: Arc<dyn Device>) -> Result<Self> {
let inode = self.inner.read().inode.mknod(name, mode, device)?;
Self::new(inode) Self::new(inode)
} }
@ -190,6 +198,10 @@ impl Vnode {
self.inner.read().inode.poll(mask, poller) self.inner.read().inode.poll(mask, poller)
} }
pub fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
self.inner.read().inode.ioctl(cmd, arg)
}
pub fn metadata(&self) -> Metadata { pub fn metadata(&self) -> Metadata {
self.inner.read().inode.metadata() self.inner.read().inode.metadata()
} }

View File

@ -31,6 +31,7 @@ extern crate lru;
#[macro_use] #[macro_use]
extern crate controlled; extern crate controlled;
pub mod device;
pub mod driver; pub mod driver;
pub mod error; pub mod error;
pub mod events; pub mod events;
@ -41,7 +42,6 @@ pub mod rights;
pub mod syscall; pub mod syscall;
pub mod thread; pub mod thread;
pub mod time; pub mod time;
pub mod tty;
mod util; mod util;
pub mod vm; pub mod vm;
@ -49,6 +49,7 @@ pub fn init(ramdisk: &[u8]) {
driver::init(); driver::init();
process::fifo_scheduler::init(); process::fifo_scheduler::init();
fs::initramfs::init(ramdisk).unwrap(); fs::initramfs::init(ramdisk).unwrap();
device::init().unwrap();
} }
fn init_thread() { fn init_thread() {

View File

@ -11,13 +11,13 @@ use self::signal::sig_queues::SigQueues;
use self::signal::signals::kernel::KernelSignal; use self::signal::signals::kernel::KernelSignal;
use self::signal::signals::Signal; use self::signal::signals::Signal;
use self::status::ProcessStatus; use self::status::ProcessStatus;
use crate::device::tty::get_n_tty;
use crate::fs::file_table::FileTable; use crate::fs::file_table::FileTable;
use crate::fs::fs_resolver::FsResolver; use crate::fs::fs_resolver::FsResolver;
use crate::fs::utils::FileCreationMask; use crate::fs::utils::FileCreationMask;
use crate::prelude::*; use crate::prelude::*;
use crate::rights::Full; use crate::rights::Full;
use crate::thread::{allocate_tid, thread_table, Thread}; use crate::thread::{allocate_tid, thread_table, Thread};
use crate::tty::get_n_tty;
use crate::vm::vmar::Vmar; use crate::vm::vmar::Vmar;
use jinux_frame::sync::WaitQueue; use jinux_frame::sync::WaitQueue;

View File

@ -6,7 +6,6 @@ use crate::fs::{
use crate::log_syscall_entry; use crate::log_syscall_entry;
use crate::prelude::*; use crate::prelude::*;
use crate::syscall::constants::MAX_FILENAME_LEN; use crate::syscall::constants::MAX_FILENAME_LEN;
use crate::tty::get_n_tty;
use crate::util::read_cstring_from_user; use crate::util::read_cstring_from_user;
use super::SyscallReturn; use super::SyscallReturn;
@ -46,14 +45,6 @@ pub fn sys_openat(
return Ok(SyscallReturn::Return(fd as _)); 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 // The common path
let current = current!(); let current = current!();
let file_handle = { let file_handle = {

View File

@ -81,7 +81,7 @@ pub const S_IFLNK: u32 = 0o120000;
#[repr(C)] #[repr(C)]
pub struct Stat { pub struct Stat {
/// ID of device containing file /// ID of device containing file
st_dev: usize, st_dev: u64,
/// Inode number /// Inode number
st_ino: usize, st_ino: usize,
/// Number of hard links /// Number of hard links
@ -95,7 +95,7 @@ pub struct Stat {
/// Padding bytes /// Padding bytes
__pad0: u32, __pad0: u32,
/// Device ID (if special file) /// Device ID (if special file)
st_rdev: usize, st_rdev: u64,
/// Total size, in bytes /// Total size, in bytes
st_size: isize, st_size: isize,
/// Block size for filesystem I/O /// Block size for filesystem I/O
@ -122,7 +122,7 @@ impl From<Metadata> for Stat {
st_uid: info.uid as u32, st_uid: info.uid as u32,
st_gid: info.gid as u32, st_gid: info.gid as u32,
__pad0: 0, __pad0: 0,
st_rdev: 0, st_rdev: info.rdev,
st_size: info.size as isize, st_size: info.size as isize,
st_blksize: info.blk_size as isize, st_blksize: info.blk_size as isize,
st_blocks: (info.blocks * (info.blk_size / 512)) as isize, // Number of 512B blocks st_blocks: (info.blocks * (info.blk_size / 512)) as isize, // Number of 512B blocks