mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-15 00:06:47 +00:00
245 lines
7.3 KiB
Rust
245 lines
7.3 KiB
Rust
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<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 {
|
|
self.inner.read().inode.poll(mask, poller)
|
|
}
|
|
|
|
pub fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
|
self.inner.read().inode.ioctl(cmd, arg)
|
|
}
|
|
|
|
pub fn fs(&self) -> Arc<dyn FileSystem> {
|
|
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()
|
|
}
|
|
}
|