mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-24 01:43:22 +00:00
Add support for DevFS
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
cc2ab9d5d4
commit
6f321ad7b7
17
services/libs/jinux-std/src/device/mod.rs
Normal file
17
services/libs/jinux-std/src/device/mod.rs
Normal 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(())
|
||||
}
|
23
services/libs/jinux-std/src/device/null.rs
Normal file
23
services/libs/jinux-std/src/device/null.rs
Normal 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())
|
||||
}
|
||||
}
|
@ -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<usize> {
|
||||
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?
|
26
services/libs/jinux-std/src/device/zero.rs
Normal file
26
services/libs/jinux-std/src/device/zero.rs
Normal 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())
|
||||
}
|
||||
}
|
@ -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! {
|
||||
|
143
services/libs/jinux-std/src/fs/device.rs
Normal file
143
services/libs/jinux-std/src/fs/device.rs
Normal 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(())
|
||||
}
|
@ -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<i32> {
|
||||
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 {
|
||||
|
@ -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<dyn FileSystem> = RamFS::new();
|
||||
static ref ROOT_FS: Arc<dyn FileSystem> = RamFS::new(true);
|
||||
static ref ROOT_DENTRY: Arc<Dentry> = {
|
||||
fn init() -> Result<Arc<Dentry>> {
|
||||
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<dyn FileSystem> = ProcFS::new();
|
||||
static ref PROC_DENTRY: Arc<Dentry> = {
|
||||
let vnode = Vnode::new(PROC_FS.root_inode()).unwrap();
|
||||
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 {
|
||||
@ -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,
|
||||
|
@ -76,6 +76,10 @@ impl FileLike for InodeHandle<Rights> {
|
||||
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 {
|
||||
self.dentry().vnode().metadata()
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod device;
|
||||
pub mod epoll;
|
||||
pub mod file_handle;
|
||||
pub mod file_table;
|
||||
|
@ -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<D: DirOps + 'static> Inode for ProcDir<D> {
|
||||
|
||||
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<Arc<dyn Inode>> {
|
||||
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<usize> {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
|
||||
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 mknod(
|
||||
&self,
|
||||
_name: &str,
|
||||
_mode: InodeMode,
|
||||
_device: Arc<dyn Device>,
|
||||
) -> Result<Arc<dyn Inode>> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
@ -186,18 +177,6 @@ impl<D: DirOps + 'static> Inode for ProcDir<D> {
|
||||
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<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -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<F: FileOps + 'static> Inode for ProcFile<F> {
|
||||
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> {
|
||||
Err(Error::new(Errno::EINVAL))
|
||||
}
|
||||
@ -108,7 +78,7 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -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<S: SymOps + 'static> Inode for ProcSym<S> {
|
||||
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> {
|
||||
self.inner.read_link()
|
||||
}
|
||||
@ -103,7 +73,7 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -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<SuperBlock>,
|
||||
root: Arc<RamInode>,
|
||||
inode_allocator: AtomicUsize,
|
||||
flags: FsFlags,
|
||||
}
|
||||
|
||||
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 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<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) {
|
||||
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<dyn Device>),
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
@ -156,6 +185,13 @@ impl Inner {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_device(&self) -> Option<&Arc<dyn Device>> {
|
||||
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<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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@ -352,7 +394,41 @@ impl Inode for RamInode {
|
||||
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 {
|
||||
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<dyn FileSystem> {
|
||||
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<i32> {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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<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);
|
||||
children.insert_dentry(&dentry);
|
||||
dentry
|
||||
|
@ -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<DeviceType> 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<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<()>;
|
||||
|
||||
|
@ -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<Self> {
|
||||
let inode = self.inner.read().inode.mknod(name, type_, mode)?;
|
||||
pub fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Self> {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -190,6 +198,10 @@ impl Vnode {
|
||||
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 {
|
||||
self.inner.read().inode.metadata()
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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<Metadata> 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
|
||||
|
Reference in New Issue
Block a user