Remove Vnode to let the fs use PageCache for itself

This commit is contained in:
LI Qing
2023-09-13 12:07:58 +08:00
committed by Tate, Hongliang Tian
parent aeea333945
commit 98bf3d4845
30 changed files with 483 additions and 533 deletions

View File

@ -27,7 +27,7 @@ pub fn init() -> Result<()> {
InodeType::SymLink, InodeType::SymLink,
InodeMode::from_bits_truncate(0o777), InodeMode::from_bits_truncate(0o777),
)?; )?;
ptmx.write_link("pts/ptmx")?; ptmx.inode().write_link("pts/ptmx")?;
Ok(()) Ok(())
} }

View File

@ -46,6 +46,16 @@ impl Inode for PtyMasterInode {
self.0.ptmx().metadata() self.0.ptmx().metadata()
} }
fn type_(&self) -> InodeType {
self.0.ptmx().metadata().type_
}
fn mode(&self) -> InodeMode {
self.0.ptmx().metadata().mode
}
fn set_mode(&self, mode: InodeMode) {}
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.0.ptmx().metadata().atime self.0.ptmx().metadata().atime
} }
@ -58,8 +68,6 @@ impl Inode for PtyMasterInode {
fn set_mtime(&self, time: Duration) {} fn set_mtime(&self, time: Duration) {}
fn set_mode(&self, mode: InodeMode) {}
fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> { fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> {
Ok(()) Ok(())
} }
@ -72,10 +80,18 @@ impl Inode for PtyMasterInode {
self.0.read(buf) self.0.read(buf)
} }
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
self.0.read(buf)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> { fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.0.write(buf) self.0.write(buf)
} }
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.0.write(buf)
}
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> { fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
self.0.ioctl(cmd, arg) self.0.ioctl(cmd, arg)
} }

View File

@ -94,7 +94,7 @@ impl FileSystem for DevPts {
} }
fn flags(&self) -> FsFlags { fn flags(&self) -> FsFlags {
FsFlags::NO_PAGECACHE FsFlags::empty()
} }
} }
@ -148,6 +148,16 @@ impl Inode for RootInode {
self.metadata.clone() self.metadata.clone()
} }
fn type_(&self) -> InodeType {
self.metadata.type_
}
fn mode(&self) -> InodeMode {
self.metadata.mode
}
fn set_mode(&self, mode: InodeMode) {}
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.metadata.atime self.metadata.atime
} }
@ -160,8 +170,6 @@ impl Inode for RootInode {
fn set_mtime(&self, time: Duration) {} fn set_mtime(&self, time: Duration) {}
fn set_mode(&self, mode: InodeMode) {}
fn create(&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::EPERM)) Err(Error::new(Errno::EPERM))
} }

View File

@ -66,6 +66,16 @@ impl Inode for Ptmx {
self.metadata.clone() self.metadata.clone()
} }
fn type_(&self) -> InodeType {
self.metadata.type_
}
fn mode(&self) -> InodeMode {
self.metadata.mode
}
fn set_mode(&self, mode: InodeMode) {}
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.metadata.atime self.metadata.atime
} }
@ -78,8 +88,6 @@ impl Inode for Ptmx {
fn set_mtime(&self, time: Duration) {} fn set_mtime(&self, time: Duration) {}
fn set_mode(&self, mode: InodeMode) {}
fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> { fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> {
Ok(()) Ok(())
} }
@ -92,10 +100,18 @@ impl Inode for Ptmx {
Ok(0) Ok(0)
} }
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
Ok(0)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> { fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
Ok(0) Ok(0)
} }
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
Ok(0)
}
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> { fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
Ok(0) Ok(0)
} }

View File

@ -50,6 +50,16 @@ impl Inode for PtySlaveInode {
self.metadata.clone() self.metadata.clone()
} }
fn type_(&self) -> InodeType {
self.metadata.type_
}
fn mode(&self) -> InodeMode {
self.metadata.mode
}
fn set_mode(&self, mode: InodeMode) {}
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.metadata.atime self.metadata.atime
} }
@ -62,8 +72,6 @@ impl Inode for PtySlaveInode {
fn set_mtime(&self, time: Duration) {} fn set_mtime(&self, time: Duration) {}
fn set_mode(&self, mode: InodeMode) {}
fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> { fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> {
Ok(()) Ok(())
} }
@ -76,10 +84,18 @@ impl Inode for PtySlaveInode {
self.device.read(buf) self.device.read(buf)
} }
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
self.device.read(buf)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> { fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.device.write(buf) self.device.write(buf)
} }
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.device.write(buf)
}
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> { fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
self.device.ioctl(cmd, arg) self.device.ioctl(cmd, arg)
} }

View File

