From 807686ac6db120752c9c882f9bc9c81c51505a2d Mon Sep 17 00:00:00 2001 From: SuchAFuriousDeath <48620541+SuchAFuriousDeath@users.noreply.github.com> Date: Sun, 31 Mar 2024 14:47:34 +0200 Subject: [PATCH] Implements seek and read on vfile (#781) --- src/kernel/src/fs/dev/vnode.rs | 21 ++++++++++++-- src/kernel/src/fs/file.rs | 39 +++++++++++++++++++++---- src/kernel/src/fs/host/file.rs | 11 +++++++ src/kernel/src/fs/host/vnode.rs | 29 ++++++++++++++++++- src/kernel/src/fs/mount.rs | 2 +- src/kernel/src/fs/null/vnode.rs | 43 +++++++++++++++++++++++++++- src/kernel/src/fs/tmp/node.rs | 20 ++++++++++++- src/kernel/src/fs/uio.rs | 21 ++++++++++++++ src/kernel/src/fs/vnode.rs | 46 ++++++++++++++++++++++++------ src/kernel/src/main.rs | 2 +- src/kernel/src/process/filedesc.rs | 1 - src/kernel/src/shm/mod.rs | 14 ++++----- src/kernel/src/signal/set.rs | 2 +- 13 files changed, 221 insertions(+), 30 deletions(-) diff --git a/src/kernel/src/fs/dev/vnode.rs b/src/kernel/src/fs/dev/vnode.rs index 8680229b5..97de8aed1 100644 --- a/src/kernel/src/fs/dev/vnode.rs +++ b/src/kernel/src/fs/dev/vnode.rs @@ -2,8 +2,7 @@ use super::dirent::Dirent; use super::{AllocVnodeError, DevFs}; use crate::errno::{Errno, EIO, ENOENT, ENOTDIR, ENXIO}; use crate::fs::{ - check_access, Access, IoCmd, OpenFlags, RevokeFlags, VFileType, Vnode, VnodeAttrs, VnodeItem, - VnodeType, + check_access, Access, IoCmd, RevokeFlags, Uio, UioMut, Vnode, VnodeAttrs, VnodeType, }; use crate::process::VThread; use macros::Errno; @@ -167,6 +166,24 @@ impl crate::fs::VnodeBackend for VnodeBackend { // TODO: Implement this. todo!() } + + fn read( + &self, + #[allow(unused_variables)] vn: &Arc, + #[allow(unused_variables)] buf: &mut UioMut, + #[allow(unused_variables)] td: Option<&VThread>, + ) -> Result> { + todo!() + } + + fn write( + &self, + #[allow(unused_variables)] vn: &Arc, + #[allow(unused_variables)] buf: &mut Uio, + #[allow(unused_variables)] td: Option<&VThread>, + ) -> Result> { + todo!() + } } /// Represents an error when [`lookup()`] is failed. diff --git a/src/kernel/src/fs/file.rs b/src/kernel/src/fs/file.rs index 2fa3b97d8..b5db7ca8e 100644 --- a/src/kernel/src/fs/file.rs +++ b/src/kernel/src/fs/file.rs @@ -2,7 +2,7 @@ use super::{CharacterDevice, IoCmd, Offset, Stat, TruncateLength, Uio, UioMut, V use crate::dmem::BlockPool; use crate::errno::Errno; use crate::errno::{EINVAL, ENOTTY, ENXIO, EOPNOTSUPP}; -use crate::fs::PollEvents; +use crate::fs::{IoVec, PollEvents}; use crate::kqueue::KernelQueue; use crate::net::Socket; use crate::process::VThread; @@ -19,6 +19,7 @@ use thiserror::Error; pub struct VFile { ty: VFileType, // f_type flags: VFileFlags, // f_flag + offset: i64, // f_offset } impl VFile { @@ -26,6 +27,7 @@ impl VFile { Self { ty, flags: VFileFlags::empty(), + offset: 0, } } @@ -90,7 +92,7 @@ impl VFile { fn read(&self, buf: &mut UioMut, td: Option<&VThread>) -> Result> { match &self.ty { - VFileType::Vnode(vn) => vn.read(self, buf, td), + VFileType::Vnode(vn) => FileBackend::read(vn, self, buf, td), VFileType::Socket(so) | VFileType::IpcSocket(so) => so.read(self, buf, td), VFileType::KernelQueue(kq) => kq.read(self, buf, td), VFileType::SharedMemory(shm) => shm.read(self, buf, td), @@ -101,7 +103,7 @@ impl VFile { fn write(&self, buf: &mut Uio, td: Option<&VThread>) -> Result> { match &self.ty { - VFileType::Vnode(vn) => vn.write(self, buf, td), + VFileType::Vnode(vn) => FileBackend::write(vn, self, buf, td), VFileType::Socket(so) | VFileType::IpcSocket(so) => so.write(self, buf, td), VFileType::KernelQueue(kq) => kq.write(self, buf, td), VFileType::SharedMemory(shm) => shm.write(self, buf, td), @@ -154,12 +156,39 @@ impl Seek for VFile { fn seek(&mut self, _pos: SeekFrom) -> std::io::Result { todo!() } + + fn rewind(&mut self) -> std::io::Result<()> { + self.offset = 0; + + Ok(()) + } + + fn stream_position(&mut self) -> std::io::Result { + if let Ok(offset) = self.offset.try_into() { + Ok(offset) + } else { + todo!() + } + } } impl Read for VFile { - #[allow(unused_variables)] // TODO: Remove when implementing. fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - todo!() + let ref mut iovec = IoVec::from_slice(buf); + + let mut uio = UioMut::from_single_vec(iovec); + + let Ok(read) = VFile::read(self, &mut uio, None) else { + todo!() + }; + + if let Ok(read) = TryInto::::try_into(read) { + self.offset += read; + } else { + todo!() + } + + Ok(read) } } diff --git a/src/kernel/src/fs/host/file.rs b/src/kernel/src/fs/host/file.rs index a4036db39..51250bf4e 100644 --- a/src/kernel/src/fs/host/file.rs +++ b/src/kernel/src/fs/host/file.rs @@ -1,3 +1,4 @@ +use crate::fs::UioMut; use std::collections::HashMap; use std::io::Error; use std::mem::zeroed; @@ -272,6 +273,16 @@ impl HostFile { } } + #[cfg(unix)] + pub(super) fn read(&self, buf: &mut UioMut) -> Result { + todo!() + } + + #[cfg(windows)] + pub(super) fn read(&self, buf: &mut UioMut) -> Result { + todo!() + } + #[cfg(unix)] fn stat(&self) -> Result { use libc::fstat; diff --git a/src/kernel/src/fs/host/vnode.rs b/src/kernel/src/fs/host/vnode.rs index 087d7b296..fcb956cc6 100644 --- a/src/kernel/src/fs/host/vnode.rs +++ b/src/kernel/src/fs/host/vnode.rs @@ -1,7 +1,7 @@ use super::file::HostFile; use super::{GetVnodeError, HostFs}; use crate::errno::{Errno, EEXIST, EIO, ENOENT, ENOTDIR}; -use crate::fs::{Access, IoCmd, Mode, OpenFlags, VFileType, Vnode, VnodeAttrs, VnodeType}; +use crate::fs::{Access, IoCmd, Mode, Uio, UioMut, Vnode, VnodeAttrs, VnodeType}; use crate::process::VThread; use crate::ucred::{Gid, Uid}; use macros::Errno; @@ -123,6 +123,26 @@ impl crate::fs::VnodeBackend for VnodeBackend { Ok(vn) } + + fn read( + &self, + _: &Arc, + buf: &mut UioMut, + _: Option<&VThread>, + ) -> Result> { + let read = self.file.read(buf).map_err(ReadError::ReadFailed)?; + + Ok(read) + } + + fn write( + &self, + #[allow(unused_variables)] vn: &Arc, + #[allow(unused_variables)] buf: &mut Uio, + #[allow(unused_variables)] td: Option<&VThread>, + ) -> Result> { + todo!() + } } /// Represents an error when [`getattr()`] fails. @@ -182,3 +202,10 @@ impl From for MkDirError { } } } + +#[derive(Debug, Error, Errno)] +enum ReadError { + #[error("read failed")] + #[errno(EIO)] + ReadFailed(#[source] std::io::Error), +} diff --git a/src/kernel/src/fs/mount.rs b/src/kernel/src/fs/mount.rs index aeb84f615..43167a435 100644 --- a/src/kernel/src/fs/mount.rs +++ b/src/kernel/src/fs/mount.rs @@ -10,7 +10,7 @@ use std::collections::HashMap; use std::convert::Infallible; use std::fmt::Formatter; use std::fmt::{Debug, Display, Error}; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use std::hint::unreachable_unchecked; use std::path::PathBuf; use std::sync::{Arc, Mutex, RwLock, RwLockWriteGuard}; diff --git a/src/kernel/src/fs/null/vnode.rs b/src/kernel/src/fs/null/vnode.rs index 5b1af1b80..68002203c 100644 --- a/src/kernel/src/fs/null/vnode.rs +++ b/src/kernel/src/fs/null/vnode.rs @@ -1,7 +1,8 @@ use crate::{ errno::{Errno, EISDIR, EROFS}, fs::{ - null::hash::NULL_HASHTABLE, perm::Access, Mount, MountFlags, Vnode, VnodeAttrs, VnodeType, + null::hash::NULL_HASHTABLE, perm::Access, Mount, MountFlags, Uio, UioMut, Vnode, + VnodeAttrs, VnodeType, }, process::VThread, }; @@ -89,6 +90,34 @@ impl crate::fs::VnodeBackend for VnodeBackend { Ok(vnode) } + + fn read( + &self, + _: &Arc, + buf: &mut UioMut, + td: Option<&VThread>, + ) -> Result> { + let read = self + .lower + .read(buf, td) + .map_err(ReadError::ReadFromLowerFailed)?; + + Ok(read) + } + + fn write( + &self, + _: &Arc, + buf: &mut Uio, + td: Option<&VThread>, + ) -> Result> { + let written = self + .lower + .write(buf, td) + .map_err(WriteError::WriteFromLowerFailed)?; + + Ok(written) + } } /// See `null_nodeget` on the PS4 for a reference. @@ -149,3 +178,15 @@ pub(super) enum OpenError { #[derive(Debug, Error, Errno)] pub(super) enum NodeGetError {} + +#[derive(Debug, Error, Errno)] +enum ReadError { + #[error("read from lower vnode failed")] + ReadFromLowerFailed(#[source] Box), +} + +#[derive(Debug, Error, Errno)] +enum WriteError { + #[error("write from lower vnode failed")] + WriteFromLowerFailed(#[source] Box), +} diff --git a/src/kernel/src/fs/tmp/node.rs b/src/kernel/src/fs/tmp/node.rs index 7f373a306..11fd4c96d 100644 --- a/src/kernel/src/fs/tmp/node.rs +++ b/src/kernel/src/fs/tmp/node.rs @@ -1,6 +1,6 @@ use super::{AllocVnodeError, TempFs}; use crate::errno::{Errno, ENOENT, ENOSPC}; -use crate::fs::{Access, OpenFlags, VFileType, Vnode, VnodeAttrs, VnodeType}; +use crate::fs::{Access, Uio, UioMut, Vnode, VnodeAttrs, VnodeType}; use crate::process::VThread; use gmtx::{Gutex, GutexGroup, GutexWriteGuard}; use macros::Errno; @@ -201,6 +201,24 @@ impl crate::fs::VnodeBackend for VnodeBackend { Ok(vnode) } + + fn read( + &self, + #[allow(unused_variables)] vn: &Arc, + #[allow(unused_variables)] buf: &mut UioMut, + #[allow(unused_variables)] td: Option<&VThread>, + ) -> Result> { + todo!() + } + + fn write( + &self, + #[allow(unused_variables)] vn: &Arc, + #[allow(unused_variables)] buf: &mut Uio, + #[allow(unused_variables)] td: Option<&VThread>, + ) -> Result> { + todo!() + } } /// Represents an error when [`Nodes::alloc()`] fails. diff --git a/src/kernel/src/fs/uio.rs b/src/kernel/src/fs/uio.rs index 634f5a4d9..e82512b28 100644 --- a/src/kernel/src/fs/uio.rs +++ b/src/kernel/src/fs/uio.rs @@ -34,6 +34,18 @@ impl<'a> IoVec<'a> { _phantom: std::marker::PhantomData, } } + + pub fn from_slice(slice: &'a mut [u8]) -> Self { + Self { + base: slice.as_ptr(), + len: slice.len(), + _phantom: std::marker::PhantomData, + } + } + + pub fn len(&self) -> usize { + self.len + } } pub struct Uio<'a> { @@ -84,6 +96,15 @@ impl<'a> UioMut<'a> { Ok(Self { vecs, bytes_left }) } + + pub fn from_single_vec(vec: &'a mut IoVec<'a>) -> Self { + let bytes_left = vec.len; + + Self { + vecs: std::slice::from_mut(vec), + bytes_left, + } + } } #[derive(Debug, Error, Errno)] diff --git a/src/kernel/src/fs/vnode.rs b/src/kernel/src/fs/vnode.rs index 211d5aaae..3db9ebbb4 100644 --- a/src/kernel/src/fs/vnode.rs +++ b/src/kernel/src/fs/vnode.rs @@ -1,6 +1,6 @@ use super::{ - unixify_access, Access, CharacterDevice, FileBackend, IoCmd, Mode, Mount, OpenFlags, - RevokeFlags, Stat, TruncateLength, Uio, UioMut, VFile, VFileType, + unixify_access, Access, CharacterDevice, FileBackend, IoCmd, Mode, Mount, RevokeFlags, Stat, + TruncateLength, Uio, UioMut, VFile, }; use crate::arnd; use crate::errno::{Errno, ENOTDIR, ENOTTY, EOPNOTSUPP, EPERM}; @@ -138,27 +138,41 @@ impl Vnode { pub fn revoke(self: &Arc, flags: RevokeFlags) -> Result<(), Box> { self.backend.revoke(self, flags) } + + pub fn read( + self: &Arc, + buf: &mut UioMut, + td: Option<&VThread>, + ) -> Result> { + self.backend.read(self, buf, td) + } + + pub fn write( + self: &Arc, + buf: &mut Uio, + td: Option<&VThread>, + ) -> Result> { + self.backend.write(self, buf, td) + } } impl FileBackend for Vnode { - #[allow(unused_variables)] // TODO: remove when implementing fn read( self: &Arc, - file: &VFile, + _: &VFile, buf: &mut UioMut, td: Option<&VThread>, ) -> Result> { - todo!() + self.backend.read(self, buf, td) } - #[allow(unused_variables)] // TODO: remove when implementing fn write( self: &Arc, - file: &VFile, + _: &VFile, buf: &mut Uio, td: Option<&VThread>, ) -> Result> { - todo!() + self.backend.write(self, buf, td) } #[allow(unused_variables)] // TODO: remove when implementing @@ -299,6 +313,22 @@ pub(super) trait VnodeBackend: Debug + Send + Sync + 'static { ) -> Result<(), Box> { panic!("vop_revoke called"); } + + /// An implementation of `vop_read`. + fn read( + &self, + #[allow(unused_variables)] vn: &Arc, + #[allow(unused_variables)] buf: &mut UioMut, + #[allow(unused_variables)] td: Option<&VThread>, + ) -> Result>; + + /// An implementation of `vop_write`. + fn write( + &self, + #[allow(unused_variables)] vn: &Arc, + #[allow(unused_variables)] buf: &mut Uio, + #[allow(unused_variables)] td: Option<&VThread>, + ) -> Result>; } /// An implementation of `vattr` struct. diff --git a/src/kernel/src/main.rs b/src/kernel/src/main.rs index c77164881..2cb935818 100644 --- a/src/kernel/src/main.rs +++ b/src/kernel/src/main.rs @@ -376,7 +376,7 @@ fn run() -> Result<(), KernelError> { ProcType::BigApp, 1, // See sys_budget_set on the PS4. root, - "QXuNNl0Zhn", + system_component, syscalls, )?; diff --git a/src/kernel/src/process/filedesc.rs b/src/kernel/src/process/filedesc.rs index 27ecdf2bb..d57675529 100644 --- a/src/kernel/src/process/filedesc.rs +++ b/src/kernel/src/process/filedesc.rs @@ -2,7 +2,6 @@ use crate::budget::BudgetType; use crate::errno::{Errno, EBADF}; use crate::fs::{VFile, VFileFlags, VFileType, Vnode}; use crate::kqueue::KernelQueue; -use bitflags::bitflags; use gmtx::{Gutex, GutexGroup}; use macros::Errno; use std::collections::VecDeque; diff --git a/src/kernel/src/shm/mod.rs b/src/kernel/src/shm/mod.rs index 3c5b3e756..21237f664 100644 --- a/src/kernel/src/shm/mod.rs +++ b/src/kernel/src/shm/mod.rs @@ -111,22 +111,20 @@ impl SharedMemory { } impl FileBackend for SharedMemory { - #[allow(unused_variables)] fn read( self: &Arc, - file: &VFile, - buf: &mut UioMut, - td: Option<&VThread>, + _: &VFile, + _: &mut UioMut, + _: Option<&VThread>, ) -> Result> { Err(Box::new(DefaultFileBackendError::OperationNotSupported)) } - #[allow(unused_variables)] fn write( self: &Arc, - file: &VFile, - buf: &mut Uio, - td: Option<&VThread>, + _: &VFile, + _: &mut Uio, + _: Option<&VThread>, ) -> Result> { Err(Box::new(DefaultFileBackendError::OperationNotSupported)) } diff --git a/src/kernel/src/signal/set.rs b/src/kernel/src/signal/set.rs index 0d52a2266..50c5d4034 100644 --- a/src/kernel/src/signal/set.rs +++ b/src/kernel/src/signal/set.rs @@ -33,7 +33,7 @@ impl SignalSet { /// An implementation of `_SIG_WORD`. fn word(s: Signal) -> usize { // This is safe because `Signal` is guaranteed to be non-negative. - unsafe { (Self::idx(s) >> 5).try_into().unwrap() } + (Self::idx(s) >> 5).try_into().unwrap() } /// An implementation of `_SIG_BIT`.