mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-28 03:43:23 +00:00
Remove Vnode to let the fs use PageCache for itself
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
aeea333945
commit
98bf3d4845
@ -27,7 +27,7 @@ pub fn init() -> Result<()> {
|
||||
InodeType::SymLink,
|
||||
InodeMode::from_bits_truncate(0o777),
|
||||
)?;
|
||||
ptmx.write_link("pts/ptmx")?;
|
||||
ptmx.inode().write_link("pts/ptmx")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,16 @@ impl Inode for PtyMasterInode {
|
||||
self.0.ptmx().metadata()
|
||||
}
|
||||
|
||||
fn type_(&self) -> InodeType {
|
||||
self.0.ptmx().metadata().type_
|
||||
}
|
||||
|
||||
fn mode(&self) -> InodeMode {
|
||||
self.0.ptmx().metadata().mode
|
||||
}
|
||||
|
||||
fn set_mode(&self, mode: InodeMode) {}
|
||||
|
||||
fn atime(&self) -> Duration {
|
||||
self.0.ptmx().metadata().atime
|
||||
}
|
||||
@ -58,8 +68,6 @@ impl Inode for PtyMasterInode {
|
||||
|
||||
fn set_mtime(&self, time: Duration) {}
|
||||
|
||||
fn set_mode(&self, mode: InodeMode) {}
|
||||
|
||||
fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
@ -72,10 +80,18 @@ impl Inode for PtyMasterInode {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
self.0.ioctl(cmd, arg)
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ impl FileSystem for DevPts {
|
||||
}
|
||||
|
||||
fn flags(&self) -> FsFlags {
|
||||
FsFlags::NO_PAGECACHE
|
||||
FsFlags::empty()
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,6 +148,16 @@ impl Inode for RootInode {
|
||||
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 {
|
||||
self.metadata.atime
|
||||
}
|
||||
@ -160,8 +170,6 @@ impl Inode for RootInode {
|
||||
|
||||
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>> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
@ -66,6 +66,16 @@ impl Inode for Ptmx {
|
||||
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 {
|
||||
self.metadata.atime
|
||||
}
|
||||
@ -78,8 +88,6 @@ impl Inode for Ptmx {
|
||||
|
||||
fn set_mtime(&self, time: Duration) {}
|
||||
|
||||
fn set_mode(&self, mode: InodeMode) {}
|
||||
|
||||
fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
@ -92,10 +100,18 @@ impl Inode for Ptmx {
|
||||
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> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
Ok(0)
|
||||
}
|
||||
|
@ -50,6 +50,16 @@ impl Inode for PtySlaveInode {
|
||||
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 {
|
||||
self.metadata.atime
|
||||
}
|
||||
@ -62,8 +72,6 @@ impl Inode for PtySlaveInode {
|
||||
|
||||
fn set_mtime(&self, time: Duration) {}
|
||||
|
||||
fn set_mode(&self, mode: InodeMode) {}
|
||||
|
||||
fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
@ -76,10 +84,18 @@ impl Inode for PtySlaveInode {
|
||||
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> {
|
||||
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> {
|
||||
self.device.ioctl(cmd, arg)
|
||||
}
|
||||
|
@ -62,8 +62,8 @@ impl FsResolver {
|
||||
let follow_tail_link = !creation_flags.contains(CreationFlags::O_NOFOLLOW);
|
||||
let dentry = match self.lookup_inner(path, follow_tail_link) {
|
||||
Ok(dentry) => {
|
||||
let vnode = dentry.vnode();
|
||||
if vnode.inode_type() == InodeType::SymLink
|
||||
let inode = dentry.inode();
|
||||
if inode.type_() == InodeType::SymLink
|
||||
&& !status_flags.contains(StatusFlags::O_PATH)
|
||||
{
|
||||
return_errno_with_message!(Errno::ELOOP, "file is a symlink");
|
||||
@ -74,7 +74,7 @@ impl FsResolver {
|
||||
return_errno_with_message!(Errno::EEXIST, "file exists");
|
||||
}
|
||||
if creation_flags.contains(CreationFlags::O_DIRECTORY)
|
||||
&& vnode.inode_type() != InodeType::Dir
|
||||
&& inode.type_() != InodeType::Dir
|
||||
{
|
||||
return_errno_with_message!(
|
||||
Errno::ENOTDIR,
|
||||
@ -95,7 +95,7 @@ impl FsResolver {
|
||||
if file_name.ends_with('/') {
|
||||
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");
|
||||
}
|
||||
dir_dentry.create(&file_name, InodeType::File, inode_mode)?
|
||||
@ -177,7 +177,7 @@ impl FsResolver {
|
||||
|
||||
// Iterate next dentry
|
||||
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();
|
||||
|
||||
// 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");
|
||||
}
|
||||
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() {
|
||||
return_errno_with_message!(Errno::ENOENT, "empty symlink");
|
||||
}
|
||||
@ -275,9 +275,9 @@ impl FsResolver {
|
||||
// Dereference the tail symlinks if needed
|
||||
loop {
|
||||
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 mut link = dentry.vnode().read_link()?;
|
||||
let mut link = dentry.inode().read_link()?;
|
||||
if link.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "invalid symlink");
|
||||
}
|
||||
|
@ -11,14 +11,14 @@ impl InodeHandle<Rights> {
|
||||
access_mode: AccessMode,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<Self> {
|
||||
let vnode = dentry.vnode();
|
||||
if access_mode.is_readable() && !vnode.inode_mode().is_readable() {
|
||||
let inode = dentry.inode();
|
||||
if access_mode.is_readable() && !inode.mode().is_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");
|
||||
}
|
||||
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");
|
||||
}
|
||||
let inner = Arc::new(InodeHandle_ {
|
||||
@ -75,15 +75,15 @@ impl FileLike for InodeHandle<Rights> {
|
||||
}
|
||||
|
||||
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> {
|
||||
self.dentry().vnode().ioctl(cmd, arg)
|
||||
self.dentry().inode().ioctl(cmd, arg)
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Metadata {
|
||||
self.dentry().vnode().metadata()
|
||||
self.dentry().inode_metadata()
|
||||
}
|
||||
|
||||
fn status_flags(&self) -> StatusFlags {
|
||||
|
@ -26,9 +26,9 @@ impl InodeHandle_ {
|
||||
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
||||
let mut offset = self.offset.lock();
|
||||
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 {
|
||||
self.dentry.vnode().read_at(*offset, buf)?
|
||||
self.dentry.inode().read_at(*offset, buf)?
|
||||
};
|
||||
|
||||
*offset += len;
|
||||
@ -38,12 +38,12 @@ impl InodeHandle_ {
|
||||
pub fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||
let mut offset = self.offset.lock();
|
||||
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) {
|
||||
self.dentry.vnode().write_direct_at(*offset, buf)?
|
||||
self.dentry.inode().write_direct_at(*offset, buf)?
|
||||
} else {
|
||||
self.dentry.vnode().write_at(*offset, buf)?
|
||||
self.dentry.inode().write_at(*offset, buf)?
|
||||
};
|
||||
|
||||
*offset += len;
|
||||
@ -52,9 +52,9 @@ impl InodeHandle_ {
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
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 {
|
||||
self.dentry.vnode().read_to_end(buf)?
|
||||
self.dentry.inode().read_to_end(buf)?
|
||||
};
|
||||
Ok(len)
|
||||
}
|
||||
@ -69,7 +69,7 @@ impl InodeHandle_ {
|
||||
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);
|
||||
file_size
|
||||
.checked_add(off)
|
||||
@ -94,7 +94,7 @@ impl InodeHandle_ {
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.dentry.vnode().len()
|
||||
self.dentry.inode_len()
|
||||
}
|
||||
|
||||
pub fn access_mode(&self) -> AccessMode {
|
||||
@ -113,7 +113,7 @@ impl InodeHandle_ {
|
||||
|
||||
pub fn readdir(&self, visitor: &mut dyn DirentVisitor) -> Result<usize> {
|
||||
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;
|
||||
Ok(read_cnt)
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ impl FileSystem for ProcFS {
|
||||
}
|
||||
|
||||
fn flags(&self) -> FsFlags {
|
||||
FsFlags::NO_PAGECACHE
|
||||
FsFlags::empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,18 @@ impl<D: DirOps + 'static> Inode for ProcDir<D> {
|
||||
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 {
|
||||
self.info.atime()
|
||||
}
|
||||
@ -80,10 +92,6 @@ impl<D: DirOps + 'static> Inode for ProcDir<D> {
|
||||
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>> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use core::time::Duration;
|
||||
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 super::{ProcFS, ProcInodeInfo};
|
||||
@ -37,6 +37,18 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
|
||||
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 {
|
||||
self.info.atime()
|
||||
}
|
||||
@ -53,10 +65,6 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
|
||||
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<()> {
|
||||
unreachable!()
|
||||
}
|
||||
@ -74,10 +82,18 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
|
||||
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> {
|
||||
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> {
|
||||
Err(Error::new(Errno::EINVAL))
|
||||
}
|
||||
|
@ -58,6 +58,10 @@ impl ProcInodeInfo {
|
||||
self.metadata.write().mtime = time;
|
||||
}
|
||||
|
||||
pub fn mode(&self) -> InodeMode {
|
||||
self.metadata.read().mode
|
||||
}
|
||||
|
||||
pub fn set_mode(&self, mode: InodeMode) {
|
||||
self.metadata.write().mode = mode;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use core::time::Duration;
|
||||
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 super::{ProcFS, ProcInodeInfo};
|
||||
@ -37,6 +37,18 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
|
||||
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 {
|
||||
self.info.atime()
|
||||
}
|
||||
@ -53,10 +65,6 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
|
||||
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<()> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
@ -69,10 +77,18 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
|
||||
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> {
|
||||
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> {
|
||||
self.inner.read_link()
|
||||
}
|
||||
|
@ -1,49 +1,41 @@
|
||||
use crate::events::IoEvents;
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::Poller;
|
||||
use alloc::str;
|
||||
use alloc::string::String;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use core::time::Duration;
|
||||
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 super::*;
|
||||
use crate::events::IoEvents;
|
||||
use crate::fs::device::Device;
|
||||
use crate::fs::utils::{
|
||||
DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata,
|
||||
SuperBlock, NAME_MAX,
|
||||
DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata, PageCache,
|
||||
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.
|
||||
pub struct RamFS {
|
||||
metadata: RwLock<SuperBlock>,
|
||||
root: Arc<RamInode>,
|
||||
inode_allocator: AtomicUsize,
|
||||
flags: FsFlags,
|
||||
}
|
||||
|
||||
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 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
|
||||
@ -78,7 +70,7 @@ impl FileSystem for RamFS {
|
||||
}
|
||||
|
||||
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 {
|
||||
inner: Inner::File,
|
||||
inner: Inner::File(PageCache::new(weak_inode).unwrap()),
|
||||
metadata: Metadata::new_file(ino, mode, sb),
|
||||
this: Weak::default(),
|
||||
fs: Weak::default(),
|
||||
@ -112,7 +109,7 @@ impl Inode_ {
|
||||
|
||||
pub fn new_symlink(ino: usize, mode: InodeMode, sb: &SuperBlock) -> Self {
|
||||
Self {
|
||||
inner: Inner::SymLink(Str256::from("")),
|
||||
inner: Inner::SymLink(String::from("")),
|
||||
metadata: Metadata::new_symlink(ino, mode, sb),
|
||||
this: Weak::default(),
|
||||
fs: Weak::default(),
|
||||
@ -157,18 +154,34 @@ impl Inode_ {
|
||||
self.metadata.size = new_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)]
|
||||
enum Inner {
|
||||
Dir(DirEntry),
|
||||
File,
|
||||
SymLink(Str256),
|
||||
File(PageCache),
|
||||
SymLink(String),
|
||||
Device(Arc<dyn Device>),
|
||||
Socket,
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
fn as_file(&self) -> Option<&PageCache> {
|
||||
match self {
|
||||
Inner::File(page_cache) => Some(page_cache),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_direntry(&self) -> Option<&DirEntry> {
|
||||
match self {
|
||||
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 {
|
||||
Inner::SymLink(link) => Some(link),
|
||||
_ => None,
|
||||
@ -235,7 +248,7 @@ impl DirEntry {
|
||||
} else {
|
||||
self.children
|
||||
.iter()
|
||||
.any(|(child, _)| child == &Str256::from(name))
|
||||
.any(|(child, _)| child.as_ref() == name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,7 +260,7 @@ impl DirEntry {
|
||||
} else {
|
||||
self.children
|
||||
.idxes_and_items()
|
||||
.find(|(_, (child, _))| child == &Str256::from(name))
|
||||
.find(|(_, (child, _))| child.as_ref() == name)
|
||||
.map(|(idx, (_, inode))| (idx + 2, inode.clone()))
|
||||
}
|
||||
}
|
||||
@ -344,7 +357,7 @@ impl<'a> From<&'a str> for Str256 {
|
||||
s.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> {
|
||||
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().this = weak_self.clone();
|
||||
inode
|
||||
@ -432,18 +450,65 @@ impl Inode for RamInode {
|
||||
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() {
|
||||
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() {
|
||||
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 {
|
||||
@ -470,6 +535,14 @@ impl Inode for RamInode {
|
||||
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) {
|
||||
self.0.write().metadata.mode = mode;
|
||||
}
|
||||
@ -483,6 +556,10 @@ impl Inode for RamInode {
|
||||
if self.0.read().metadata.type_ != InodeType::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();
|
||||
if self_inode.inner.as_direntry().unwrap().contains_entry(name) {
|
||||
return_errno_with_message!(Errno::EEXIST, "entry exists");
|
||||
@ -501,6 +578,10 @@ impl Inode for RamInode {
|
||||
if self.0.read().metadata.type_ != InodeType::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();
|
||||
if self_inode.inner.as_direntry().unwrap().contains_entry(name) {
|
||||
return_errno_with_message!(Errno::EEXIST, "entry exists");
|
||||
@ -512,7 +593,7 @@ impl Inode for RamInode {
|
||||
InodeType::Socket => RamInode::new_socket(&fs, mode),
|
||||
InodeType::Dir => {
|
||||
let dir_inode = RamInode::new_dir(&fs, mode, &self_inode.this);
|
||||
self_inode.metadata.nlinks += 1;
|
||||
self_inode.inc_nlinks();
|
||||
dir_inode
|
||||
}
|
||||
_ => {
|
||||
@ -545,6 +626,9 @@ impl Inode for RamInode {
|
||||
if self.0.read().metadata.type_ != InodeType::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
|
||||
.downcast_ref::<RamInode>()
|
||||
.ok_or(Error::new(Errno::EXDEV))?;
|
||||
@ -563,7 +647,7 @@ impl Inode for RamInode {
|
||||
.append_entry(name, old.0.read().this.upgrade().unwrap());
|
||||
self_inode.inc_size();
|
||||
drop(self_inode);
|
||||
old.0.write().metadata.nlinks += 1;
|
||||
old.0.write().inc_nlinks();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -583,7 +667,7 @@ impl Inode for RamInode {
|
||||
self_dir.remove_entry(idx);
|
||||
self_inode.dec_size();
|
||||
drop(self_inode);
|
||||
target.0.write().metadata.nlinks -= 1;
|
||||
target.0.write().dec_nlinks();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -612,9 +696,11 @@ impl Inode for RamInode {
|
||||
}
|
||||
self_dir.remove_entry(idx);
|
||||
self_inode.dec_size();
|
||||
self_inode.metadata.nlinks -= 1;
|
||||
self_inode.dec_nlinks();
|
||||
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(())
|
||||
}
|
||||
|
||||
@ -638,6 +724,9 @@ impl Inode for RamInode {
|
||||
if self.0.read().metadata.type_ != InodeType::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
|
||||
.downcast_ref::<RamInode>()
|
||||
.ok_or(Error::new(Errno::EXDEV))?;
|
||||
@ -703,8 +792,8 @@ impl Inode for RamInode {
|
||||
self_inode.dec_size();
|
||||
target_inode.inc_size();
|
||||
if src_inode.0.read().metadata.type_ == InodeType::Dir {
|
||||
self_inode.metadata.nlinks -= 1;
|
||||
target_inode.metadata.nlinks += 1;
|
||||
self_inode.dec_nlinks();
|
||||
target_inode.inc_nlinks();
|
||||
}
|
||||
drop(self_inode);
|
||||
drop(target_inode);
|
||||
@ -736,7 +825,7 @@ impl Inode for RamInode {
|
||||
}
|
||||
let mut self_inode = self.0.write();
|
||||
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.
|
||||
self_inode.metadata.size = target.len();
|
||||
Ok(())
|
||||
|
@ -7,3 +7,4 @@ mod fs;
|
||||
const RAMFS_MAGIC: u64 = 0x0102_1994;
|
||||
const BLOCK_SIZE: usize = 4096;
|
||||
const ROOT_INO: usize = 1;
|
||||
const NAME_MAX: usize = 255;
|
||||
|
@ -12,7 +12,7 @@ use spin::Once;
|
||||
|
||||
/// Unpack and prepare the rootfs from the initramfs CPIO buffer.
|
||||
pub fn init(initramfs_buf: &[u8]) -> Result<()> {
|
||||
init_root_mount()?;
|
||||
init_root_mount();
|
||||
|
||||
println!("[kernel] unpacking the initramfs.cpio.gz to rootfs ...");
|
||||
let fs = FsResolver::new();
|
||||
@ -52,7 +52,7 @@ pub fn init(initramfs_buf: &[u8]) -> Result<()> {
|
||||
match metadata.file_type() {
|
||||
FileType::File => {
|
||||
let dentry = parent.create(name, InodeType::File, mode)?;
|
||||
entry.read_all(dentry.vnode().writer(0))?;
|
||||
entry.read_all(dentry.inode().writer(0))?;
|
||||
}
|
||||
FileType::Dir => {
|
||||
let _ = parent.create(name, InodeType::Dir, mode)?;
|
||||
@ -64,7 +64,7 @@ pub fn init(initramfs_buf: &[u8]) -> Result<()> {
|
||||
entry.read_all(&mut link_data)?;
|
||||
core::str::from_utf8(&link_data)?.to_string()
|
||||
};
|
||||
dentry.vnode().write_link(&link_content)?;
|
||||
dentry.inode().write_link(&link_content)?;
|
||||
}
|
||||
type_ => {
|
||||
panic!("unsupported file type = {:?} in initramfs", type_);
|
||||
@ -76,7 +76,7 @@ pub fn init(initramfs_buf: &[u8]) -> Result<()> {
|
||||
proc_dentry.mount(ProcFS::new())?;
|
||||
// Mount DevFS
|
||||
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");
|
||||
|
||||
Ok(())
|
||||
@ -84,14 +84,11 @@ pub fn init(initramfs_buf: &[u8]) -> Result<()> {
|
||||
|
||||
static ROOT_MOUNT: Once<Arc<MountNode>> = Once::new();
|
||||
|
||||
fn init_root_mount() -> Result<()> {
|
||||
ROOT_MOUNT.try_call_once(|| -> Result<Arc<MountNode>> {
|
||||
let rootfs = RamFS::new(true);
|
||||
let root_mount = MountNode::new_root(rootfs)?;
|
||||
Ok(root_mount)
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
fn init_root_mount() {
|
||||
ROOT_MOUNT.call_once(|| -> Arc<MountNode> {
|
||||
let rootfs = RamFS::new();
|
||||
MountNode::new_root(rootfs)
|
||||
});
|
||||
}
|
||||
|
||||
pub fn root_mount() -> &'static Arc<MountNode> {
|
||||
|
@ -5,7 +5,7 @@ use alloc::string::String;
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
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! {
|
||||
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
|
||||
pub struct Dentry {
|
||||
vnode: Vnode,
|
||||
inode: Arc<dyn Inode>,
|
||||
name_and_parent: RwLock<Option<(String, Arc<Dentry>)>>,
|
||||
this: Weak<Dentry>,
|
||||
children: Mutex<Children>,
|
||||
@ -22,21 +22,21 @@ pub struct 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
|
||||
/// struct holds an arc reference to this root dentry, while this dentry holds a
|
||||
/// weak reference to the MountNode struct.
|
||||
pub(super) fn new_root(vnode: Vnode, mount: Weak<MountNode>) -> Arc<Self> {
|
||||
let root = Self::new(vnode, DentryOptions::Root(mount));
|
||||
pub(super) fn new_root(inode: Arc<dyn Inode>, mount: Weak<MountNode>) -> Arc<Self> {
|
||||
let root = Self::new(inode, DentryOptions::Root(mount));
|
||||
DCACHE.lock().insert(root.key(), root.clone());
|
||||
root
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
vnode,
|
||||
inode,
|
||||
mount_node: match &options {
|
||||
DentryOptions::Root(mount) => mount.clone(),
|
||||
DentryOptions::Leaf(name_and_parent) => name_and_parent.1.mount_node.clone(),
|
||||
@ -129,9 +129,9 @@ impl Dentry {
|
||||
DentryKey::new(self)
|
||||
}
|
||||
|
||||
/// Get the vnode.
|
||||
pub fn vnode(&self) -> &Vnode {
|
||||
&self.vnode
|
||||
/// Get the inode.
|
||||
pub fn inode(&self) -> &Arc<dyn Inode> {
|
||||
&self.inode
|
||||
}
|
||||
|
||||
/// Get the DentryFlags.
|
||||
@ -164,13 +164,9 @@ impl Dentry {
|
||||
self.mount_node.upgrade().unwrap()
|
||||
}
|
||||
|
||||
pub fn inode(&self) -> Weak<dyn Inode> {
|
||||
self.vnode.inode()
|
||||
}
|
||||
|
||||
/// Create a dentry by making inode.
|
||||
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);
|
||||
}
|
||||
let mut children = self.children.lock();
|
||||
@ -179,9 +175,9 @@ impl Dentry {
|
||||
}
|
||||
|
||||
let child = {
|
||||
let vnode = self.vnode.create(name, type_, mode)?;
|
||||
let inode = self.inode.create(name, type_, mode)?;
|
||||
let dentry = Self::new(
|
||||
vnode,
|
||||
inode,
|
||||
DentryOptions::Leaf((String::from(name), self.this())),
|
||||
);
|
||||
children.insert_dentry(&dentry);
|
||||
@ -192,7 +188,7 @@ impl Dentry {
|
||||
|
||||
/// 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 {
|
||||
if self.inode.type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
let mut children = self.children.lock();
|
||||
@ -201,9 +197,9 @@ impl Dentry {
|
||||
}
|
||||
|
||||
let child = {
|
||||
let vnode = self.vnode.mknod(name, mode, device)?;
|
||||
let inode = self.inode.mknod(name, mode, device)?;
|
||||
let dentry = Self::new(
|
||||
vnode,
|
||||
inode,
|
||||
DentryOptions::Leaf((String::from(name), self.this())),
|
||||
);
|
||||
children.insert_dentry(&dentry);
|
||||
@ -214,10 +210,10 @@ impl Dentry {
|
||||
|
||||
/// Lookup a dentry.
|
||||
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);
|
||||
}
|
||||
if !self.vnode.inode_mode().is_executable() {
|
||||
if !self.inode.mode().is_executable() {
|
||||
return_errno!(Errno::EACCES);
|
||||
}
|
||||
if name.len() > NAME_MAX {
|
||||
@ -232,9 +228,9 @@ impl Dentry {
|
||||
match children.find_dentry(name) {
|
||||
Some(dentry) => dentry.overlaid_dentry(),
|
||||
None => {
|
||||
let vnode = self.vnode.lookup(name)?;
|
||||
let inode = self.inode.lookup(name)?;
|
||||
let dentry = Self::new(
|
||||
vnode,
|
||||
inode,
|
||||
DentryOptions::Leaf((String::from(name), self.this())),
|
||||
);
|
||||
children.insert_dentry(&dentry);
|
||||
@ -248,7 +244,7 @@ impl Dentry {
|
||||
|
||||
/// Link a new name for the dentry by linking inode.
|
||||
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);
|
||||
}
|
||||
let mut children = self.children.lock();
|
||||
@ -258,10 +254,10 @@ impl Dentry {
|
||||
if !Arc::ptr_eq(&old.mount_node(), &self.mount_node()) {
|
||||
return_errno_with_message!(Errno::EXDEV, "cannot cross mount");
|
||||
}
|
||||
let old_vnode = old.vnode();
|
||||
self.vnode.link(old_vnode, name)?;
|
||||
let old_inode = old.inode();
|
||||
self.inode.link(old_inode, name)?;
|
||||
let dentry = Self::new(
|
||||
old_vnode.clone(),
|
||||
old_inode.clone(),
|
||||
DentryOptions::Leaf((String::from(name), self.this())),
|
||||
);
|
||||
children.insert_dentry(&dentry);
|
||||
@ -270,51 +266,34 @@ impl Dentry {
|
||||
|
||||
/// Delete a dentry by unlinking inode.
|
||||
pub fn unlink(&self, name: &str) -> Result<()> {
|
||||
if self.vnode.inode_type() != InodeType::Dir {
|
||||
if self.inode.type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
let mut children = self.children.lock();
|
||||
let _ = children.find_dentry_with_checking_mountpoint(name)?;
|
||||
self.vnode.unlink(name)?;
|
||||
self.inode.unlink(name)?;
|
||||
children.delete_dentry(name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Delete a directory dentry by rmdiring inode.
|
||||
pub fn rmdir(&self, name: &str) -> Result<()> {
|
||||
if self.vnode.inode_type() != InodeType::Dir {
|
||||
if self.inode.type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
let mut children = self.children.lock();
|
||||
let _ = children.find_dentry_with_checking_mountpoint(name)?;
|
||||
self.vnode.rmdir(name)?;
|
||||
self.inode.rmdir(name)?;
|
||||
children.delete_dentry(name);
|
||||
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.
|
||||
pub fn rename(&self, old_name: &str, new_dir: &Arc<Self>, new_name: &str) -> Result<()> {
|
||||
if old_name == "." || old_name == ".." || new_name == "." || new_name == ".." {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -326,7 +305,7 @@ impl Dentry {
|
||||
let mut children = self.children.lock();
|
||||
let old_dentry = children.find_dentry_with_checking_mountpoint(old_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() {
|
||||
Some(dentry) => {
|
||||
children.delete_dentry(old_name);
|
||||
@ -346,7 +325,7 @@ impl Dentry {
|
||||
write_lock_children_on_two_dentries(self, new_dir);
|
||||
let old_dentry = self_children.find_dentry_with_checking_mountpoint(old_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() {
|
||||
Some(dentry) => {
|
||||
self_children.delete_dentry(old_name);
|
||||
@ -369,7 +348,7 @@ impl Dentry {
|
||||
///
|
||||
/// Return the mounted child mount.
|
||||
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);
|
||||
}
|
||||
if self.effective_parent().is_none() {
|
||||
@ -401,52 +380,52 @@ impl Dentry {
|
||||
|
||||
/// Get the filesystem the inode belongs to
|
||||
pub fn fs(&self) -> Arc<dyn FileSystem> {
|
||||
self.vnode.fs()
|
||||
self.inode.fs()
|
||||
}
|
||||
|
||||
/// Get the inode metadata
|
||||
pub fn inode_metadata(&self) -> Metadata {
|
||||
self.vnode.metadata()
|
||||
self.inode.metadata()
|
||||
}
|
||||
|
||||
/// Get the inode type
|
||||
pub fn inode_type(&self) -> InodeType {
|
||||
self.vnode.inode_type()
|
||||
self.inode.type_()
|
||||
}
|
||||
|
||||
/// Get the inode permission mode
|
||||
pub fn inode_mode(&self) -> InodeMode {
|
||||
self.vnode.inode_mode()
|
||||
self.inode.mode()
|
||||
}
|
||||
|
||||
/// Set the inode permission mode
|
||||
pub fn set_inode_mode(&self, mode: InodeMode) {
|
||||
self.vnode.set_inode_mode(mode)
|
||||
self.inode.set_mode(mode)
|
||||
}
|
||||
|
||||
/// Get the inode length
|
||||
pub fn inode_len(&self) -> usize {
|
||||
self.vnode.len()
|
||||
self.inode.len()
|
||||
}
|
||||
|
||||
/// Get the access timestamp
|
||||
pub fn atime(&self) -> Duration {
|
||||
self.vnode.atime()
|
||||
self.inode.atime()
|
||||
}
|
||||
|
||||
/// Set the access timestamp
|
||||
pub fn set_atime(&self, time: Duration) {
|
||||
self.vnode.set_atime(time)
|
||||
self.inode.set_atime(time)
|
||||
}
|
||||
|
||||
/// Get the modified timestamp
|
||||
pub fn mtime(&self) -> Duration {
|
||||
self.vnode.mtime()
|
||||
self.inode.mtime()
|
||||
}
|
||||
|
||||
/// Set the modified timestamp
|
||||
pub fn set_mtime(&self, time: Duration) {
|
||||
self.vnode.set_mtime(time)
|
||||
self.inode.set_mtime(time)
|
||||
}
|
||||
|
||||
/// Get the absolute path.
|
||||
@ -482,7 +461,7 @@ impl Debug for Dentry {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
f.debug_struct("Dentry")
|
||||
.field("abs_path", &self.abs_path())
|
||||
.field("vnode", &self.vnode)
|
||||
.field("inode", &self.inode)
|
||||
.field("flags", &self.flags())
|
||||
.finish()
|
||||
}
|
||||
@ -537,7 +516,7 @@ impl Children {
|
||||
pub fn insert_dentry(&mut self, dentry: &Arc<Dentry>) {
|
||||
// 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.
|
||||
if !dentry.vnode().is_dentry_cacheable() {
|
||||
if !dentry.inode().is_dentry_cacheable() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,3 @@
|
||||
use alloc::sync::Arc;
|
||||
use bitflags::bitflags;
|
||||
use core::any::Any;
|
||||
|
||||
use super::Inode;
|
||||
use crate::prelude::*;
|
||||
|
||||
@ -40,8 +36,6 @@ impl SuperBlock {
|
||||
|
||||
bitflags! {
|
||||
pub struct FsFlags: u32 {
|
||||
/// Disable page cache.
|
||||
const NO_PAGECACHE = 1 << 0;
|
||||
/// Dentry cannot be evicted.
|
||||
const DENTRY_UNEVICTABLE = 1 << 1;
|
||||
}
|
||||
|
@ -1,18 +1,17 @@
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use bitflags::bitflags;
|
||||
use core::any::Any;
|
||||
use core::time::Duration;
|
||||
use core2::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult, Write};
|
||||
use jinux_frame::vm::VmFrame;
|
||||
use jinux_rights::Full;
|
||||
|
||||
use super::{DirentVisitor, FileSystem, IoctlCmd, SuperBlock};
|
||||
use crate::events::IoEvents;
|
||||
use crate::fs::device::{Device, DeviceType};
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::Poller;
|
||||
use crate::vm::vmo::Vmo;
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromInt)]
|
||||
pub enum InodeType {
|
||||
NamedPipe = 0o010000,
|
||||
CharDevice = 0o020000,
|
||||
@ -236,6 +235,12 @@ pub trait Inode: Any + Sync + Send {
|
||||
|
||||
fn metadata(&self) -> Metadata;
|
||||
|
||||
fn type_(&self) -> InodeType;
|
||||
|
||||
fn mode(&self) -> InodeMode;
|
||||
|
||||
fn set_mode(&self, mode: InodeMode);
|
||||
|
||||
fn atime(&self) -> 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_mode(&self, mode: InodeMode);
|
||||
|
||||
fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
@ -254,14 +257,26 @@ pub trait Inode: Any + Sync + Send {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
|
||||
fn page_cache(&self) -> Option<Vmo<Full>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
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> {
|
||||
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>> {
|
||||
Err(Error::new(Errno::ENOTDIR))
|
||||
}
|
||||
@ -343,6 +358,59 @@ impl dyn Inode {
|
||||
pub fn downcast_ref<T: Inode>(&self) -> Option<&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 {
|
||||
|
@ -13,7 +13,6 @@ pub use ioctl::IoctlCmd;
|
||||
pub use mount::MountNode;
|
||||
pub use page_cache::PageCache;
|
||||
pub use status_flags::StatusFlags;
|
||||
pub use vnode::{Vnode, VnodeWriter};
|
||||
|
||||
mod access_mode;
|
||||
mod channel;
|
||||
@ -28,7 +27,6 @@ mod ioctl;
|
||||
mod mount;
|
||||
mod page_cache;
|
||||
mod status_flags;
|
||||
mod vnode;
|
||||
|
||||
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
|
||||
pub enum SeekFrom {
|
||||
|
@ -1,6 +1,6 @@
|
||||
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.
|
||||
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
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// The internal constructor.
|
||||
///
|
||||
/// 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>> {
|
||||
let vnode = Vnode::new(fs.root_inode())?;
|
||||
Ok(Arc::new_cyclic(|weak_self| Self {
|
||||
root_dentry: Dentry::new_root(vnode, weak_self.clone()),
|
||||
fn new(fs: Arc<dyn FileSystem>, mountpoint: Option<Arc<Dentry>>) -> Arc<Self> {
|
||||
Arc::new_cyclic(|weak_self| Self {
|
||||
root_dentry: Dentry::new_root(fs.root_inode(), weak_self.clone()),
|
||||
mountpoint_dentry: mountpoint,
|
||||
children: Mutex::new(BTreeMap::new()),
|
||||
fs,
|
||||
this: weak_self.clone(),
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
/// 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 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());
|
||||
Ok(child_mount)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::Inode;
|
||||
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 core::ops::Range;
|
||||
@ -13,24 +13,40 @@ pub struct PageCache {
|
||||
}
|
||||
|
||||
impl PageCache {
|
||||
pub fn new(inode: &Arc<dyn Inode>) -> Result<Self> {
|
||||
let manager = Arc::new(PageCacheManager::new(Arc::downgrade(inode)));
|
||||
let pages = VmoOptions::<Full>::new(inode.len())
|
||||
/// Creates an empty size page cache associated with a new inode.
|
||||
pub fn new(backed_inode: Weak<dyn Inode>) -> Result<Self> {
|
||||
let manager = Arc::new(PageCacheManager::new(backed_inode));
|
||||
let pages = VmoOptions::<Full>::new(0)
|
||||
.flags(VmoFlags::RESIZABLE)
|
||||
.pager(manager.clone())
|
||||
.alloc()?;
|
||||
Ok(Self { pages, manager })
|
||||
}
|
||||
|
||||
pub fn pages(&self) -> &Vmo<Full> {
|
||||
&self.pages
|
||||
/// Creates a page cache associated with an existing inode.
|
||||
///
|
||||
/// 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 high,restrict 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
|
||||
/// them to the disk.
|
||||
pub fn evict_range(&self, range: Range<usize>) {
|
||||
// TODO: Implement this method.
|
||||
warn!("pagecache: evict_range is not implemented");
|
||||
pub fn evict_range(&self, range: Range<usize>) -> Result<()> {
|
||||
self.manager.evict_range(range)
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,12 +65,31 @@ struct PageCacheManager {
|
||||
}
|
||||
|
||||
impl PageCacheManager {
|
||||
pub fn new(inode: Weak<dyn Inode>) -> Self {
|
||||
pub fn new(backed_inode: Weak<dyn Inode>) -> Self {
|
||||
Self {
|
||||
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 {
|
||||
@ -70,20 +105,18 @@ impl Pager for PageCacheManager {
|
||||
let page_idx = offset / PAGE_SIZE;
|
||||
let mut pages = self.pages.lock();
|
||||
let frame = if let Some(page) = pages.get(&page_idx) {
|
||||
page.frame()
|
||||
page.frame().clone()
|
||||
} else {
|
||||
let page = if offset < self.backed_inode.upgrade().unwrap().metadata().size {
|
||||
let mut page = Page::alloc_zero()?;
|
||||
self.backed_inode
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.read_page(page_idx, &page.frame())?;
|
||||
let backed_inode = self.backed_inode.upgrade().unwrap();
|
||||
let page = if offset < backed_inode.len() {
|
||||
let mut page = Page::alloc()?;
|
||||
backed_inode.read_page(page_idx, page.frame())?;
|
||||
page.set_state(PageState::UpToDate);
|
||||
page
|
||||
} else {
|
||||
Page::alloc_zero()?
|
||||
};
|
||||
let frame = page.frame();
|
||||
let frame = page.frame().clone();
|
||||
pages.put(page_idx, page);
|
||||
frame
|
||||
};
|
||||
@ -110,7 +143,7 @@ impl Pager for PageCacheManager {
|
||||
self.backed_inode
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.write_page(page_idx, &page.frame())?
|
||||
.write_page(page_idx, page.frame())?
|
||||
}
|
||||
} else {
|
||||
warn!("page {} is not in page cache, do nothing", page_idx);
|
||||
@ -151,8 +184,8 @@ impl Page {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn frame(&self) -> VmFrame {
|
||||
self.frame.clone()
|
||||
pub fn frame(&self) -> &VmFrame {
|
||||
&self.frame
|
||||
}
|
||||
|
||||
pub fn state(&self) -> &PageState {
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
@ -18,15 +18,7 @@ impl PartialEq for UnixSocketAddrBound {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Abstract(l0), Self::Abstract(r0)) => l0 == r0,
|
||||
(Self::Path(l0), Self::Path(r0)) => {
|
||||
let Some(linode) = l0.inode().upgrade() else {
|
||||
return false;
|
||||
};
|
||||
let Some(rinode) = r0.inode().upgrade() else {
|
||||
return false;
|
||||
};
|
||||
Arc::ptr_eq(&linode, &rinode)
|
||||
}
|
||||
(Self::Path(l0), Self::Path(r0)) => Arc::ptr_eq(l0.inode(), r0.inode()),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -203,8 +203,8 @@ impl Backlog {
|
||||
}
|
||||
|
||||
fn create_keyable_inode(dentry: &Arc<Dentry>) -> KeyableWeak<dyn Inode> {
|
||||
let inode = dentry.inode();
|
||||
KeyableWeak::from(inode)
|
||||
let weak_inode = Arc::downgrade(dentry.inode());
|
||||
KeyableWeak::from(weak_inode)
|
||||
}
|
||||
|
||||
pub(super) fn unregister_backlog(addr: &UnixSocketAddrBound) {
|
||||
|
@ -69,8 +69,8 @@ fn lookup_and_parse_ldso(
|
||||
};
|
||||
let ldso_elf = {
|
||||
let mut buf = Box::new([0u8; PAGE_SIZE]);
|
||||
let vnode = ldso_file.vnode();
|
||||
vnode.read_at(0, &mut *buf)?;
|
||||
let inode = ldso_file.inode();
|
||||
inode.read_at(0, &mut *buf)?;
|
||||
Elf::parse_elf(&*buf)?
|
||||
};
|
||||
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;
|
||||
debug_assert!(file_offset % PAGE_SIZE == virtual_addr % PAGE_SIZE);
|
||||
let page_cache_vmo = {
|
||||
let vnode = elf_file.vnode();
|
||||
vnode.page_cache().ok_or(Error::with_message(
|
||||
let inode = elf_file.inode();
|
||||
inode.page_cache().ok_or(Error::with_message(
|
||||
Errno::ENOENT,
|
||||
"executable has no page cache",
|
||||
))?
|
||||
|
@ -26,11 +26,11 @@ pub fn load_program_to_vm(
|
||||
recursion_limit: usize,
|
||||
) -> Result<(String, ElfLoadInfo)> {
|
||||
let abs_path = elf_file.abs_path();
|
||||
let vnode = elf_file.vnode();
|
||||
let inode = elf_file.inode();
|
||||
let file_header = {
|
||||
// read the first page of file header
|
||||
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
|
||||
};
|
||||
if let Some(mut new_argv) = parse_shebang_line(&*file_header)? {
|
||||
|
@ -102,8 +102,8 @@ fn mmap_filebacked_vmo(
|
||||
let page_cache_vmo = {
|
||||
let fs_resolver = current.fs().read();
|
||||
let dentry = fs_resolver.lookup_from_fd(fd)?;
|
||||
let vnode = dentry.vnode();
|
||||
vnode.page_cache().ok_or(Error::with_message(
|
||||
let inode = dentry.inode();
|
||||
inode.page_cache().ok_or(Error::with_message(
|
||||
Errno::EBADF,
|
||||
"File does not have page cache",
|
||||
))?
|
||||
|
@ -32,7 +32,7 @@ pub fn sys_readlinkat(
|
||||
let fs_path = FsPath::new(dirfd, pathname.as_ref())?;
|
||||
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 write_len = bytes.len().min(usr_buf_len);
|
||||
write_bytes_to_user(usr_buf_addr, &bytes[..write_len])?;
|
||||
|
@ -46,7 +46,7 @@ pub fn sys_symlinkat(
|
||||
InodeType::SymLink,
|
||||
InodeMode::from_bits_truncate(0o777),
|
||||
)?;
|
||||
new_dentry.write_link(&target)?;
|
||||
new_dentry.inode().write_link(&target)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user