@ -62,8 +62,8 @@ impl FsResolver {
let follow_tail_link = !creation_flags.contains(CreationFlags::O_NOFOLLOW); let follow_tail_link = !creation_flags.contains(CreationFlags::O_NOFOLLOW);
let dentry = match self.lookup_inner(path, follow_tail_link) { let dentry = match self.lookup_inner(path, follow_tail_link) {
Ok(dentry) => { Ok(dentry) => {
let vnode = dentry.vnode(); let inode = dentry.inode();
if vnode.inode_type() == InodeType::SymLink if inode.type_() == InodeType::SymLink
&& !status_flags.contains(StatusFlags::O_PATH) && !status_flags.contains(StatusFlags::O_PATH)
{ {
return_errno_with_message!(Errno::ELOOP, "file is a symlink"); return_errno_with_message!(Errno::ELOOP, "file is a symlink");
@ -74,7 +74,7 @@ impl FsResolver {
return_errno_with_message!(Errno::EEXIST, "file exists"); return_errno_with_message!(Errno::EEXIST, "file exists");
} }
if creation_flags.contains(CreationFlags::O_DIRECTORY) if creation_flags.contains(CreationFlags::O_DIRECTORY)
&& vnode.inode_type() != InodeType::Dir && inode.type_() != InodeType::Dir
{ {
return_errno_with_message!( return_errno_with_message!(
Errno::ENOTDIR, Errno::ENOTDIR,
@ -95,7 +95,7 @@ impl FsResolver {
if file_name.ends_with('/') { if file_name.ends_with('/') {
return_errno_with_message!(Errno::EISDIR, "path refers to a directory"); return_errno_with_message!(Errno::EISDIR, "path refers to a directory");
} }
if !dir_dentry.vnode().inode_mode().is_writable() { if !dir_dentry.inode_mode().is_writable() {
return_errno_with_message!(Errno::EACCES, "file cannot be created"); return_errno_with_message!(Errno::EACCES, "file cannot be created");
} }
dir_dentry.create(&file_name, InodeType::File, inode_mode)? dir_dentry.create(&file_name, InodeType::File, inode_mode)?
@ -177,7 +177,7 @@ impl FsResolver {
// Iterate next dentry // Iterate next dentry
let next_dentry = dentry.lookup(next_name)?; let next_dentry = dentry.lookup(next_name)?;
let next_type = next_dentry.vnode().inode_type(); let next_type = next_dentry.inode_type();
let next_is_tail = path_remain.is_empty(); let next_is_tail = path_remain.is_empty();
// If next inode is a symlink, follow symlinks at most `SYMLINKS_MAX` times. // If next inode is a symlink, follow symlinks at most `SYMLINKS_MAX` times.
@ -186,7 +186,7 @@ impl FsResolver {
return_errno_with_message!(Errno::ELOOP, "too many symlinks"); return_errno_with_message!(Errno::ELOOP, "too many symlinks");
} }
let link_path_remain = { let link_path_remain = {
let mut tmp_link_path = next_dentry.vnode().read_link()?; let mut tmp_link_path = next_dentry.inode().read_link()?;
if tmp_link_path.is_empty() { if tmp_link_path.is_empty() {
return_errno_with_message!(Errno::ENOENT, "empty symlink"); return_errno_with_message!(Errno::ENOENT, "empty symlink");
} }
@ -275,9 +275,9 @@ impl FsResolver {
// Dereference the tail symlinks if needed // Dereference the tail symlinks if needed
loop { loop {
match dir_dentry.lookup(base_name.trim_end_matches('/')) { match dir_dentry.lookup(base_name.trim_end_matches('/')) {
Ok(dentry) if dentry.vnode().inode_type() == InodeType::SymLink => { Ok(dentry) if dentry.inode_type() == InodeType::SymLink => {
let link = { let link = {
let mut link = dentry.vnode().read_link()?; let mut link = dentry.inode().read_link()?;
if link.is_empty() { if link.is_empty() {
return_errno_with_message!(Errno::ENOENT, "invalid symlink"); return_errno_with_message!(Errno::ENOENT, "invalid symlink");
} }

View File

@ -11,14 +11,14 @@ impl InodeHandle<Rights> {
access_mode: AccessMode, access_mode: AccessMode,
status_flags: StatusFlags, status_flags: StatusFlags,
) -> Result<Self> { ) -> Result<Self> {
let vnode = dentry.vnode(); let inode = dentry.inode();
if access_mode.is_readable() && !vnode.inode_mode().is_readable() { if access_mode.is_readable() && !inode.mode().is_readable() {
return_errno_with_message!(Errno::EACCES, "File is not readable"); return_errno_with_message!(Errno::EACCES, "File is not readable");
} }
if access_mode.is_writable() && !vnode.inode_mode().is_writable() { if access_mode.is_writable() && !inode.mode().is_writable() {
return_errno_with_message!(Errno::EACCES, "File is not writable"); return_errno_with_message!(Errno::EACCES, "File is not writable");
} }
if access_mode.is_writable() && vnode.inode_type() == InodeType::Dir { if access_mode.is_writable() && inode.type_() == InodeType::Dir {
return_errno_with_message!(Errno::EISDIR, "Directory cannot open to write"); return_errno_with_message!(Errno::EISDIR, "Directory cannot open to write");
} }
let inner = Arc::new(InodeHandle_ { let inner = Arc::new(InodeHandle_ {
@ -75,15 +75,15 @@ impl FileLike for InodeHandle<Rights> {
} }
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
self.dentry().vnode().poll(mask, poller) self.dentry().inode().poll(mask, poller)
} }
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> { fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
self.dentry().vnode().ioctl(cmd, arg) self.dentry().inode().ioctl(cmd, arg)
} }
fn metadata(&self) -> Metadata { fn metadata(&self) -> Metadata {
self.dentry().vnode().metadata() self.dentry().inode_metadata()
} }
fn status_flags(&self) -> StatusFlags { fn status_flags(&self) -> StatusFlags {

View File

@ -26,9 +26,9 @@ impl InodeHandle_ {
pub fn read(&self, buf: &mut [u8]) -> Result<usize> { pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
let mut offset = self.offset.lock(); let mut offset = self.offset.lock();
let len = if self.status_flags().contains(StatusFlags::O_DIRECT) { let len = if self.status_flags().contains(StatusFlags::O_DIRECT) {
self.dentry.vnode().read_direct_at(*offset, buf)? self.dentry.inode().read_direct_at(*offset, buf)?
} else { } else {
self.dentry.vnode().read_at(*offset, buf)? self.dentry.inode().read_at(*offset, buf)?
}; };
*offset += len; *offset += len;
@ -38,12 +38,12 @@ impl InodeHandle_ {
pub fn write(&self, buf: &[u8]) -> Result<usize> { pub fn write(&self, buf: &[u8]) -> Result<usize> {
let mut offset = self.offset.lock(); let mut offset = self.offset.lock();
if self.status_flags().contains(StatusFlags::O_APPEND) { if self.status_flags().contains(StatusFlags::O_APPEND) {
*offset = self.dentry.vnode().len(); *offset = self.dentry.inode_len();
} }
let len = if self.status_flags().contains(StatusFlags::O_DIRECT) { let len = if self.status_flags().contains(StatusFlags::O_DIRECT) {
self.dentry.vnode().write_direct_at(*offset, buf)? self.dentry.inode().write_direct_at(*offset, buf)?
} else { } else {
self.dentry.vnode().write_at(*offset, buf)? self.dentry.inode().write_at(*offset, buf)?
}; };
*offset += len; *offset += len;
@ -52,9 +52,9 @@ impl InodeHandle_ {
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> { pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
let len = if self.status_flags().contains(StatusFlags::O_DIRECT) { let len = if self.status_flags().contains(StatusFlags::O_DIRECT) {
self.dentry.vnode().read_direct_to_end(buf)? self.dentry.inode().read_direct_to_end(buf)?
} else { } else {
self.dentry.vnode().read_to_end(buf)? self.dentry.inode().read_to_end(buf)?
}; };
Ok(len) Ok(len)
} }
@ -69,7 +69,7 @@ impl InodeHandle_ {
off as isize off as isize
} }
SeekFrom::End(off /* as isize */) => { SeekFrom::End(off /* as isize */) => {
let file_size = self.dentry.vnode().len() as isize; let file_size = self.dentry.inode_len() as isize;
assert!(file_size >= 0); assert!(file_size >= 0);
file_size file_size
.checked_add(off) .checked_add(off)
@ -94,7 +94,7 @@ impl InodeHandle_ {
} }
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.dentry.vnode().len() self.dentry.inode_len()
} }
pub fn access_mode(&self) -> AccessMode { pub fn access_mode(&self) -> AccessMode {
@ -113,7 +113,7 @@ impl InodeHandle_ {
pub fn readdir(&self, visitor: &mut dyn DirentVisitor) -> Result<usize> { pub fn readdir(&self, visitor: &mut dyn DirentVisitor) -> Result<usize> {
let mut offset = self.offset.lock(); let mut offset = self.offset.lock();
let read_cnt = self.dentry.vnode().readdir_at(*offset, visitor)?; let read_cnt = self.dentry.inode().readdir_at(*offset, visitor)?;
*offset += read_cnt; *offset += read_cnt;
Ok(read_cnt) Ok(read_cnt)
} }

View File

@ -61,7 +61,7 @@ impl FileSystem for ProcFS {
} }
fn flags(&self) -> FsFlags { fn flags(&self) -> FsFlags {
FsFlags::NO_PAGECACHE FsFlags::empty()
} }
} }

View File

@ -64,6 +64,18 @@ impl<D: DirOps + 'static> Inode for ProcDir<D> {
self.info.metadata() self.info.metadata()
} }
fn type_(&self) -> InodeType {
InodeType::Dir
}
fn mode(&self) -> InodeMode {
self.info.mode()
}
fn set_mode(&self, mode: InodeMode) {
self.info.set_mode(mode)
}
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.info.atime() self.info.atime()
} }
@ -80,10 +92,6 @@ impl<D: DirOps + 'static> Inode for ProcDir<D> {
self.info.set_mtime(time) self.info.set_mtime(time)
} }
fn set_mode(&self, mode: InodeMode) {
self.info.set_mode(mode)
}
fn create(&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::EPERM)) Err(Error::new(Errno::EPERM))
} }

View File

@ -1,7 +1,7 @@
use core::time::Duration; use core::time::Duration;
use jinux_frame::vm::VmFrame; use jinux_frame::vm::VmFrame;
use crate::fs::utils::{FileSystem, Inode, InodeMode, IoctlCmd, Metadata}; use crate::fs::utils::{FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata};
use crate::prelude::*; use crate::prelude::*;
use super::{ProcFS, ProcInodeInfo}; use super::{ProcFS, ProcInodeInfo};
@ -37,6 +37,18 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
self.info.metadata() self.info.metadata()
} }
fn type_(&self) -> InodeType {
InodeType::File
}
fn mode(&self) -> InodeMode {
self.info.mode()
}
fn set_mode(&self, mode: InodeMode) {
self.info.set_mode(mode)
}
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.info.atime() self.info.atime()
} }
@ -53,10 +65,6 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
self.info.set_mtime(time) self.info.set_mtime(time)
} }
fn set_mode(&self, mode: InodeMode) {
self.info.set_mode(mode)
}
fn read_page(&self, _idx: usize, _frame: &VmFrame) -> Result<()> { fn read_page(&self, _idx: usize, _frame: &VmFrame) -> Result<()> {
unreachable!() unreachable!()
} }
@ -74,10 +82,18 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
Ok(len) Ok(len)
} }
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
self.read_at(offset, buf)
}
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> { fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))
} }
fn write_direct_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
Err(Error::new(Errno::EPERM))
}
fn read_link(&self) -> Result<String> { fn read_link(&self) -> Result<String> {
Err(Error::new(Errno::EINVAL)) Err(Error::new(Errno::EINVAL))
} }

View File

@ -58,6 +58,10 @@ impl ProcInodeInfo {
self.metadata.write().mtime = time; self.metadata.write().mtime = time;
} }
pub fn mode(&self) -> InodeMode {
self.metadata.read().mode
}
pub fn set_mode(&self, mode: InodeMode) { pub fn set_mode(&self, mode: InodeMode) {
self.metadata.write().mode = mode; self.metadata.write().mode = mode;
} }

View File

@ -1,7 +1,7 @@
use core::time::Duration; use core::time::Duration;
use jinux_frame::vm::VmFrame; use jinux_frame::vm::VmFrame;
use crate::fs::utils::{FileSystem, Inode, InodeMode, IoctlCmd, Metadata}; use crate::fs::utils::{FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata};
use crate::prelude::*; use crate::prelude::*;
use super::{ProcFS, ProcInodeInfo}; use super::{ProcFS, ProcInodeInfo};
@ -37,6 +37,18 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
self.info.metadata() self.info.metadata()
} }
fn type_(&self) -> InodeType {
InodeType::SymLink
}
fn mode(&self) -> InodeMode {
self.info.mode()
}
fn set_mode(&self, mode: InodeMode) {
self.info.set_mode(mode)
}
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.info.atime() self.info.atime()
} }
@ -53,10 +65,6 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
self.info.set_mtime(time) self.info.set_mtime(time)
} }
fn set_mode(&self, mode: InodeMode) {
self.info.set_mode(mode)
}
fn read_page(&self, _idx: usize, _frame: &VmFrame) -> Result<()> { fn read_page(&self, _idx: usize, _frame: &VmFrame) -> Result<()> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))
} }
@ -69,10 +77,18 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))
} }
fn read_direct_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize> {
Err(Error::new(Errno::EPERM))
}
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> { fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))
} }
fn write_direct_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
Err(Error::new(Errno::EPERM))
}
fn read_link(&self) -> Result<String> { fn read_link(&self) -> Result<String> {
self.inner.read_link() self.inner.read_link()
} }

View File

