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,
status_flags: StatusFlags,
) -> Result<Self> {
let inode_info = dentry.vnode().inode().metadata();
if access_mode.is_readable() && !inode_info.mode.is_readable() {
let vnode = dentry.vnode();
if access_mode.is_readable() && !vnode.inode_mode().is_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");
}
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");
}
let inner = Arc::new(InodeHandle_ {
@ -43,6 +43,13 @@ impl InodeHandle<Rights> {
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> {
if !self.1.contains(Rights::WRITE) {
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::rights::Rights;
use alloc::sync::Arc;
use jinux_frame::vm::VmIo;
pub struct InodeHandle<R = Rights>(Arc<InodeHandle_>, R);
@ -23,20 +21,10 @@ struct InodeHandle_ {
impl InodeHandle_ {
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
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) {
self.dentry
.vnode()
.inode()
.read_at(start, &mut buf[0..end - start])?
self.dentry.vnode().read_direct_at(*offset, buf)?
} else {
self.dentry
.vnode()
.pages()
.read_bytes(start, &mut buf[0..end - start])?;
end - start
self.dentry.vnode().read_at(*offset, buf)?
};
*offset += len;
@ -45,29 +33,28 @@ impl InodeHandle_ {
pub fn write(&self, buf: &[u8]) -> Result<usize> {
let mut offset = self.offset.lock();
let file_size = self.dentry.vnode().inode().metadata().size;
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) {
self.dentry.vnode().inode().write_at(*offset, buf)?
self.dentry.vnode().write_direct_at(*offset, buf)?
} else {
let pages = self.dentry.vnode().pages();
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()
self.dentry.vnode().write_at(*offset, buf)?
};
*offset += 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> {
let mut offset = self.offset.lock();
let new_offset: isize = match pos {
@ -78,7 +65,7 @@ impl InodeHandle_ {
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);
file_size
.checked_add(off)
@ -125,7 +112,7 @@ impl InodeHandle_ {
pub fn readdir(&self, writer: &mut dyn DirentWriter) -> Result<usize> {
let mut offset = self.offset.lock();
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();
Ok(written_size)
}

View File

@ -10,6 +10,11 @@ impl<R: TRights> InodeHandle<R> {
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)]
pub fn write(&self, buf: &[u8]) -> Result<usize> {
self.0.write(buf)

View File

@ -70,7 +70,7 @@ impl FileHandle {
pub fn metadata(&self) -> Metadata {
match &self.inner {
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! {
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 {
@ -29,15 +36,11 @@ impl Clone for FsResolver {
}
impl FsResolver {
pub fn new() -> Result<Self> {
let root = {
let root_vnode = Vnode::new(ROOT_FS.root_inode())?;
Dentry::new_root(root_vnode)
};
Ok(Self {
root: root.clone(),
cwd: root,
})
pub fn new() -> Self {
Self {
root: ROOT_DENTRY.clone(),
cwd: ROOT_DENTRY.clone(),
}
}
/// Get the root directory
@ -65,8 +68,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 inode = dentry.vnode().inode();
if inode.metadata().type_ == InodeType::SymLink
let vnode = dentry.vnode();
if vnode.inode_type() == InodeType::SymLink
&& !status_flags.contains(StatusFlags::O_PATH)
{
return_errno_with_message!(Errno::ELOOP, "file is a symlink");
@ -77,7 +80,7 @@ impl FsResolver {
return_errno_with_message!(Errno::EEXIST, "file exists");
}
if creation_flags.contains(CreationFlags::O_DIRECTORY)
&& inode.metadata().type_ != InodeType::Dir
&& vnode.inode_type() != InodeType::Dir
{
return_errno_with_message!(
Errno::ENOTDIR,
@ -98,7 +101,7 @@ impl FsResolver {
if file_name.ends_with("/") {
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");
}
let new_dentry = dir_dentry.create(&file_name, InodeType::File, inode_mode)?;
@ -181,7 +184,7 @@ impl FsResolver {
// Iterate next dentry
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();
// 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");
}
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() {
return_errno_with_message!(Errno::ENOENT, "empty symlink");
}
@ -279,9 +282,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().metadata().type_ == InodeType::SymLink => {
Ok(dentry) if dentry.vnode().inode_type() == InodeType::SymLink => {
let link = {
let mut link = dentry.vnode().inode().read_link()?;
let mut link = dentry.vnode().read_link()?;
if link.is_empty() {
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");
}
fn resize(&self, new_size: usize) -> Result<()> {
if self.0.read().metadata.type_ != InodeType::File {
return_errno_with_message!(Errno::EISDIR, "self is not file");
fn len(&self) -> usize {
self.0.read().metadata.size
}
fn resize(&self, new_size: usize) {
self.0.write().metadata.size = new_size;
Ok(())
}
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 spin::RwLockWriteGuard;
use super::{InodeMode, InodeType, Vnode, NAME_MAX};
use super::{InodeMode, InodeType, Metadata, Vnode, NAME_MAX};
pub struct Dentry {
inner: RwLock<Dentry_>,
@ -68,12 +68,12 @@ impl Dentry {
self.inner.write().parent = Some(Arc::downgrade(parent));
}
pub fn vnode(&self) -> &Vnode {
pub(in crate::fs) fn vnode(&self) -> &Vnode {
&self.vnode
}
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);
}
let mut inner = self.inner.write();
@ -81,7 +81,7 @@ impl Dentry {
return_errno!(Errno::EEXIST);
}
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()))
};
inner.children.insert(String::from(name), child.clone());
@ -89,7 +89,7 @@ impl Dentry {
}
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);
}
if name.len() > NAME_MAX {
@ -104,7 +104,7 @@ impl Dentry {
if let Some(dentry) = inner.children.get(name) {
dentry.clone()
} 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()));
inner.children.insert(String::from(name), dentry.clone());
dentry
@ -115,7 +115,7 @@ impl Dentry {
}
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);
}
let mut inner = self.inner.write();
@ -123,38 +123,51 @@ impl Dentry {
return_errno!(Errno::EEXIST);
}
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()));
inner.children.insert(String::from(name), new_dentry);
Ok(())
}
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);
}
let mut inner = self.inner.write();
self.vnode.inode().unlink(name)?;
self.vnode.unlink(name)?;
inner.children.remove(name);
Ok(())
}
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);
}
let mut inner = self.inner.write();
self.vnode.inode().rmdir(name)?;
self.vnode.rmdir(name)?;
inner.children.remove(name);
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<()> {
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().metadata().type_ != InodeType::Dir
|| new_dir.vnode.inode().metadata().type_ != InodeType::Dir
if self.vnode.inode_type() != InodeType::Dir || new_dir.vnode.inode_type() != InodeType::Dir
{
return_errno!(Errno::ENOTDIR);
}
@ -168,12 +181,10 @@ impl Dentry {
let dentry = if let Some(dentry) = inner.children.get(old_name) {
dentry.clone()
} 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()))
};
self.vnode
.inode()
.rename(old_name, self.vnode.inode(), new_name)?;
self.vnode.rename(old_name, &self.vnode, new_name)?;
inner.children.remove(old_name);
dentry.set_name(new_name);
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) {
dentry.clone()
} 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()))
};
self.vnode
.inode()
.rename(old_name, new_dir.vnode.inode(), new_name)?;
self.vnode.rename(old_name, &new_dir.vnode, new_name)?;
self_inner.children.remove(old_name);
dentry.set_name(new_name);
dentry.set_parent(&new_dir.this());
@ -199,6 +208,22 @@ impl Dentry {
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 {
let mut path = self.name();
let mut dentry = self.this();

View File

@ -159,7 +159,9 @@ pub struct Timespec {
}
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;

View File

@ -1,31 +1,186 @@
use crate::prelude::*;
use super::{Inode, PageCacheManager};
use super::{DirentWriterContext, Inode, InodeMode, InodeType, Metadata, PageCacheManager};
use crate::rights::Rights;
use crate::vm::vmo::{Vmo, VmoFlags, VmoOptions};
use alloc::string::String;
use jinux_frame::vm::VmIo;
/// 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>,
pages: Vmo,
page_cache: Vmo,
page_cache_manager: Arc<PageCacheManager>,
}
impl Vnode {
pub fn new(inode: Arc<dyn Inode>) -> Result<Self> {
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)
.pager(page_cache_manager)
.pager(page_cache_manager.clone())
.alloc()?;
Ok(Self { inode, pages })
Ok(Self {
inner: Arc::new(RwLock::new(Inner {
inode,
page_cache,
page_cache_manager,
})),
})
}
pub fn pages(&self) -> &Vmo {
&self.pages
pub fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
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> {
&self.inode
pub fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
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 user_vm = UserVm::new();
let file_table = FileTable::new_with_stdio();
let fs = FsResolver::new().unwrap();
let fs = FsResolver::new();
let sig_dispositions = SigDispositions::new();
let process = Process::new(
@ -231,7 +231,7 @@ impl Process {
let thread = Thread::new_kernel_thread(task_fn, weak_process_ref.clone());
let pid = thread.tid();
let file_table = FileTable::new();
let fs = FsResolver::new().unwrap();
let fs = FsResolver::new();
let sig_dispositions = SigDispositions::new();
// FIXME: kernel process does not need root vmar
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())?;
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 write_len = bytes.len().min(usr_buf_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() {
return_errno_with_message!(Errno::ENOENT, "newpath is empty");
}
if new_pathname.ends_with("/")
&& old_dentry.vnode().inode().metadata().type_ != InodeType::Dir
{
if new_pathname.ends_with("/") && old_dentry.inode_type() != InodeType::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('/'))?;

View File

@ -65,7 +65,7 @@ pub fn sys_fstatat(
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)?;
Ok(SyscallReturn::Return(0))
}

View File

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