use super::{ DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoEvents, IoctlCmd, Metadata, PageCache, Poller, }; use crate::fs::device::Device; use crate::prelude::*; use crate::vm::vmo::Vmo; use alloc::string::String; use core::time::Duration; 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>, } struct Inner { inode: Arc, page_cache: Option, } impl Vnode { pub fn page_cache(&self) -> Option> { self.inner .read() .page_cache .as_ref() .map(|page_chche| page_chche.pages().dup().unwrap()) } pub fn new(inode: Arc) -> Result { 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 { 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 { 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 { 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 { 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) -> Result { 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) -> Result { 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 { let inode = self.inner.read().inode.create(name, type_, mode)?; Self::new(inode) } pub fn mknod(&self, name: &str, mode: InodeMode, device: Arc) -> Result { let inode = self.inner.read().inode.mknod(name, mode, device)?; Self::new(inode) } pub fn lookup(&self, name: &str) -> Result { 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 { 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 { self.inner.read().inode.readdir_at(offset, visitor) } pub fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { self.inner.read().inode.poll(mask, poller) } pub fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { self.inner.read().inode.ioctl(cmd, arg) } pub fn fs(&self) -> Arc { self.inner.read().inode.fs() } pub fn metadata(&self) -> Metadata { self.inner.read().inode.metadata() } 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 len(&self) -> usize { self.inner.read().inode.len() } 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() } }