@ -1,49 +1,41 @@
use crate::events::IoEvents;
use crate::prelude::*;
use crate::process::signal::Poller;
use alloc::str; use alloc::str;
use alloc::string::String;
use core::sync::atomic::{AtomicUsize, Ordering}; use core::sync::atomic::{AtomicUsize, Ordering};
use core::time::Duration; use core::time::Duration;
use jinux_frame::sync::{RwLock, RwLockWriteGuard}; use jinux_frame::sync::{RwLock, RwLockWriteGuard};
use jinux_frame::vm::VmFrame; use jinux_frame::vm::{VmFrame, VmIo};
use jinux_rights::Full;
use jinux_util::slot_vec::SlotVec; use jinux_util::slot_vec::SlotVec;
use super::*; use super::*;
use crate::events::IoEvents;
use crate::fs::device::Device; use crate::fs::device::Device;
use crate::fs::utils::{ use crate::fs::utils::{
DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata, DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata, PageCache,
SuperBlock, NAME_MAX, SuperBlock,
}; };
use crate::prelude::*;
use crate::process::signal::Poller;
use crate::vm::vmo::Vmo;
/// A volatile file system whose data and metadata exists only in memory. /// 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(use_pagecache: bool) -> Arc<Self> { pub fn new() -> 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
@ -78,7 +70,7 @@ impl FileSystem for RamFS {
} }
fn flags(&self) -> FsFlags { fn flags(&self) -> FsFlags {
self.flags FsFlags::DENTRY_UNEVICTABLE
} }
} }
@ -101,9 +93,14 @@ impl Inode_ {
} }
} }
pub fn new_file(ino: usize, mode: InodeMode, sb: &SuperBlock) -> Self { pub fn new_file(
ino: usize,
mode: InodeMode,
sb: &SuperBlock,
weak_inode: Weak<RamInode>,
) -> Self {
Self { Self {
inner: Inner::File, inner: Inner::File(PageCache::new(weak_inode).unwrap()),
metadata: Metadata::new_file(ino, mode, sb), metadata: Metadata::new_file(ino, mode, sb),
this: Weak::default(), this: Weak::default(),
fs: Weak::default(), fs: Weak::default(),
@ -112,7 +109,7 @@ impl Inode_ {
pub fn new_symlink(ino: usize, mode: InodeMode, sb: &SuperBlock) -> Self { pub fn new_symlink(ino: usize, mode: InodeMode, sb: &SuperBlock) -> Self {
Self { Self {
inner: Inner::SymLink(Str256::from("")), inner: Inner::SymLink(String::from("")),
metadata: Metadata::new_symlink(ino, mode, sb), metadata: Metadata::new_symlink(ino, mode, sb),
this: Weak::default(), this: Weak::default(),
fs: Weak::default(), fs: Weak::default(),
@ -157,18 +154,34 @@ impl Inode_ {
self.metadata.size = new_size; self.metadata.size = new_size;
self.metadata.blocks = (new_size + BLOCK_SIZE - 1) / BLOCK_SIZE; self.metadata.blocks = (new_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
} }
pub fn inc_nlinks(&mut self) {
self.metadata.nlinks += 1;
}
pub fn dec_nlinks(&mut self) {
debug_assert!(self.metadata.nlinks > 0);
self.metadata.nlinks -= 1;
}
} }
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
enum Inner { enum Inner {
Dir(DirEntry), Dir(DirEntry),
File, File(PageCache),
SymLink(Str256), SymLink(String),
Device(Arc<dyn Device>), Device(Arc<dyn Device>),
Socket, Socket,
} }
impl Inner { impl Inner {
fn as_file(&self) -> Option<&PageCache> {
match self {
Inner::File(page_cache) => Some(page_cache),
_ => None,
}
}
fn as_direntry(&self) -> Option<&DirEntry> { fn as_direntry(&self) -> Option<&DirEntry> {
match self { match self {
Inner::Dir(dir_entry) => Some(dir_entry), Inner::Dir(dir_entry) => Some(dir_entry),
@ -190,7 +203,7 @@ impl Inner {
} }
} }
fn as_symlink_mut(&mut self) -> Option<&mut Str256> { fn as_symlink_mut(&mut self) -> Option<&mut String> {
match self { match self {
Inner::SymLink(link) => Some(link), Inner::SymLink(link) => Some(link),
_ => None, _ => None,
@ -235,7 +248,7 @@ impl DirEntry {
} else { } else {
self.children self.children
.iter() .iter()
.any(|(child, _)| child == &Str256::from(name)) .any(|(child, _)| child.as_ref() == name)
} }
} }
@ -247,7 +260,7 @@ impl DirEntry {
} else { } else {
self.children self.children
.idxes_and_items() .idxes_and_items()
.find(|(_, (child, _))| child == &Str256::from(name)) .find(|(_, (child, _))| child.as_ref() == name)
.map(|(idx, (_, inode))| (idx + 2, inode.clone())) .map(|(idx, (_, inode))| (idx + 2, inode.clone()))
} }
} }
@ -344,7 +357,7 @@ impl<'a> From<&'a str> for Str256 {
s.len() s.len()
}; };
inner[0..len].copy_from_slice(&s.as_bytes()[0..len]); inner[0..len].copy_from_slice(&s.as_bytes()[0..len]);
Str256(inner) Self(inner)
} }
} }
@ -373,7 +386,12 @@ impl RamInode {
fn new_file(fs: &Arc<RamFS>, mode: InodeMode) -> Arc<Self> { fn new_file(fs: &Arc<RamFS>, mode: InodeMode) -> Arc<Self> {
Arc::new_cyclic(|weak_self| { Arc::new_cyclic(|weak_self| {
let inode = RamInode(RwLock::new(Inode_::new_file(fs.alloc_id(), mode, &fs.sb()))); let inode = RamInode(RwLock::new(Inode_::new_file(
fs.alloc_id(),
mode,
&fs.sb(),
weak_self.clone(),
)));
inode.0.write().fs = Arc::downgrade(fs); inode.0.write().fs = Arc::downgrade(fs);
inode.0.write().this = weak_self.clone(); inode.0.write().this = weak_self.clone();
inode inode
@ -432,18 +450,65 @@ impl Inode for RamInode {
Ok(()) Ok(())
} }
fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result<usize> { fn page_cache(&self) -> Option<Vmo<Full>> {
self.0
.read()
.inner
.as_file()
.map(|page_cache| page_cache.pages())
}
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
if let Some(device) = self.0.read().inner.as_device() { if let Some(device) = self.0.read().inner.as_device() {
return device.read(buf); return device.read(buf);
} }
return_errno_with_message!(Errno::EOPNOTSUPP, "direct read is not supported");
let self_inode = self.0.read();
let Some(page_cache) = self_inode.inner.as_file() else {
return_errno_with_message!(Errno::EISDIR, "read is not supported");
};
let (offset, read_len) = {
let file_len = self_inode.metadata.size;
let start = file_len.min(offset);
let end = file_len.min(offset + buf.len());
(start, end - start)
};
page_cache
.pages()
.read_bytes(offset, &mut buf[..read_len])?;
Ok(read_len)
} }
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> { fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
self.read_at(offset, buf)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
if let Some(device) = self.0.read().inner.as_device() { if let Some(device) = self.0.read().inner.as_device() {
return device.write(buf); return device.write(buf);
} }
return_errno_with_message!(Errno::EOPNOTSUPP, "direct write is not supported");
let self_inode = self.0.read();
let Some(page_cache) = self_inode.inner.as_file() else {
return_errno_with_message!(Errno::EISDIR, "write is not supported");
};
let file_len = self_inode.metadata.size;
let new_len = offset + buf.len();
let should_expand_len = new_len > file_len;
if should_expand_len {
page_cache.pages().resize(new_len)?;
}
page_cache.pages().write_bytes(offset, buf)?;
if should_expand_len {
// Turn the read guard into a write guard without releasing the lock.
let mut self_inode = self_inode.upgrade();
self_inode.resize(new_len);
}
Ok(buf.len())
}
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.write_at(offset, buf)
} }
fn len(&self) -> usize { fn len(&self) -> usize {
@ -470,6 +535,14 @@ impl Inode for RamInode {
self.0.write().metadata.mtime = time; self.0.write().metadata.mtime = time;
} }
fn type_(&self) -> InodeType {
self.0.read().metadata.type_
}
fn mode(&self) -> InodeMode {
self.0.read().metadata.mode
}
fn set_mode(&self, mode: InodeMode) { fn set_mode(&self, mode: InodeMode) {
self.0.write().metadata.mode = mode; self.0.write().metadata.mode = mode;
} }
@ -483,6 +556,10 @@ impl Inode for RamInode {
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");
} }
if name.len() > NAME_MAX {
return_errno!(Errno::ENAMETOOLONG);
}
let mut self_inode = self.0.write(); let mut self_inode = self.0.write();
if self_inode.inner.as_direntry().unwrap().contains_entry(name) { if self_inode.inner.as_direntry().unwrap().contains_entry(name) {
return_errno_with_message!(Errno::EEXIST, "entry exists"); return_errno_with_message!(Errno::EEXIST, "entry exists");
@ -501,6 +578,10 @@ impl Inode for RamInode {
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");
} }
if name.len() > NAME_MAX {
return_errno!(Errno::ENAMETOOLONG);
}
let mut self_inode = self.0.write(); let mut self_inode = self.0.write();
if self_inode.inner.as_direntry().unwrap().contains_entry(name) { if self_inode.inner.as_direntry().unwrap().contains_entry(name) {
return_errno_with_message!(Errno::EEXIST, "entry exists"); return_errno_with_message!(Errno::EEXIST, "entry exists");
@ -512,7 +593,7 @@ impl Inode for RamInode {
InodeType::Socket => RamInode::new_socket(&fs, mode), InodeType::Socket => RamInode::new_socket(&fs, mode),
InodeType::Dir => { InodeType::Dir => {
let dir_inode = RamInode::new_dir(&fs, mode, &self_inode.this); let dir_inode = RamInode::new_dir(&fs, mode, &self_inode.this);
self_inode.metadata.nlinks += 1; self_inode.inc_nlinks();
dir_inode dir_inode
} }
_ => { _ => {
@ -545,6 +626,9 @@ impl Inode for RamInode {
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");
} }
if !Arc::ptr_eq(&self.fs(), &old.fs()) {
return_errno_with_message!(Errno::EXDEV, "not same fs");
}
let old = old let old = old
.downcast_ref::<RamInode>() .downcast_ref::<RamInode>()
.ok_or(Error::new(Errno::EXDEV))?; .ok_or(Error::new(Errno::EXDEV))?;
@ -563,7 +647,7 @@ impl Inode for RamInode {
.append_entry(name, old.0.read().this.upgrade().unwrap()); .append_entry(name, old.0.read().this.upgrade().unwrap());
self_inode.inc_size(); self_inode.inc_size();
drop(self_inode); drop(self_inode);
old.0.write().metadata.nlinks += 1; old.0.write().inc_nlinks();
Ok(()) Ok(())
} }
@ -583,7 +667,7 @@ impl Inode for RamInode {
self_dir.remove_entry(idx); self_dir.remove_entry(idx);
self_inode.dec_size(); self_inode.dec_size();
drop(self_inode); drop(self_inode);
target.0.write().metadata.nlinks -= 1; target.0.write().dec_nlinks();
Ok(()) Ok(())
} }
@ -612,9 +696,11 @@ impl Inode for RamInode {
} }
self_dir.remove_entry(idx); self_dir.remove_entry(idx);
self_inode.dec_size(); self_inode.dec_size();
self_inode.metadata.nlinks -= 1; self_inode.dec_nlinks();
drop(self_inode); drop(self_inode);
target.0.write().metadata.nlinks -= 2; let mut target_inode = self.0.write();
target_inode.dec_nlinks();
target_inode.dec_nlinks();
Ok(()) Ok(())
} }
@ -638,6 +724,9 @@ impl Inode for RamInode {
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");
} }
if !Arc::ptr_eq(&self.fs(), &target.fs()) {
return_errno_with_message!(Errno::EXDEV, "not same fs");
}
let target = target let target = target
.downcast_ref::<RamInode>() .downcast_ref::<RamInode>()
.ok_or(Error::new(Errno::EXDEV))?; .ok_or(Error::new(Errno::EXDEV))?;
@ -703,8 +792,8 @@ impl Inode for RamInode {
self_inode.dec_size(); self_inode.dec_size();
target_inode.inc_size(); target_inode.inc_size();
if src_inode.0.read().metadata.type_ == InodeType::Dir { if src_inode.0.read().metadata.type_ == InodeType::Dir {
self_inode.metadata.nlinks -= 1; self_inode.dec_nlinks();
target_inode.metadata.nlinks += 1; target_inode.inc_nlinks();
} }
drop(self_inode); drop(self_inode);
drop(target_inode); drop(target_inode);
@ -736,7 +825,7 @@ impl Inode for RamInode {
} }
let mut self_inode = self.0.write(); let mut self_inode = self.0.write();
let link = self_inode.inner.as_symlink_mut().unwrap(); let link = self_inode.inner.as_symlink_mut().unwrap();
*link = Str256::from(target); *link = String::from(target);
// Symlink's metadata.blocks should be 0, so just set the size. // Symlink's metadata.blocks should be 0, so just set the size.
self_inode.metadata.size = target.len(); self_inode.metadata.size = target.len();
Ok(()) Ok(())

View File

@ -7,3 +7,4 @@ mod fs;
const RAMFS_MAGIC: u64 = 0x0102_1994; const RAMFS_MAGIC: u64 = 0x0102_1994;
const BLOCK_SIZE: usize = 4096; const BLOCK_SIZE: usize = 4096;
const ROOT_INO: usize = 1; const ROOT_INO: usize = 1;
const NAME_MAX: usize = 255;

View File

@ -12,7 +12,7 @@ use spin::Once;
/// Unpack and prepare the rootfs from the initramfs CPIO buffer. /// Unpack and prepare the rootfs from the initramfs CPIO buffer.
pub fn init(initramfs_buf: &[u8]) -> Result<()> { pub fn init(initramfs_buf: &[u8]) -> Result<()> {
init_root_mount()?; init_root_mount();
println!("[kernel] unpacking the initramfs.cpio.gz to rootfs ..."); println!("[kernel] unpacking the initramfs.cpio.gz to rootfs ...");
let fs = FsResolver::new(); let fs = FsResolver::new();
@ -52,7 +52,7 @@ pub fn init(initramfs_buf: &[u8]) -> Result<()> {
match metadata.file_type() { match metadata.file_type() {
FileType::File => { FileType::File => {
let dentry = parent.create(name, InodeType::File, mode)?; let dentry = parent.create(name, InodeType::File, mode)?;
entry.read_all(dentry.vnode().writer(0))?; entry.read_all(dentry.inode().writer(0))?;
} }
FileType::Dir => { FileType::Dir => {
let _ = parent.create(name, InodeType::Dir, mode)?; let _ = parent.create(name, InodeType::Dir, mode)?;
@ -64,7 +64,7 @@ pub fn init(initramfs_buf: &[u8]) -> Result<()> {
entry.read_all(&mut link_data)?; entry.read_all(&mut link_data)?;
core::str::from_utf8(&link_data)?.to_string() core::str::from_utf8(&link_data)?.to_string()
}; };
dentry.vnode().write_link(&link_content)?; dentry.inode().write_link(&link_content)?;
} }
type_ => { type_ => {
panic!("unsupported file type = {:?} in initramfs", type_); panic!("unsupported file type = {:?} in initramfs", type_);
@ -76,7 +76,7 @@ pub fn init(initramfs_buf: &[u8]) -> Result<()> {
proc_dentry.mount(ProcFS::new())?; proc_dentry.mount(ProcFS::new())?;
// Mount DevFS // Mount DevFS
let dev_dentry = fs.lookup(&FsPath::try_from("/dev")?)?; let dev_dentry = fs.lookup(&FsPath::try_from("/dev")?)?;
dev_dentry.mount(RamFS::new(false))?; dev_dentry.mount(RamFS::new())?;
println!("[kernel] rootfs is ready"); println!("[kernel] rootfs is ready");
Ok(()) Ok(())
@ -84,14 +84,11 @@ pub fn init(initramfs_buf: &[u8]) -> Result<()> {
static ROOT_MOUNT: Once<Arc<MountNode>> = Once::new(); static ROOT_MOUNT: Once<Arc<MountNode>> = Once::new();
fn init_root_mount() -> Result<()> { fn init_root_mount() {
ROOT_MOUNT.try_call_once(|| -> Result<Arc<MountNode>> { ROOT_MOUNT.call_once(|| -> Arc<MountNode> {
let rootfs = RamFS::new(true); let rootfs = RamFS::new();
let root_mount = MountNode::new_root(rootfs)?; MountNode::new_root(rootfs)
Ok(root_mount) });
})?;
Ok(())
} }
pub fn root_mount() -> &'static Arc<MountNode> { pub fn root_mount() -> &'static Arc<MountNode> {

View File

@ -5,7 +5,7 @@ use alloc::string::String;
use core::sync::atomic::{AtomicU32, Ordering}; use core::sync::atomic::{AtomicU32, Ordering};
use core::time::Duration; use core::time::Duration;
use super::{FileSystem, Inode, InodeMode, InodeType, Metadata, MountNode, Vnode, NAME_MAX}; use super::{FileSystem, Inode, InodeMode, InodeType, Metadata, MountNode, NAME_MAX};
lazy_static! { lazy_static! {
static ref DCACHE: Mutex<BTreeMap<DentryKey, Arc<Dentry>>> = Mutex::new(BTreeMap::new()); static ref DCACHE: Mutex<BTreeMap<DentryKey, Arc<Dentry>>> = Mutex::new(BTreeMap::new());
@ -13,7 +13,7 @@ lazy_static! {
/// The dentry cache to accelerate path lookup /// The dentry cache to accelerate path lookup
pub struct Dentry { pub struct Dentry {
vnode: Vnode, inode: Arc<dyn Inode>,
name_and_parent: RwLock<Option<(String, Arc<Dentry>)>>, name_and_parent: RwLock<Option<(String, Arc<Dentry>)>>,
this: Weak<Dentry>, this: Weak<Dentry>,
children: Mutex<Children>, children: Mutex<Children>,
@ -22,21 +22,21 @@ pub struct Dentry {
} }
impl Dentry { impl Dentry {
/// Create a new root dentry with the giving vnode and mount node. /// Create a new root dentry with the giving inode and mount node.
/// ///
/// It is been created during the construction of MountNode struct. The MountNode /// It is been created during the construction of MountNode struct. The MountNode
/// struct holds an arc reference to this root dentry, while this dentry holds a /// struct holds an arc reference to this root dentry, while this dentry holds a
/// weak reference to the MountNode struct. /// weak reference to the MountNode struct.
pub(super) fn new_root(vnode: Vnode, mount: Weak<MountNode>) -> Arc<Self> { pub(super) fn new_root(inode: Arc<dyn Inode>, mount: Weak<MountNode>) -> Arc<Self> {
let root = Self::new(vnode, DentryOptions::Root(mount)); let root = Self::new(inode, DentryOptions::Root(mount));
DCACHE.lock().insert(root.key(), root.clone()); DCACHE.lock().insert(root.key(), root.clone());
root root
} }
/// Internal constructor. /// Internal constructor.
fn new(vnode: Vnode, options: DentryOptions) -> Arc<Self> { fn new(inode: Arc<dyn Inode>, options: DentryOptions) -> Arc<Self> {
Arc::new_cyclic(|weak_self| Self { Arc::new_cyclic(|weak_self| Self {
vnode, inode,
mount_node: match &options { mount_node: match &options {
DentryOptions::Root(mount) => mount.clone(), DentryOptions::Root(mount) => mount.clone(),
DentryOptions::Leaf(name_and_parent) => name_and_parent.1.mount_node.clone(), DentryOptions::Leaf(name_and_parent) => name_and_parent.1.mount_node.clone(),
@ -129,9 +129,9 @@ impl Dentry {
DentryKey::new(self) DentryKey::new(self)
} }
/// Get the vnode. /// Get the inode.
pub fn vnode(&self) -> &Vnode { pub fn inode(&self) -> &Arc<dyn Inode> {
&self.vnode &self.inode
} }
/// Get the DentryFlags. /// Get the DentryFlags.
@ -164,13 +164,9 @@ impl Dentry {
self.mount_node.upgrade().unwrap() self.mount_node.upgrade().unwrap()
} }
pub fn inode(&self) -> Weak<dyn Inode> {
self.vnode.inode()
}
/// Create a dentry by making inode. /// Create a dentry by making inode.
pub fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<Self>> { pub fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<Self>> {
if self.vnode.inode_type() != InodeType::Dir { if self.inode.type_() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
let mut children = self.children.lock(); let mut children = self.children.lock();
@ -179,9 +175,9 @@ impl Dentry {
} }
let child = { let child = {
let vnode = self.vnode.create(name, type_, mode)?; let inode = self.inode.create(name, type_, mode)?;
let dentry = Self::new( let dentry = Self::new(
vnode, inode,
DentryOptions::Leaf((String::from(name), self.this())), DentryOptions::Leaf((String::from(name), self.this())),
); );
children.insert_dentry(&dentry); children.insert_dentry(&dentry);
@ -192,7 +188,7 @@ impl Dentry {
/// Create a dentry by making a device inode. /// Create a dentry by making a device inode.
pub fn mknod(&self, name: &str, mode: InodeMode, device: Arc<dyn Device>) -> Result<Arc<Self>> { pub fn mknod(&self, name: &str, mode: InodeMode, device: Arc<dyn Device>) -> Result<Arc<Self>> {
if self.vnode.inode_type() != InodeType::Dir { if self.inode.type_() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
let mut children = self.children.lock(); let mut children = self.children.lock();
@ -201,9 +197,9 @@ impl Dentry {
} }
let child = { let child = {
let vnode = self.vnode.mknod(name, mode, device)?; let inode = self.inode.mknod(name, mode, device)?;
let dentry = Self::new( let dentry = Self::new(
vnode, inode,
DentryOptions::Leaf((String::from(name), self.this())), DentryOptions::Leaf((String::from(name), self.this())),
); );
children.insert_dentry(&dentry); children.insert_dentry(&dentry);
@ -214,10 +210,10 @@ impl Dentry {
/// Lookup a dentry. /// Lookup a dentry.
pub fn lookup(&self, name: &str) -> Result<Arc<Self>> { pub fn lookup(&self, name: &str) -> Result<Arc<Self>> {
if self.vnode.inode_type() != InodeType::Dir { if self.inode.type_() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
if !self.vnode.inode_mode().is_executable() { if !self.inode.mode().is_executable() {
return_errno!(Errno::EACCES); return_errno!(Errno::EACCES);
} }
if name.len() > NAME_MAX { if name.len() > NAME_MAX {
@ -232,9 +228,9 @@ impl Dentry {
match children.find_dentry(name) { match children.find_dentry(name) {
Some(dentry) => dentry.overlaid_dentry(), Some(dentry) => dentry.overlaid_dentry(),
None => { None => {
let vnode = self.vnode.lookup(name)?; let inode = self.inode.lookup(name)?;
let dentry = Self::new( let dentry = Self::new(
vnode, inode,
DentryOptions::Leaf((String::from(name), self.this())), DentryOptions::Leaf((String::from(name), self.this())),
); );
children.insert_dentry(&dentry); children.insert_dentry(&dentry);
@ -248,7 +244,7 @@ impl Dentry {
/// Link a new name for the dentry by linking inode. /// Link a new name for the dentry by linking inode.
pub fn link(&self, old: &Arc<Self>, name: &str) -> Result<()> { pub fn link(&self, old: &Arc<Self>, name: &str) -> Result<()> {
if self.vnode.inode_type() != InodeType::Dir { if self.inode.type_() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
let mut children = self.children.lock(); let mut children = self.children.lock();
@ -258,10 +254,10 @@ impl Dentry {
if !Arc::ptr_eq(&old.mount_node(), &self.mount_node()) { if !Arc::ptr_eq(&old.mount_node(), &self.mount_node()) {
return_errno_with_message!(Errno::EXDEV, "cannot cross mount"); return_errno_with_message!(Errno::EXDEV, "cannot cross mount");
} }
let old_vnode = old.vnode(); let old_inode = old.inode();
self.vnode.link(old_vnode, name)?; self.inode.link(old_inode, name)?;
let dentry = Self::new( let dentry = Self::new(
old_vnode.clone(), old_inode.clone(),
DentryOptions::Leaf((String::from(name), self.this())), DentryOptions::Leaf((String::from(name), self.this())),
); );
children.insert_dentry(&dentry); children.insert_dentry(&dentry);
@ -270,51 +266,34 @@ impl Dentry {
/// Delete a dentry by unlinking inode. /// Delete a dentry by unlinking inode.
pub fn unlink(&self, name: &str) -> Result<()> { pub fn unlink(&self, name: &str) -> Result<()> {
if self.vnode.inode_type() != InodeType::Dir { if self.inode.type_() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
let mut children = self.children.lock(); let mut children = self.children.lock();
let _ = children.find_dentry_with_checking_mountpoint(name)?; let _ = children.find_dentry_with_checking_mountpoint(name)?;
self.vnode.unlink(name)?; self.inode.unlink(name)?;
children.delete_dentry(name); children.delete_dentry(name);
Ok(()) Ok(())
} }
/// Delete a directory dentry by rmdiring inode. /// Delete a directory dentry by rmdiring inode.
pub fn rmdir(&self, name: &str) -> Result<()> { pub fn rmdir(&self, name: &str) -> Result<()> {
if self.vnode.inode_type() != InodeType::Dir { if self.inode.type_() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
let mut children = self.children.lock(); let mut children = self.children.lock();
let _ = children.find_dentry_with_checking_mountpoint(name)?; let _ = children.find_dentry_with_checking_mountpoint(name)?;
self.vnode.rmdir(name)?; self.inode.rmdir(name)?;
children.delete_dentry(name); children.delete_dentry(name);
Ok(()) Ok(())
} }
/// Read symbolic link.
pub fn read_link(&self) -> Result<String> {
if self.vnode.inode_type() != InodeType::SymLink {
return_errno!(Errno::EINVAL);
}
self.vnode.read_link()
}
/// Write symbolic link.
pub fn write_link(&self, target: &str) -> Result<()> {
if self.vnode.inode_type() != InodeType::SymLink {
return_errno!(Errno::EINVAL);
}
self.vnode.write_link(target)
}
/// Rename a dentry to the new dentry by renaming inode. /// Rename a dentry to the new dentry by renaming inode.
pub fn rename(&self, old_name: &str, new_dir: &Arc<Self>, new_name: &str) -> Result<()> { pub fn rename(&self, old_name: &str, new_dir: &Arc<Self>, new_name: &str) -> Result<()> {
if old_name == "." || old_name == ".." || new_name == "." || new_name == ".." { if old_name == "." || old_name == ".." || new_name == "." || new_name == ".." {
return_errno_with_message!(Errno::EISDIR, "old_name or new_name is a directory"); return_errno_with_message!(Errno::EISDIR, "old_name or new_name is a directory");
} }
if self.vnode.inode_type() != InodeType::Dir || new_dir.vnode.inode_type() != InodeType::Dir if self.inode.type_() != InodeType::Dir || new_dir.inode.type_() != InodeType::Dir {
{
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
@ -326,7 +305,7 @@ impl Dentry {
let mut children = self.children.lock(); let mut children = self.children.lock();
let old_dentry = children.find_dentry_with_checking_mountpoint(old_name)?; let old_dentry = children.find_dentry_with_checking_mountpoint(old_name)?;
let _ = children.find_dentry_with_checking_mountpoint(new_name)?; let _ = children.find_dentry_with_checking_mountpoint(new_name)?;
self.vnode.rename(old_name, &self.vnode, new_name)?; self.inode.rename(old_name, &self.inode, new_name)?;
match old_dentry.as_ref() { match old_dentry.as_ref() {
Some(dentry) => { Some(dentry) => {
children.delete_dentry(old_name); children.delete_dentry(old_name);
@ -346,7 +325,7 @@ impl Dentry {
write_lock_children_on_two_dentries(self, new_dir); write_lock_children_on_two_dentries(self, new_dir);
let old_dentry = self_children.find_dentry_with_checking_mountpoint(old_name)?; let old_dentry = self_children.find_dentry_with_checking_mountpoint(old_name)?;
let _ = new_dir_children.find_dentry_with_checking_mountpoint(new_name)?; let _ = new_dir_children.find_dentry_with_checking_mountpoint(new_name)?;
self.vnode.rename(old_name, &new_dir.vnode, new_name)?; self.inode.rename(old_name, &new_dir.inode, new_name)?;
match old_dentry.as_ref() { match old_dentry.as_ref() {
Some(dentry) => { Some(dentry) => {
self_children.delete_dentry(old_name); self_children.delete_dentry(old_name);
@ -369,7 +348,7 @@ impl Dentry {
/// ///
/// Return the mounted child mount. /// Return the mounted child mount.
pub fn mount(&self, fs: Arc<dyn FileSystem>) -> Result<Arc<MountNode>> { pub fn mount(&self, fs: Arc<dyn FileSystem>) -> Result<Arc<MountNode>> {
if self.vnode.inode_type() != InodeType::Dir { if self.inode.type_() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
if self.effective_parent().is_none() { if self.effective_parent().is_none() {
@ -401,52 +380,52 @@ impl Dentry {
/// Get the filesystem the inode belongs to /// Get the filesystem the inode belongs to
pub fn fs(&self) -> Arc<dyn FileSystem> { pub fn fs(&self) -> Arc<dyn FileSystem> {
self.vnode.fs() self.inode.fs()
} }
/// Get the inode metadata /// Get the inode metadata
pub fn inode_metadata(&self) -> Metadata { pub fn inode_metadata(&self) -> Metadata {
self.vnode.metadata() self.inode.metadata()
} }
/// Get the inode type /// Get the inode type
pub fn inode_type(&self) -> InodeType { pub fn inode_type(&self) -> InodeType {
self.vnode.inode_type() self.inode.type_()
} }
/// Get the inode permission mode /// Get the inode permission mode
pub fn inode_mode(&self) -> InodeMode { pub fn inode_mode(&self) -> InodeMode {
self.vnode.inode_mode() self.inode.mode()
} }
/// Set the inode permission mode /// Set the inode permission mode
pub fn set_inode_mode(&self, mode: InodeMode) { pub fn set_inode_mode(&self, mode: InodeMode) {
self.vnode.set_inode_mode(mode) self.inode.set_mode(mode)
} }
/// Get the inode length /// Get the inode length
pub fn inode_len(&self) -> usize { pub fn inode_len(&self) -> usize {
self.vnode.len() self.inode.len()
} }
/// Get the access timestamp /// Get the access timestamp
pub fn atime(&self) -> Duration { pub fn atime(&self) -> Duration {
self.vnode.atime() self.inode.atime()
} }
/// Set the access timestamp /// Set the access timestamp
pub fn set_atime(&self, time: Duration) { pub fn set_atime(&self, time: Duration) {
self.vnode.set_atime(time) self.inode.set_atime(time)
} }
/// Get the modified timestamp /// Get the modified timestamp
pub fn mtime(&self) -> Duration { pub fn mtime(&self) -> Duration {
self.vnode.mtime() self.inode.mtime()
} }
/// Set the modified timestamp /// Set the modified timestamp
pub fn set_mtime(&self, time: Duration) { pub fn set_mtime(&self, time: Duration) {
self.vnode.set_mtime(time) self.inode.set_mtime(time)
} }
/// Get the absolute path. /// Get the absolute path.
@ -482,7 +461,7 @@ impl Debug for Dentry {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("Dentry") f.debug_struct("Dentry")
.field("abs_path", &self.abs_path()) .field("abs_path", &self.abs_path())
.field("vnode", &self.vnode) .field("inode", &self.inode)
.field("flags", &self.flags()) .field("flags", &self.flags())
.finish() .finish()
} }
@ -537,7 +516,7 @@ impl Children {
pub fn insert_dentry(&mut self, dentry: &Arc<Dentry>) { pub fn insert_dentry(&mut self, dentry: &Arc<Dentry>) {
// Do not cache it in DCACHE and children if is not cacheable. // Do not cache it in DCACHE and children if is not cacheable.
// When we look up it from the parent, it will always be newly created. // When we look up it from the parent, it will always be newly created.
if !dentry.vnode().is_dentry_cacheable() { if !dentry.inode().is_dentry_cacheable() {
return; return;
} }

View File

@ -1,7 +1,3 @@
use alloc::sync::Arc;
use bitflags::bitflags;
use core::any::Any;
use super::Inode; use super::Inode;
use crate::prelude::*; use crate::prelude::*;
@ -40,8 +36,6 @@ impl SuperBlock {
bitflags! { bitflags! {
pub struct FsFlags: u32 { pub struct FsFlags: u32 {
/// Disable page cache.
const NO_PAGECACHE = 1 << 0;
/// Dentry cannot be evicted. /// Dentry cannot be evicted.
const DENTRY_UNEVICTABLE = 1 << 1; const DENTRY_UNEVICTABLE = 1 << 1;
} }

View File

@ -1,18 +1,17 @@
use alloc::string::String;
use alloc::sync::Arc;
use bitflags::bitflags;
use core::any::Any;
use core::time::Duration; use core::time::Duration;
use core2::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult, Write};
use jinux_frame::vm::VmFrame; use jinux_frame::vm::VmFrame;
use jinux_rights::Full;
use super::{DirentVisitor, FileSystem, IoctlCmd, SuperBlock}; use super::{DirentVisitor, FileSystem, IoctlCmd, SuperBlock};
use crate::events::IoEvents; use crate::events::IoEvents;
use crate::fs::device::{Device, DeviceType}; use crate::fs::device::{Device, DeviceType};
use crate::prelude::*; use crate::prelude::*;
use crate::process::signal::Poller; use crate::process::signal::Poller;
use crate::vm::vmo::Vmo;
#[repr(u32)] #[repr(u32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromInt)]
pub enum InodeType { pub enum InodeType {
NamedPipe = 0o010000, NamedPipe = 0o010000,
CharDevice = 0o020000, CharDevice = 0o020000,
@ -236,6 +235,12 @@ pub trait Inode: Any + Sync + Send {
fn metadata(&self) -> Metadata; fn metadata(&self) -> Metadata;
fn type_(&self) -> InodeType;
fn mode(&self) -> InodeMode;
fn set_mode(&self, mode: InodeMode);
fn atime(&self) -> Duration; fn atime(&self) -> Duration;
fn set_atime(&self, time: Duration); fn set_atime(&self, time: Duration);
@ -244,8 +249,6 @@ pub trait Inode: Any + Sync + Send {
fn set_mtime(&self, time: Duration); fn set_mtime(&self, time: Duration);
fn set_mode(&self, mode: InodeMode);
fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> { fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> {
Err(Error::new(Errno::EISDIR)) Err(Error::new(Errno::EISDIR))
} }
@ -254,14 +257,26 @@ pub trait Inode: Any + Sync + Send {
Err(Error::new(Errno::EISDIR)) Err(Error::new(Errno::EISDIR))
} }
fn page_cache(&self) -> Option<Vmo<Full>> {
None
}
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)) Err(Error::new(Errno::EISDIR))
} }
fn read_direct_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)) Err(Error::new(Errno::EISDIR))
} }
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
Err(Error::new(Errno::EISDIR))
}
fn create(&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)) Err(Error::new(Errno::ENOTDIR))
} }
@ -343,6 +358,59 @@ impl dyn Inode {
pub fn downcast_ref<T: Inode>(&self) -> Option<&T> { pub fn downcast_ref<T: Inode>(&self) -> Option<&T> {
(self as &dyn Any).downcast_ref::<T>() (self as &dyn Any).downcast_ref::<T>()
} }
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
if !self.type_().support_read() {
return_errno!(Errno::EISDIR);
}
let file_len = self.len();
if buf.len() < file_len {
buf.resize(file_len, 0);
}
self.read_at(0, &mut buf[..file_len])
}
pub fn read_direct_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
if !self.type_().support_read() {
return_errno!(Errno::EISDIR);
}
let file_len = self.len();
if buf.len() < file_len {
buf.resize(file_len, 0);
}
self.read_direct_at(0, &mut buf[..file_len])
}
pub fn writer(&self, from_offset: usize) -> InodeWriter {
InodeWriter {
inner: self,
offset: from_offset,
}
}
}
pub struct InodeWriter<'a> {
inner: &'a dyn Inode,
offset: usize,
}
impl<'a> Write for InodeWriter<'a> {
#[inline]
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
let write_len = self
.inner
.write_at(self.offset, buf)
.map_err(|_| IoError::new(IoErrorKind::WriteZero, "failed to write buffer"))?;
self.offset += write_len;
Ok(write_len)
}
#[inline]
fn flush(&mut self) -> IoResult<()> {
Ok(())
}
} }
impl Debug for dyn Inode { impl Debug for dyn Inode {

View File

@ -13,7 +13,6 @@ pub use ioctl::IoctlCmd;
pub use mount::MountNode; pub use mount::MountNode;
pub use page_cache::PageCache; pub use page_cache::PageCache;
pub use status_flags::StatusFlags; pub use status_flags::StatusFlags;
pub use vnode::{Vnode, VnodeWriter};
mod access_mode; mod access_mode;
mod channel; mod channel;
@ -28,7 +27,6 @@ mod ioctl;
mod mount; mod mount;
mod page_cache; mod page_cache;
mod status_flags; mod status_flags;
mod vnode;
#[derive(Copy, PartialEq, Eq, Clone, Debug)] #[derive(Copy, PartialEq, Eq, Clone, Debug)]
pub enum SeekFrom { pub enum SeekFrom {

View File

@ -1,6 +1,6 @@
use crate::prelude::*; use crate::prelude::*;
use super::{Dentry, DentryKey, FileSystem, InodeType, Vnode}; use super::{Dentry, DentryKey, FileSystem, InodeType};
/// The MountNode can form a mount tree to maintain the mount information. /// The MountNode can form a mount tree to maintain the mount information.
pub struct MountNode { pub struct MountNode {
@ -25,22 +25,21 @@ impl MountNode {
/// ///
/// It is allowed to create a mount node even if the fs has been provided to another /// It is allowed to create a mount node even if the fs has been provided to another
/// mount node. It is the fs's responsibility to ensure the data consistency. /// mount node. It is the fs's responsibility to ensure the data consistency.
pub fn new_root(fs: Arc<dyn FileSystem>) -> Result<Arc<Self>> { pub fn new_root(fs: Arc<dyn FileSystem>) -> Arc<Self> {
Self::new(fs, None) Self::new(fs, None)
} }
/// The internal constructor. /// The internal constructor.
/// ///
/// Root mount node has no mountpoint which other mount nodes must have mountpoint. /// Root mount node has no mountpoint which other mount nodes must have mountpoint.
fn new(fs: Arc<dyn FileSystem>, mountpoint: Option<Arc<Dentry>>) -> Result<Arc<Self>> { fn new(fs: Arc<dyn FileSystem>, mountpoint: Option<Arc<Dentry>>) -> Arc<Self> {
let vnode = Vnode::new(fs.root_inode())?; Arc::new_cyclic(|weak_self| Self {
Ok(Arc::new_cyclic(|weak_self| Self { root_dentry: Dentry::new_root(fs.root_inode(), weak_self.clone()),
root_dentry: Dentry::new_root(vnode, weak_self.clone()),
mountpoint_dentry: mountpoint, mountpoint_dentry: mountpoint,
children: Mutex::new(BTreeMap::new()), children: Mutex::new(BTreeMap::new()),
fs, fs,
this: weak_self.clone(), this: weak_self.clone(),
})) })
} }
/// Mount an fs on the mountpoint, it will create a new child mount node. /// Mount an fs on the mountpoint, it will create a new child mount node.
@ -63,7 +62,7 @@ impl MountNode {
} }
let key = mountpoint.key(); let key = mountpoint.key();
let child_mount = Self::new(fs, Some(mountpoint.clone()))?; let child_mount = Self::new(fs, Some(mountpoint.clone()));
self.children.lock().insert(key, child_mount.clone()); self.children.lock().insert(key, child_mount.clone());
Ok(child_mount) Ok(child_mount)
} }

View File

@ -1,6 +1,6 @@
use super::Inode; use super::Inode;
use crate::prelude::*; use crate::prelude::*;
use crate::vm::vmo::{Pager, Vmo, VmoFlags, VmoOptions}; use crate::vm::vmo::{get_page_idx_range, Pager, Vmo, VmoFlags, VmoOptions};
use jinux_rights::Full; use jinux_rights::Full;
use core::ops::Range; use core::ops::Range;
@ -13,24 +13,40 @@ pub struct PageCache {
} }
impl PageCache { impl PageCache {
pub fn new(inode: &Arc<dyn Inode>) -> Result<Self> { /// Creates an empty size page cache associated with a new inode.
let manager = Arc::new(PageCacheManager::new(Arc::downgrade(inode))); pub fn new(backed_inode: Weak<dyn Inode>) -> Result<Self> {
let pages = VmoOptions::<Full>::new(inode.len()) let manager = Arc::new(PageCacheManager::new(backed_inode));
let pages = VmoOptions::<Full>::new(0)
.flags(VmoFlags::RESIZABLE) .flags(VmoFlags::RESIZABLE)
.pager(manager.clone()) .pager(manager.clone())
.alloc()?; .alloc()?;
Ok(Self { pages, manager }) Ok(Self { pages, manager })
} }
pub fn pages(&self) -> &Vmo<Full> { /// Creates a page cache associated with an existing inode.
&self.pages ///
/// The `capacity` is the initial cache size required by the inode.
/// It is usually used the same size as the inode.
pub fn with_capacity(capacity: usize, backed_inode: Weak<dyn Inode>) -> Result<Self> {
let manager = Arc::new(PageCacheManager::new(backed_inode));
let pages = VmoOptions::<Full>::new(capacity)
.flags(VmoFlags::RESIZABLE)
.pager(manager.clone())
.alloc()?;
Ok(Self { pages, manager })
}
/// Returns the Vmo object backed by inode.
// TODO: The capability is too highrestrict it to eliminate the possibility of misuse.
// For example, the `resize` api should be forbidded.
pub fn pages(&self) -> Vmo<Full> {
self.pages.dup().unwrap()
} }
/// Evict the data within a specified range from the page cache and persist /// Evict the data within a specified range from the page cache and persist
/// them to the disk. /// them to the disk.
pub fn evict_range(&self, range: Range<usize>) { pub fn evict_range(&self, range: Range<usize>) -> Result<()> {
// TODO: Implement this method. self.manager.evict_range(range)
warn!("pagecache: evict_range is not implemented");
} }
} }
@ -49,12 +65,31 @@ struct PageCacheManager {
} }
impl PageCacheManager { impl PageCacheManager {
pub fn new(inode: Weak<dyn Inode>) -> Self { pub fn new(backed_inode: Weak<dyn Inode>) -> Self {
Self { Self {
pages: Mutex::new(LruCache::unbounded()), pages: Mutex::new(LruCache::unbounded()),
backed_inode: inode, backed_inode,
} }
} }
pub fn evict_range(&self, range: Range<usize>) -> Result<()> {
let page_idx_range = get_page_idx_range(&range);
let mut pages = self.pages.lock();
for page_idx in page_idx_range {
if let Some(page) = pages.get_mut(&page_idx) {
if let PageState::Dirty = page.state() {
self.backed_inode
.upgrade()
.unwrap()
.write_page(page_idx, page.frame())?;
page.set_state(PageState::UpToDate);
}
} else {
warn!("page {} is not in page cache, do nothing", page_idx);
}
}
Ok(())
}
} }
impl Debug for PageCacheManager { impl Debug for PageCacheManager {
@ -70,20 +105,18 @@ impl Pager for PageCacheManager {
let page_idx = offset / PAGE_SIZE; let page_idx = offset / PAGE_SIZE;
let mut pages = self.pages.lock(); let mut pages = self.pages.lock();
let frame = if let Some(page) = pages.get(&page_idx) { let frame = if let Some(page) = pages.get(&page_idx) {
page.frame() page.frame().clone()
} else { } else {
let page = if offset < self.backed_inode.upgrade().unwrap().metadata().size { let backed_inode = self.backed_inode.upgrade().unwrap();
let mut page = Page::alloc_zero()?; let page = if offset < backed_inode.len() {
self.backed_inode let mut page = Page::alloc()?;
.upgrade() backed_inode.read_page(page_idx, page.frame())?;
.unwrap()
.read_page(page_idx, &page.frame())?;
page.set_state(PageState::UpToDate); page.set_state(PageState::UpToDate);
page page
} else { } else {
Page::alloc_zero()? Page::alloc_zero()?
}; };
let frame = page.frame(); let frame = page.frame().clone();
pages.put(page_idx, page); pages.put(page_idx, page);
frame frame
}; };
@ -110,7 +143,7 @@ impl Pager for PageCacheManager {
self.backed_inode self.backed_inode
.upgrade() .upgrade()
.unwrap() .unwrap()
.write_page(page_idx, &page.frame())? .write_page(page_idx, page.frame())?
} }
} else { } else {
warn!("page {} is not in page cache, do nothing", page_idx); warn!("page {} is not in page cache, do nothing", page_idx);
@ -151,8 +184,8 @@ impl Page {
}) })
} }
pub fn frame(&self) -> VmFrame { pub fn frame(&self) -> &VmFrame {
self.frame.clone() &self.frame
} }
pub fn state(&self) -> &PageState { pub fn state(&self) -> &PageState {

View File

@ -1,300 +0,0 @@
use super::{
DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata, PageCache,
};
use crate::events::IoEvents;
use crate::fs::device::Device;
use crate::prelude::*;
use crate::process::signal::Poller;
use crate::vm::vmo::Vmo;
use alloc::string::String;
use core::time::Duration;
use core2::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult, Write};
use jinux_frame::vm::VmIo;
use jinux_rights::Full;
/// VFS-level representation of an inode
#[derive(Clone)]
pub struct Vnode {
// The RwLock is to maintain the correct file length for concurrent read or write.
inner: Arc<RwLock<Inner>>,
}
struct Inner {
inode: Arc<dyn Inode>,
page_cache: Option<PageCache>,
}
impl Vnode {
pub fn page_cache(&self) -> Option<Vmo<Full>> {
self.inner
.read()
.page_cache
.as_ref()
.map(|page_chche| page_chche.pages().dup().unwrap())
}
pub fn new(inode: Arc<dyn Inode>) -> Result<Self> {
let page_cache = if inode.fs().flags().contains(FsFlags::NO_PAGECACHE) {
None
} else {
Some(PageCache::new(&inode)?)
};
Ok(Self {
inner: Arc::new(RwLock::new(Inner { inode, page_cache })),
})
}
pub fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
let type_ = self.inode_type();
if !type_.support_write() {
return_errno!(Errno::EINVAL);
}
let inner = self.inner.write();
match &inner.page_cache {
None => inner.inode.write_at(offset, buf),
Some(page_cache) => {
let file_len = inner.inode.len();
let should_expand_len = offset + buf.len() > file_len;
if should_expand_len {
page_cache.pages().resize(offset + buf.len())?;
}
page_cache.pages().write_bytes(offset, buf)?;
if should_expand_len {
inner.inode.resize(offset + buf.len());
}
Ok(buf.len())
}
}
}
pub fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
let type_ = self.inode_type();
if !type_.support_write() {
return_errno!(Errno::EINVAL);
}
let inner = self.inner.write();
if let Some(page_cache) = &inner.page_cache {
page_cache.evict_range(offset..offset + buf.len());
}
inner.inode.write_at(offset, buf)
}
pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
let type_ = self.inode_type();
if !type_.support_read() {
return_errno!(Errno::EISDIR);
}
let inner = self.inner.read();
match &inner.page_cache {
None => inner.inode.read_at(offset, buf),
Some(page_cache) => {
let (offset, read_len) = {
let file_len = inner.inode.len();
let start = file_len.min(offset);
let end = file_len.min(offset + buf.len());
(start, end - start)
};
page_cache
.pages()
.read_bytes(offset, &mut buf[..read_len])?;
Ok(read_len)
}
}
}
pub fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
let type_ = self.inode_type();
if !type_.support_read() {
return_errno!(Errno::EISDIR);
}
let inner = self.inner.read();
if let Some(page_cache) = &inner.page_cache {
page_cache.evict_range(offset..offset + buf.len());
}
inner.inode.read_at(offset, buf)
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
let type_ = self.inode_type();
if !type_.support_read() {
return_errno!(Errno::EISDIR);
}
let inner = self.inner.read();
let file_len = inner.inode.len();
if buf.len() < file_len {
buf.resize(file_len, 0);
}
match &inner.page_cache {
None => inner.inode.read_at(0, &mut buf[..file_len]),
Some(page_cache) => {
page_cache.pages().read_bytes(0, &mut buf[..file_len])?;
Ok(file_len)
}
}
}
pub fn read_direct_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
let type_ = self.inode_type();
if !type_.support_read() {
return_errno!(Errno::EISDIR);
}
let inner = self.inner.read();
let file_len = inner.inode.len();
if buf.len() < file_len {
buf.resize(file_len, 0);
}
if let Some(page_cache) = &inner.page_cache {
page_cache.evict_range(0..file_len);
}
inner.inode.read_at(0, &mut buf[..file_len])
}
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)
}
pub fn lookup(&self, name: &str) -> Result<Self> {
let inode = self.inner.read().inode.lookup(name)?;
Self::new(inode)
}
pub fn link(&self, old: &Vnode, name: &str) -> Result<()> {
self.inner.read().inode.link(&old.inner.read().inode, name)
}
pub fn unlink(&self, name: &str) -> Result<()> {
self.inner.read().inode.unlink(name)
}
pub fn rmdir(&self, name: &str) -> Result<()> {
self.inner.read().inode.rmdir(name)
}
pub fn rename(&self, old_name: &str, target: &Vnode, new_name: &str) -> Result<()> {
self.inner
.read()
.inode
.rename(old_name, &target.inner.read().inode, new_name)
}
pub fn read_link(&self) -> Result<String> {
self.inner.read().inode.read_link()
}
pub fn write_link(&self, target: &str) -> Result<()> {
self.inner.write().inode.write_link(target)
}
pub fn readdir_at(&self, offset: usize, visitor: &mut dyn DirentVisitor) -> Result<usize> {
self.inner.read().inode.readdir_at(offset, visitor)
}
pub fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
let inode = self.inner.read().inode.clone();
inode.poll(mask, poller)
}
pub fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
let inode = self.inner.read().inode.clone();
inode.ioctl(cmd, arg)
}
pub fn fs(&self) -> Arc<dyn FileSystem> {
self.inner.read().inode.fs()
}
pub fn metadata(&self) -> Metadata {
self.inner.read().inode.metadata()
}
pub fn inode(&self) -> Weak<dyn Inode> {
let inner = self.inner.read();
Arc::downgrade(&inner.inode)
}
pub fn inode_type(&self) -> InodeType {
self.inner.read().inode.metadata().type_
}
pub fn inode_mode(&self) -> InodeMode {
self.inner.read().inode.metadata().mode
}
pub fn set_inode_mode(&self, mode: InodeMode) {
self.inner.read().inode.set_mode(mode)
}
pub fn len(&self) -> usize {
self.inner.read().inode.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn atime(&self) -> Duration {
self.inner.read().inode.atime()
}
pub fn set_atime(&self, time: Duration) {
self.inner.read().inode.set_atime(time)
}
pub fn mtime(&self) -> Duration {
self.inner.read().inode.mtime()
}
pub fn set_mtime(&self, time: Duration) {
self.inner.read().inode.set_mtime(time)
}
pub fn is_dentry_cacheable(&self) -> bool {
self.inner.read().inode.is_dentry_cacheable()
}
pub fn writer(&self, from_offset: usize) -> VnodeWriter {
VnodeWriter {
inner: self,
offset: from_offset,
}
}
}
impl Debug for Vnode {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("Vnode")
.field("inode", &self.inner.read().inode)
.field("page_cache", &self.inner.read().page_cache)
.finish()
}
}
pub struct VnodeWriter<'a> {
inner: &'a Vnode,
offset: usize,
}
impl<'a> Write for VnodeWriter<'a> {
#[inline]
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
let write_len = self
.inner
.write_at(self.offset, buf)
.map_err(|_| IoError::new(IoErrorKind::WriteZero, "failed to write buffer"))?;
self.offset += write_len;
Ok(write_len)
}
#[inline]
fn flush(&mut self) -> IoResult<()> {
Ok(())
}
}

View File

@ -18,15 +18,7 @@ impl PartialEq for UnixSocketAddrBound {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
match (self, other) { match (self, other) {
(Self::Abstract(l0), Self::Abstract(r0)) => l0 == r0, (Self::Abstract(l0), Self::Abstract(r0)) => l0 == r0,
(Self::Path(l0), Self::Path(r0)) => { (Self::Path(l0), Self::Path(r0)) => Arc::ptr_eq(l0.inode(), r0.inode()),
let Some(linode) = l0.inode().upgrade() else {
return false;
};
let Some(rinode) = r0.inode().upgrade() else {
return false;
};
Arc::ptr_eq(&linode, &rinode)
}
_ => false, _ => false,
} }
} }

View File

@ -203,8 +203,8 @@ impl Backlog {
} }
fn create_keyable_inode(dentry: &Arc<Dentry>) -> KeyableWeak<dyn Inode> { fn create_keyable_inode(dentry: &Arc<Dentry>) -> KeyableWeak<dyn Inode> {
let inode = dentry.inode(); let weak_inode = Arc::downgrade(dentry.inode());
KeyableWeak::from(inode) KeyableWeak::from(weak_inode)
} }
pub(super) fn unregister_backlog(addr: &UnixSocketAddrBound) { pub(super) fn unregister_backlog(addr: &UnixSocketAddrBound) {

View File

@ -69,8 +69,8 @@ fn lookup_and_parse_ldso(
}; };
let ldso_elf = { let ldso_elf = {
let mut buf = Box::new([0u8; PAGE_SIZE]); let mut buf = Box::new([0u8; PAGE_SIZE]);
let vnode = ldso_file.vnode(); let inode = ldso_file.inode();
vnode.read_at(0, &mut *buf)?; inode.read_at(0, &mut *buf)?;
Elf::parse_elf(&*buf)? Elf::parse_elf(&*buf)?
}; };
Ok((ldso_file, ldso_elf)) Ok((ldso_file, ldso_elf))
@ -250,8 +250,8 @@ fn init_segment_vmo(program_header: &ProgramHeader64, elf_file: &Dentry) -> Resu
let virtual_addr = program_header.virtual_addr as usize; let virtual_addr = program_header.virtual_addr as usize;
debug_assert!(file_offset % PAGE_SIZE == virtual_addr % PAGE_SIZE); debug_assert!(file_offset % PAGE_SIZE == virtual_addr % PAGE_SIZE);
let page_cache_vmo = { let page_cache_vmo = {
let vnode = elf_file.vnode(); let inode = elf_file.inode();
vnode.page_cache().ok_or(Error::with_message( inode.page_cache().ok_or(Error::with_message(
Errno::ENOENT, Errno::ENOENT,
"executable has no page cache", "executable has no page cache",
))? ))?

View File

@ -26,11 +26,11 @@ pub fn load_program_to_vm(
recursion_limit: usize, recursion_limit: usize,
) -> Result<(String, ElfLoadInfo)> { ) -> Result<(String, ElfLoadInfo)> {
let abs_path = elf_file.abs_path(); let abs_path = elf_file.abs_path();
let vnode = elf_file.vnode(); let inode = elf_file.inode();
let file_header = { let file_header = {
// read the first page of file header // read the first page of file header
let mut file_header_buffer = Box::new([0u8; PAGE_SIZE]); let mut file_header_buffer = Box::new([0u8; PAGE_SIZE]);
vnode.read_at(0, &mut *file_header_buffer)?; inode.read_at(0, &mut *file_header_buffer)?;
file_header_buffer file_header_buffer
}; };
if let Some(mut new_argv) = parse_shebang_line(&*file_header)? { if let Some(mut new_argv) = parse_shebang_line(&*file_header)? {

View File

@ -102,8 +102,8 @@ fn mmap_filebacked_vmo(
let page_cache_vmo = { let page_cache_vmo = {
let fs_resolver = current.fs().read(); let fs_resolver = current.fs().read();
let dentry = fs_resolver.lookup_from_fd(fd)?; let dentry = fs_resolver.lookup_from_fd(fd)?;
let vnode = dentry.vnode(); let inode = dentry.inode();
vnode.page_cache().ok_or(Error::with_message( inode.page_cache().ok_or(Error::with_message(
Errno::EBADF, Errno::EBADF,
"File does not have page cache", "File does not have page cache",
))? ))?

View File

@ -32,7 +32,7 @@ pub fn sys_readlinkat(
let fs_path = FsPath::new(dirfd, pathname.as_ref())?; let fs_path = FsPath::new(dirfd, pathname.as_ref())?;
current.fs().read().lookup_no_follow(&fs_path)? current.fs().read().lookup_no_follow(&fs_path)?
}; };
let linkpath = dentry.read_link()?; let linkpath = dentry.inode().read_link()?;
let bytes = linkpath.as_bytes(); let bytes = linkpath.as_bytes();
let write_len = bytes.len().min(usr_buf_len); let write_len = bytes.len().min(usr_buf_len);
write_bytes_to_user(usr_buf_addr, &bytes[..write_len])?; write_bytes_to_user(usr_buf_addr, &bytes[..write_len])?;

View File

@ -46,7 +46,7 @@ pub fn sys_symlinkat(
InodeType::SymLink, InodeType::SymLink,
InodeMode::from_bits_truncate(0o777), InodeMode::from_bits_truncate(0o777),
)?; )?;
new_dentry.write_link(&target)?; new_dentry.inode().write_link(&target)?;
Ok(SyscallReturn::Return(0)) Ok(SyscallReturn::Return(0))
} }