Enhance the vnode

This commit is contained in:
LI Qing
2023-03-02 09:36:17 +08:00
committed by Tate, Hongliang Tian
parent 9606119028
commit ece1a545ce
14 changed files with 279 additions and 97 deletions

View File

@ -9,14 +9,14 @@ impl InodeHandle<Rights> {
access_mode: AccessMode, access_mode: AccessMode,
status_flags: StatusFlags, status_flags: StatusFlags,
) -> Result<Self> { ) -> Result<Self> {
let inode_info = dentry.vnode().inode().metadata(); let vnode = dentry.vnode();
if access_mode.is_readable() && !inode_info.mode.is_readable() { if access_mode.is_readable() && !vnode.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() && !inode_info.mode.is_writable() { if access_mode.is_writable() && !vnode.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() && inode_info.type_ == InodeType::Dir { if access_mode.is_writable() && vnode.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_ {
@ -43,6 +43,13 @@ impl InodeHandle<Rights> {
self.0.read(buf) self.0.read(buf)
} }
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
if !self.1.contains(Rights::READ) {
return_errno_with_message!(Errno::EBADF, "File is not readable");
}
self.0.read_to_end(buf)
}
pub fn write(&self, buf: &[u8]) -> Result<usize> { pub fn write(&self, buf: &[u8]) -> Result<usize> {
if !self.1.contains(Rights::WRITE) { if !self.1.contains(Rights::WRITE) {
return_errno_with_message!(Errno::EBADF, "File is not writable"); return_errno_with_message!(Errno::EBADF, "File is not writable");

View File

@ -8,8 +8,6 @@ use crate::fs::utils::{
}; };
use crate::prelude::*; use crate::prelude::*;
use crate::rights::Rights; use crate::rights::Rights;
use alloc::sync::Arc;
use jinux_frame::vm::VmIo;
pub struct InodeHandle<R = Rights>(Arc<InodeHandle_>, R); pub struct InodeHandle<R = Rights>(Arc<InodeHandle_>, R);
@ -23,20 +21,10 @@ struct InodeHandle_ {
impl InodeHandle_ { 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 file_size = self.dentry.vnode().inode().metadata().size;
let start = file_size.min(*offset);
let end = file_size.min(*offset + buf.len());
let len = if self.status_flags.lock().contains(StatusFlags::O_DIRECT) { let len = if self.status_flags.lock().contains(StatusFlags::O_DIRECT) {
self.dentry self.dentry.vnode().read_direct_at(*offset, buf)?
.vnode()
.inode()
.read_at(start, &mut buf[0..end - start])?
} else { } else {
self.dentry self.dentry.vnode().read_at(*offset, buf)?
.vnode()
.pages()
.read_bytes(start, &mut buf[0..end - start])?;
end - start
}; };
*offset += len; *offset += len;
@ -45,29 +33,28 @@ 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();
let file_size = self.dentry.vnode().inode().metadata().size;
if self.status_flags.lock().contains(StatusFlags::O_APPEND) { if self.status_flags.lock().contains(StatusFlags::O_APPEND) {
*offset = file_size; *offset = self.dentry.vnode().len();
} }
let len = if self.status_flags.lock().contains(StatusFlags::O_DIRECT) { let len = if self.status_flags.lock().contains(StatusFlags::O_DIRECT) {
self.dentry.vnode().inode().write_at(*offset, buf)? self.dentry.vnode().write_direct_at(*offset, buf)?
} else { } else {
let pages = self.dentry.vnode().pages(); self.dentry.vnode().write_at(*offset, buf)?
let should_expand_size = *offset + buf.len() > file_size;
if should_expand_size {
pages.resize(*offset + buf.len())?;
}
pages.write_bytes(*offset, buf)?;
if should_expand_size {
self.dentry.vnode().inode().resize(*offset + buf.len())?;
}
buf.len()
}; };
*offset += len; *offset += len;
Ok(len) Ok(len)
} }
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
let len = if self.status_flags.lock().contains(StatusFlags::O_DIRECT) {
self.dentry.vnode().read_direct_to_end(buf)?
} else {
self.dentry.vnode().read_to_end(buf)?
};
Ok(len)
}
pub fn seek(&self, pos: SeekFrom) -> Result<usize> { pub fn seek(&self, pos: SeekFrom) -> Result<usize> {
let mut offset = self.offset.lock(); let mut offset = self.offset.lock();
let new_offset: isize = match pos { let new_offset: isize = match pos {
@ -78,7 +65,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().inode().metadata().size as isize; let file_size = self.dentry.vnode().len() as isize;
assert!(file_size >= 0); assert!(file_size >= 0);
file_size file_size
.checked_add(off) .checked_add(off)
@ -125,7 +112,7 @@ impl InodeHandle_ {
pub fn readdir(&self, writer: &mut dyn DirentWriter) -> Result<usize> { pub fn readdir(&self, writer: &mut dyn DirentWriter) -> Result<usize> {
let mut offset = self.offset.lock(); let mut offset = self.offset.lock();
let mut dir_writer_ctx = DirentWriterContext::new(*offset, writer); let mut dir_writer_ctx = DirentWriterContext::new(*offset, writer);
let written_size = self.dentry.vnode().inode().readdir(&mut dir_writer_ctx)?; let written_size = self.dentry.vnode().readdir(&mut dir_writer_ctx)?;
*offset = dir_writer_ctx.pos(); *offset = dir_writer_ctx.pos();
Ok(written_size) Ok(written_size)
} }

View File

@ -10,6 +10,11 @@ impl<R: TRights> InodeHandle<R> {
self.0.read(buf) self.0.read(buf)
} }
#[require(R > Read)]
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
self.0.read_to_end(buf)
}
#[require(R > Write)] #[require(R > Write)]
pub fn write(&self, buf: &[u8]) -> Result<usize> { pub fn write(&self, buf: &[u8]) -> Result<usize> {
self.0.write(buf) self.0.write(buf)

View File

@ -70,7 +70,7 @@ impl FileHandle {
pub fn metadata(&self) -> Metadata { pub fn metadata(&self) -> Metadata {
match &self.inner { match &self.inner {
Inner::File(file) => file.metadata(), Inner::File(file) => file.metadata(),
Inner::Inode(inode_handle) => inode_handle.dentry().vnode().inode().metadata(), Inner::Inode(inode_handle) => inode_handle.dentry().vnode().metadata(),
} }
} }

View File

@ -11,7 +11,14 @@ use super::utils::{
}; };
lazy_static! { lazy_static! {
static ref ROOT_FS: Arc<dyn FileSystem> = RamFS::new(); static ref RAM_FS: Arc<dyn FileSystem> = RamFS::new();
static ref ROOT_DENTRY: Arc<Dentry> = {
fn init() -> Result<Arc<Dentry>> {
let root_vnode = Vnode::new(RAM_FS.root_inode())?;
Ok(Dentry::new_root(root_vnode))
}
init().unwrap()
};
} }
pub struct FsResolver { pub struct FsResolver {
@ -29,15 +36,11 @@ impl Clone for FsResolver {
} }
impl FsResolver { impl FsResolver {
pub fn new() -> Result<Self> { pub fn new() -> Self {
let root = { Self {
let root_vnode = Vnode::new(ROOT_FS.root_inode())?; root: ROOT_DENTRY.clone(),
Dentry::new_root(root_vnode) cwd: ROOT_DENTRY.clone(),
}; }
Ok(Self {
root: root.clone(),
cwd: root,
})
} }
/// Get the root directory /// Get the root directory
@ -65,8 +68,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 inode = dentry.vnode().inode(); let vnode = dentry.vnode();
if inode.metadata().type_ == InodeType::SymLink if vnode.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");
@ -77,7 +80,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)
&& inode.metadata().type_ != InodeType::Dir && vnode.inode_type() != InodeType::Dir
{ {
return_errno_with_message!( return_errno_with_message!(
Errno::ENOTDIR, Errno::ENOTDIR,
@ -98,7 +101,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().metadata().mode.is_writable() { if !dir_dentry.vnode().inode_mode().is_writable() {
return_errno_with_message!(Errno::EPERM, "file cannot be created"); return_errno_with_message!(Errno::EPERM, "file cannot be created");
} }
let new_dentry = dir_dentry.create(&file_name, InodeType::File, inode_mode)?; let new_dentry = dir_dentry.create(&file_name, InodeType::File, inode_mode)?;
@ -181,7 +184,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().metadata().type_; let next_type = next_dentry.vnode().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.
@ -190,7 +193,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().inode().read_link()?; let mut tmp_link_path = next_dentry.vnode().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");
} }
@ -279,9 +282,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().metadata().type_ == InodeType::SymLink => { Ok(dentry) if dentry.vnode().inode_type() == InodeType::SymLink => {
let link = { let link = {
let mut link = dentry.vnode().inode().read_link()?; let mut link = dentry.vnode().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

@ -301,12 +301,12 @@ impl Inode for RamInode {
return_errno_with_message!(Errno::EOPNOTSUPP, "direct write is not supported"); return_errno_with_message!(Errno::EOPNOTSUPP, "direct write is not supported");
} }
fn resize(&self, new_size: usize) -> Result<()> { fn len(&self) -> usize {
if self.0.read().metadata.type_ != InodeType::File { self.0.read().metadata.size
return_errno_with_message!(Errno::EISDIR, "self is not file"); }
}
fn resize(&self, new_size: usize) {
self.0.write().metadata.size = new_size; self.0.write().metadata.size = new_size;
Ok(())
} }
fn mknod(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> { fn mknod(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> {

View File

@ -2,7 +2,7 @@ use crate::prelude::*;
use alloc::string::String; use alloc::string::String;
use spin::RwLockWriteGuard; use spin::RwLockWriteGuard;
use super::{InodeMode, InodeType, Vnode, NAME_MAX}; use super::{InodeMode, InodeType, Metadata, Vnode, NAME_MAX};
pub struct Dentry { pub struct Dentry {
inner: RwLock<Dentry_>, inner: RwLock<Dentry_>,
@ -68,12 +68,12 @@ impl Dentry {
self.inner.write().parent = Some(Arc::downgrade(parent)); self.inner.write().parent = Some(Arc::downgrade(parent));
} }
pub fn vnode(&self) -> &Vnode { pub(in crate::fs) fn vnode(&self) -> &Vnode {
&self.vnode &self.vnode
} }
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().metadata().type_ != InodeType::Dir { if self.vnode.inode_type() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
let mut inner = self.inner.write(); let mut inner = self.inner.write();
@ -81,7 +81,7 @@ impl Dentry {
return_errno!(Errno::EEXIST); return_errno!(Errno::EEXIST);
} }
let child = { let child = {
let vnode = Vnode::new(self.vnode.inode().mknod(name, type_, mode)?)?; let vnode = self.vnode.mknod(name, type_, mode)?;
Dentry::new(name, vnode, Some(inner.this.clone())) Dentry::new(name, vnode, Some(inner.this.clone()))
}; };
inner.children.insert(String::from(name), child.clone()); inner.children.insert(String::from(name), child.clone());
@ -89,7 +89,7 @@ impl Dentry {
} }
pub fn lookup(&self, name: &str) -> Result<Arc<Self>> { pub fn lookup(&self, name: &str) -> Result<Arc<Self>> {
if self.vnode.inode().metadata().type_ != InodeType::Dir { if self.vnode.inode_type() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
if name.len() > NAME_MAX { if name.len() > NAME_MAX {
@ -104,7 +104,7 @@ impl Dentry {
if let Some(dentry) = inner.children.get(name) { if let Some(dentry) = inner.children.get(name) {
dentry.clone() dentry.clone()
} else { } else {
let vnode = Vnode::new(self.vnode.inode().lookup(name)?)?; let vnode = self.vnode.lookup(name)?;
let dentry = Dentry::new(name, vnode, Some(inner.this.clone())); let dentry = Dentry::new(name, vnode, Some(inner.this.clone()));
inner.children.insert(String::from(name), dentry.clone()); inner.children.insert(String::from(name), dentry.clone());
dentry dentry
@ -115,7 +115,7 @@ impl Dentry {
} }
pub fn link(&self, old: &Arc<Self>, name: &str) -> Result<()> { pub fn link(&self, old: &Arc<Self>, name: &str) -> Result<()> {
if self.vnode.inode().metadata().type_ != InodeType::Dir { if self.vnode.inode_type() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
let mut inner = self.inner.write(); let mut inner = self.inner.write();
@ -123,38 +123,51 @@ impl Dentry {
return_errno!(Errno::EEXIST); return_errno!(Errno::EEXIST);
} }
let target_vnode = old.vnode(); let target_vnode = old.vnode();
self.vnode.inode().link(target_vnode.inode(), name)?; self.vnode.link(target_vnode, name)?;
let new_dentry = Self::new(name, target_vnode.clone(), Some(inner.this.clone())); let new_dentry = Self::new(name, target_vnode.clone(), Some(inner.this.clone()));
inner.children.insert(String::from(name), new_dentry); inner.children.insert(String::from(name), new_dentry);
Ok(()) Ok(())
} }
pub fn unlink(&self, name: &str) -> Result<()> { pub fn unlink(&self, name: &str) -> Result<()> {
if self.vnode.inode().metadata().type_ != InodeType::Dir { if self.vnode.inode_type() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
let mut inner = self.inner.write(); let mut inner = self.inner.write();
self.vnode.inode().unlink(name)?; self.vnode.unlink(name)?;
inner.children.remove(name); inner.children.remove(name);
Ok(()) Ok(())
} }
pub fn rmdir(&self, name: &str) -> Result<()> { pub fn rmdir(&self, name: &str) -> Result<()> {
if self.vnode.inode().metadata().type_ != InodeType::Dir { if self.vnode.inode_type() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
let mut inner = self.inner.write(); let mut inner = self.inner.write();
self.vnode.inode().rmdir(name)?; self.vnode.rmdir(name)?;
inner.children.remove(name); inner.children.remove(name);
Ok(()) Ok(())
} }
pub fn read_link(&self) -> Result<String> {
if self.vnode.inode_type() != InodeType::SymLink {
return_errno!(Errno::EINVAL);
}
self.vnode.read_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)
}
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().metadata().type_ != InodeType::Dir if self.vnode.inode_type() != InodeType::Dir || new_dir.vnode.inode_type() != InodeType::Dir
|| new_dir.vnode.inode().metadata().type_ != InodeType::Dir
{ {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
@ -168,12 +181,10 @@ impl Dentry {
let dentry = if let Some(dentry) = inner.children.get(old_name) { let dentry = if let Some(dentry) = inner.children.get(old_name) {
dentry.clone() dentry.clone()
} else { } else {
let vnode = Vnode::new(self.vnode.inode().lookup(old_name)?)?; let vnode = self.vnode.lookup(old_name)?;
Dentry::new(old_name, vnode, Some(inner.this.clone())) Dentry::new(old_name, vnode, Some(inner.this.clone()))
}; };
self.vnode self.vnode.rename(old_name, &self.vnode, new_name)?;
.inode()
.rename(old_name, self.vnode.inode(), new_name)?;
inner.children.remove(old_name); inner.children.remove(old_name);
dentry.set_name(new_name); dentry.set_name(new_name);
inner.children.insert(String::from(new_name), dentry); inner.children.insert(String::from(new_name), dentry);
@ -183,12 +194,10 @@ impl Dentry {
let dentry = if let Some(dentry) = self_inner.children.get(old_name) { let dentry = if let Some(dentry) = self_inner.children.get(old_name) {
dentry.clone() dentry.clone()
} else { } else {
let vnode = Vnode::new(self.vnode.inode().lookup(old_name)?)?; let vnode = self.vnode.lookup(old_name)?;
Dentry::new(old_name, vnode, Some(self_inner.this.clone())) Dentry::new(old_name, vnode, Some(self_inner.this.clone()))
}; };
self.vnode self.vnode.rename(old_name, &new_dir.vnode, new_name)?;
.inode()
.rename(old_name, new_dir.vnode.inode(), new_name)?;
self_inner.children.remove(old_name); self_inner.children.remove(old_name);
dentry.set_name(new_name); dentry.set_name(new_name);
dentry.set_parent(&new_dir.this()); dentry.set_parent(&new_dir.this());
@ -199,6 +208,22 @@ impl Dentry {
Ok(()) Ok(())
} }
pub fn inode_metadata(&self) -> Metadata {
self.vnode.metadata()
}
pub fn inode_type(&self) -> InodeType {
self.vnode.inode_type()
}
pub fn inode_mode(&self) -> InodeMode {
self.vnode.inode_mode()
}
pub fn inode_len(&self) -> usize {
self.vnode.len()
}
pub fn abs_path(&self) -> String { pub fn abs_path(&self) -> String {
let mut path = self.name(); let mut path = self.name();
let mut dentry = self.this(); let mut dentry = self.this();

View File

@ -159,7 +159,9 @@ pub struct Timespec {
} }
pub trait Inode: Any + Sync + Send { pub trait Inode: Any + Sync + Send {
fn resize(&self, new_size: usize) -> Result<()>; fn len(&self) -> usize;
fn resize(&self, new_size: usize);
fn metadata(&self) -> Metadata; fn metadata(&self) -> Metadata;

View File

@ -1,31 +1,186 @@
use crate::prelude::*; use crate::prelude::*;
use super::{Inode, PageCacheManager}; use super::{DirentWriterContext, Inode, InodeMode, InodeType, Metadata, PageCacheManager};
use crate::rights::Rights; use crate::rights::Rights;
use crate::vm::vmo::{Vmo, VmoFlags, VmoOptions}; use crate::vm::vmo::{Vmo, VmoFlags, VmoOptions};
use alloc::string::String;
use jinux_frame::vm::VmIo;
/// VFS-level representation of an inode /// VFS-level representation of an inode
#[derive(Clone)] #[derive(Clone)]
pub struct Vnode { 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>, inode: Arc<dyn Inode>,
pages: Vmo, page_cache: Vmo,
page_cache_manager: Arc<PageCacheManager>,
} }
impl Vnode { impl Vnode {
pub fn new(inode: Arc<dyn Inode>) -> Result<Self> { pub fn new(inode: Arc<dyn Inode>) -> Result<Self> {
let page_cache_manager = Arc::new(PageCacheManager::new(&Arc::downgrade(&inode))); let page_cache_manager = Arc::new(PageCacheManager::new(&Arc::downgrade(&inode)));
let pages = VmoOptions::<Rights>::new(inode.metadata().size) let page_cache = VmoOptions::<Rights>::new(inode.len())
.flags(VmoFlags::RESIZABLE) .flags(VmoFlags::RESIZABLE)
.pager(page_cache_manager) .pager(page_cache_manager.clone())
.alloc()?; .alloc()?;
Ok(Self { inode, pages }) Ok(Self {
inner: Arc::new(RwLock::new(Inner {
inode,
page_cache,
page_cache_manager,
})),
})
} }
pub fn pages(&self) -> &Vmo { pub fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
&self.pages let type_ = self.inode_type();
if type_ != InodeType::File && type_ != InodeType::Socket {
return_errno!(Errno::EINVAL);
}
let inner = self.inner.write();
let file_len = inner.inode.len();
let should_expand_len = offset + buf.len() > file_len;
if should_expand_len {
inner.page_cache.resize(offset + buf.len())?;
}
inner.page_cache.write_bytes(offset, buf)?;
if should_expand_len {
inner.inode.resize(offset + buf.len());
}
Ok(buf.len())
} }
pub fn inode(&self) -> &Arc<dyn Inode> { pub fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
&self.inode let type_ = self.inode_type();
if type_ != InodeType::File && type_ != InodeType::Socket {
return_errno!(Errno::EINVAL);
}
let inner = self.inner.write();
let file_len = inner.inode.len();
if offset + buf.len() > file_len {
inner.page_cache.resize(offset + buf.len())?;
}
// Flush the dirty pages if necessary.
// inner.page_cache_manager.flush(offset..offset + buf.len())?;
// TODO: Update the related page state to invalid to reload the content from inode
// for upcoming read or write.
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_ != InodeType::File && type_ != InodeType::Socket {
return_errno!(Errno::EISDIR);
}
let inner = self.inner.read();
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)
};
inner.page_cache.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_ != InodeType::File && type_ != InodeType::Socket {
return_errno!(Errno::EISDIR);
}
let inner = self.inner.read();
// Flush the dirty pages if necessary.
// inner.page_cache_manager.flush(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_ != InodeType::File && type_ != InodeType::Socket {
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);
}
inner.page_cache.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_ != InodeType::File && type_ != InodeType::Socket {
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);
}
// Flush the dirty pages if necessary.
// inner.page_cache_manager.flush(..file_size)?;
let len = inner.inode.read_at(0, &mut buf[..file_len])?;
Ok(len)
}
pub fn mknod(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Self> {
let inode = self.inner.read().inode.mknod(name, type_, mode)?;
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(&self, ctx: &mut DirentWriterContext) -> Result<usize> {
self.inner.read().inode.readdir(ctx)
}
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()
} }
} }

View File

@ -196,7 +196,7 @@ impl Process {
let pid = thread.tid(); let pid = thread.tid();
let user_vm = UserVm::new(); let user_vm = UserVm::new();
let file_table = FileTable::new_with_stdio(); let file_table = FileTable::new_with_stdio();
let fs = FsResolver::new().unwrap(); let fs = FsResolver::new();
let sig_dispositions = SigDispositions::new(); let sig_dispositions = SigDispositions::new();
let process = Process::new( let process = Process::new(
@ -231,7 +231,7 @@ impl Process {
let thread = Thread::new_kernel_thread(task_fn, weak_process_ref.clone()); let thread = Thread::new_kernel_thread(task_fn, weak_process_ref.clone());
let pid = thread.tid(); let pid = thread.tid();
let file_table = FileTable::new(); let file_table = FileTable::new();
let fs = FsResolver::new().unwrap(); let fs = FsResolver::new();
let sig_dispositions = SigDispositions::new(); let sig_dispositions = SigDispositions::new();
// FIXME: kernel process does not need root vmar // FIXME: kernel process does not need root vmar
let root_vmar = Vmar::<Full>::new_root().unwrap(); let root_vmar = Vmar::<Full>::new_root().unwrap();

View File

@ -44,7 +44,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.vnode().inode().read_link()?; let linkpath = dentry.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

@ -42,9 +42,7 @@ pub fn sys_renameat(
if new_pathname.is_empty() { if new_pathname.is_empty() {
return_errno_with_message!(Errno::ENOENT, "newpath is empty"); return_errno_with_message!(Errno::ENOENT, "newpath is empty");
} }
if new_pathname.ends_with("/") if new_pathname.ends_with("/") && old_dentry.inode_type() != InodeType::Dir {
&& old_dentry.vnode().inode().metadata().type_ != InodeType::Dir
{
return_errno_with_message!(Errno::ENOTDIR, "oldpath is not dir"); return_errno_with_message!(Errno::ENOTDIR, "oldpath is not dir");
} }
let new_fs_path = FsPath::new(new_dirfd, new_pathname.as_ref().trim_end_matches('/'))?; let new_fs_path = FsPath::new(new_dirfd, new_pathname.as_ref().trim_end_matches('/'))?;

View File

@ -65,7 +65,7 @@ pub fn sys_fstatat(
fs.lookup(&fs_path)? fs.lookup(&fs_path)?
} }
}; };
let stat = Stat::from(dentry.vnode().inode().metadata()); let stat = Stat::from(dentry.inode_metadata());
write_val_to_user(stat_buf_ptr, &stat)?; write_val_to_user(stat_buf_ptr, &stat)?;
Ok(SyscallReturn::Return(0)) Ok(SyscallReturn::Return(0))
} }

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.vnode().inode().write_link(&target)?; new_dentry.write_link(&target)?;
Ok(SyscallReturn::Return(0)) Ok(SyscallReturn::Return(0))
} }