Add `InodeIo` to simplify `FileIo` and `Inode`
This commit is contained in:
parent
08dfe533c4
commit
24502ac3d4
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
fs::{
|
||||
device::{Device, DeviceType},
|
||||
inode_handle::FileIo,
|
||||
utils::StatusFlags,
|
||||
utils::{InodeIo, StatusFlags},
|
||||
},
|
||||
prelude::*,
|
||||
process::signal::{PollHandle, Pollable},
|
||||
|
|
@ -37,14 +37,34 @@ impl Pollable for Full {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileIo for Full {
|
||||
fn read(&self, writer: &mut VmWriter, _status_flags: StatusFlags) -> Result<usize> {
|
||||
impl InodeIo for Full {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
let len = writer.avail();
|
||||
writer.fill_zeros(len)?;
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
fn write(&self, _reader: &mut VmReader, _status_flags: StatusFlags) -> Result<usize> {
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_reader: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
return_errno_with_message!(Errno::ENOSPC, "no space left on /dev/full")
|
||||
}
|
||||
}
|
||||
|
||||
impl FileIo for Full {
|
||||
fn check_seekable(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_offset_aware(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
fs::{
|
||||
device::{Device, DeviceType},
|
||||
inode_handle::FileIo,
|
||||
utils::StatusFlags,
|
||||
utils::{InodeIo, StatusFlags},
|
||||
},
|
||||
prelude::*,
|
||||
process::signal::{PollHandle, Pollable},
|
||||
|
|
@ -37,14 +37,34 @@ impl Pollable for Null {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileIo for Null {
|
||||
fn read(&self, _writer: &mut VmWriter, _status_flags: StatusFlags) -> Result<usize> {
|
||||
impl InodeIo for Null {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_writer: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn write(&self, reader: &mut VmReader, _status_flags: StatusFlags) -> Result<usize> {
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
reader: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
let len = reader.remain();
|
||||
reader.skip(len);
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileIo for Null {
|
||||
fn check_seekable(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_offset_aware(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
events::IoEvents,
|
||||
fs::{
|
||||
inode_handle::FileIo,
|
||||
utils::{IoctlCmd, StatusFlags},
|
||||
utils::{InodeIo, IoctlCmd, StatusFlags},
|
||||
},
|
||||
prelude::*,
|
||||
process::signal::{PollHandle, Pollable},
|
||||
|
|
@ -54,14 +54,40 @@ impl Drop for PtySlaveFile {
|
|||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.0")]
|
||||
impl FileIo for PtySlaveFile {
|
||||
fn read(&self, writer: &mut VmWriter, status_flags: StatusFlags) -> Result<usize>;
|
||||
fn write(&self, reader: &mut VmReader, status_flags: StatusFlags) -> Result<usize>;
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32>;
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.0")]
|
||||
impl Pollable for PtySlaveFile {
|
||||
fn poll(&self, mask: IoEvents, poller: Option<&mut PollHandle>) -> IoEvents;
|
||||
}
|
||||
|
||||
impl InodeIo for PtySlaveFile {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
self.0.read(writer, status_flags)
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
reader: &mut VmReader,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
self.0.write(reader, status_flags)
|
||||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.0")]
|
||||
impl FileIo for PtySlaveFile {
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32>;
|
||||
|
||||
fn check_seekable(&self) -> Result<()> {
|
||||
return_errno_with_message!(Errno::ESPIPE, "the inode is a TTY");
|
||||
}
|
||||
|
||||
fn is_offset_aware(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use crate::{
|
|||
file_table::FdFlags,
|
||||
fs_resolver::FsPath,
|
||||
inode_handle::FileIo,
|
||||
utils::{mkmod, AccessMode, IoctlCmd, OpenArgs, StatusFlags},
|
||||
utils::{mkmod, AccessMode, InodeIo, IoctlCmd, OpenArgs, StatusFlags},
|
||||
},
|
||||
prelude::*,
|
||||
process::{
|
||||
|
|
@ -87,8 +87,13 @@ impl Pollable for PtyMaster {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileIo for PtyMaster {
|
||||
fn read(&self, writer: &mut VmWriter, status_flags: StatusFlags) -> Result<usize> {
|
||||
impl InodeIo for PtyMaster {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
// TODO: Add support for timeout.
|
||||
let mut buf = vec![0u8; writer.avail().min(IO_CAPACITY)];
|
||||
let is_nonblocking = status_flags.contains(StatusFlags::O_NONBLOCK);
|
||||
|
|
@ -107,7 +112,12 @@ impl FileIo for PtyMaster {
|
|||
Ok(read_len)
|
||||
}
|
||||
|
||||
fn write(&self, reader: &mut VmReader, status_flags: StatusFlags) -> Result<usize> {
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
reader: &mut VmReader,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
let mut buf = vec![0u8; reader.remain().min(IO_CAPACITY)];
|
||||
let write_len = reader.read_fallible(&mut buf.as_mut_slice().into())?;
|
||||
|
||||
|
|
@ -123,6 +133,16 @@ impl FileIo for PtyMaster {
|
|||
self.slave.driver().pollee().invalidate();
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileIo for PtyMaster {
|
||||
fn check_seekable(&self) -> Result<()> {
|
||||
return_errno_with_message!(Errno::ESPIPE, "the inode is a pty");
|
||||
}
|
||||
|
||||
fn is_offset_aware(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
match cmd {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
fs::{
|
||||
device::{Device, DeviceType},
|
||||
inode_handle::FileIo,
|
||||
utils::StatusFlags,
|
||||
utils::{InodeIo, StatusFlags},
|
||||
},
|
||||
prelude::*,
|
||||
process::signal::{PollHandle, Pollable},
|
||||
|
|
@ -45,14 +45,34 @@ impl Pollable for Random {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileIo for Random {
|
||||
fn read(&self, writer: &mut VmWriter, _status_flags: StatusFlags) -> Result<usize> {
|
||||
impl InodeIo for Random {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
Self::getrandom(writer)
|
||||
}
|
||||
|
||||
fn write(&self, reader: &mut VmReader, _status_flags: StatusFlags) -> Result<usize> {
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
reader: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
let len = reader.remain();
|
||||
reader.skip(len);
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileIo for Random {
|
||||
fn check_seekable(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_offset_aware(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use crate::{
|
|||
fs::{
|
||||
device::{Device, DeviceType},
|
||||
inode_handle::FileIo,
|
||||
utils::{IoctlCmd, StatusFlags},
|
||||
utils::{InodeIo, IoctlCmd, StatusFlags},
|
||||
},
|
||||
prelude::*,
|
||||
process::signal::{PollHandle, Pollable},
|
||||
|
|
@ -99,19 +99,39 @@ impl Pollable for TdxGuest {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileIo for TdxGuest {
|
||||
fn read(&self, _writer: &mut VmWriter, _status_flags: StatusFlags) -> Result<usize> {
|
||||
return_errno_with_message!(Errno::EPERM, "Read operation not supported")
|
||||
impl InodeIo for TdxGuest {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_writer: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
return_errno_with_message!(Errno::EINVAL, "the file is not valid for reading")
|
||||
}
|
||||
|
||||
fn write(&self, _reader: &mut VmReader, _status_flags: StatusFlags) -> Result<usize> {
|
||||
return_errno_with_message!(Errno::EPERM, "Write operation not supported")
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_reader: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
return_errno_with_message!(Errno::EINVAL, "the file not valid for writing")
|
||||
}
|
||||
}
|
||||
|
||||
impl FileIo for TdxGuest {
|
||||
fn check_seekable(&self) -> Result<()> {
|
||||
return_errno_with_message!(Errno::ESPIPE, "seek is not supported")
|
||||
}
|
||||
|
||||
fn is_offset_aware(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
match cmd {
|
||||
IoctlCmd::TDXGETREPORT => handle_get_report(arg),
|
||||
_ => return_errno_with_message!(Errno::EPERM, "Unsupported ioctl"),
|
||||
_ => return_errno_with_message!(Errno::ENOTTY, "ioctl is not supported"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
events::IoEvents,
|
||||
fs::{
|
||||
inode_handle::FileIo,
|
||||
utils::{IoctlCmd, StatusFlags},
|
||||
utils::{InodeIo, IoctlCmd, StatusFlags},
|
||||
},
|
||||
prelude::*,
|
||||
process::signal::{PollHandle, Pollable},
|
||||
|
|
@ -57,11 +57,37 @@ impl Pollable for ConsoleFile {
|
|||
fn poll(&self, mask: IoEvents, poller: Option<&mut PollHandle>) -> IoEvents;
|
||||
}
|
||||
|
||||
impl InodeIo for ConsoleFile {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
self.0.read(writer, status_flags)
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
reader: &mut VmReader,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
self.0.write(reader, status_flags)
|
||||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.0")]
|
||||
impl FileIo for ConsoleFile {
|
||||
fn read(&self, writer: &mut VmWriter, status_flags: StatusFlags) -> Result<usize>;
|
||||
fn write(&self, reader: &mut VmReader, status_flags: StatusFlags) -> Result<usize>;
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32>;
|
||||
|
||||
fn check_seekable(&self) -> Result<()> {
|
||||
return_errno_with_message!(Errno::ESPIPE, "the inode is a TTY");
|
||||
}
|
||||
|
||||
fn is_offset_aware(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
static N_TTY: Once<Box<[Arc<Tty<ConsoleDriver>>]>> = Once::new();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
fs::{
|
||||
device::{Device, DeviceType},
|
||||
inode_handle::FileIo,
|
||||
utils::StatusFlags,
|
||||
utils::{InodeIo, StatusFlags},
|
||||
},
|
||||
prelude::*,
|
||||
process::signal::{PollHandle, Pollable},
|
||||
|
|
@ -62,14 +62,34 @@ impl Pollable for Urandom {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileIo for Urandom {
|
||||
fn read(&self, writer: &mut VmWriter, _status_flags: StatusFlags) -> Result<usize> {
|
||||
impl InodeIo for Urandom {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
Self::getrandom(writer)
|
||||
}
|
||||
|
||||
fn write(&self, reader: &mut VmReader, _status_flags: StatusFlags) -> Result<usize> {
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
reader: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
let len = reader.remain();
|
||||
reader.skip(len);
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileIo for Urandom {
|
||||
fn check_seekable(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_offset_aware(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
fs::{
|
||||
device::{Device, DeviceType},
|
||||
inode_handle::FileIo,
|
||||
utils::StatusFlags,
|
||||
utils::{InodeIo, StatusFlags},
|
||||
},
|
||||
prelude::*,
|
||||
process::signal::{PollHandle, Pollable},
|
||||
|
|
@ -37,13 +37,33 @@ impl Pollable for Zero {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileIo for Zero {
|
||||
fn read(&self, writer: &mut VmWriter, _status_flags: StatusFlags) -> Result<usize> {
|
||||
impl InodeIo for Zero {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
let read_len = writer.fill_zeros(writer.avail())?;
|
||||
Ok(read_len)
|
||||
}
|
||||
|
||||
fn write(&self, reader: &mut VmReader, _status_flags: StatusFlags) -> Result<usize> {
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
reader: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
Ok(reader.remain())
|
||||
}
|
||||
}
|
||||
|
||||
impl FileIo for Zero {
|
||||
fn check_seekable(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_offset_aware(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use id_alloc::IdAlloc;
|
|||
|
||||
pub use self::ptmx::Ptmx;
|
||||
use self::slave::PtySlaveInode;
|
||||
use super::utils::MknodType;
|
||||
use super::utils::{InodeIo, MknodType, StatusFlags};
|
||||
use crate::{
|
||||
device::PtyMaster,
|
||||
fs::{
|
||||
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
registry::{FsProperties, FsType},
|
||||
utils::{
|
||||
mkmod, DirEntryVecExt, DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType,
|
||||
IoctlCmd, Metadata, SuperBlock, NAME_MAX,
|
||||
Metadata, SuperBlock, NAME_MAX,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -158,6 +158,26 @@ impl RootInode {
|
|||
}
|
||||
}
|
||||
|
||||
impl InodeIo for RootInode {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_writer: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_reader: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
}
|
||||
|
||||
impl Inode for RootInode {
|
||||
fn size(&self) -> usize {
|
||||
self.metadata.read().size
|
||||
|
|
|
|||
|
|
@ -46,6 +46,26 @@ impl Ptmx {
|
|||
|
||||
// Many methods are left to do nothing because every time the ptmx is being opened,
|
||||
// it returns the pty master. So the ptmx can not be used at upper layer.
|
||||
impl InodeIo for Ptmx {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_writer: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_reader: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Inode for Ptmx {
|
||||
fn size(&self) -> usize {
|
||||
self.metadata.read().size
|
||||
|
|
@ -118,26 +138,6 @@ impl Inode for Ptmx {
|
|||
self.metadata.write().ctime = time;
|
||||
}
|
||||
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn fs(&self) -> Arc<dyn FileSystem> {
|
||||
// FIXME: The below code may panic if the devpts is dropped.
|
||||
self.devpts().unwrap()
|
||||
|
|
|
|||
|
|
@ -6,12 +6,10 @@
|
|||
use super::*;
|
||||
use crate::{
|
||||
device::PtySlave,
|
||||
events::IoEvents,
|
||||
fs::{
|
||||
inode_handle::FileIo,
|
||||
utils::{AccessMode, StatusFlags},
|
||||
},
|
||||
process::signal::{PollHandle, Pollable},
|
||||
};
|
||||
|
||||
/// Same major number with Linux, the minor number is the index of slave.
|
||||
|
|
@ -39,6 +37,26 @@ impl PtySlaveInode {
|
|||
}
|
||||
}
|
||||
|
||||
impl InodeIo for PtySlaveInode {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
self.device.read(writer, status_flags)
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
reader: &mut VmReader,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
self.device.write(reader, status_flags)
|
||||
}
|
||||
}
|
||||
|
||||
impl Inode for PtySlaveInode {
|
||||
/// Do not cache dentry in DCACHE.
|
||||
///
|
||||
|
|
@ -119,30 +137,6 @@ impl Inode for PtySlaveInode {
|
|||
self.metadata.write().ctime = time;
|
||||
}
|
||||
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
self.device.read(writer, StatusFlags::empty())
|
||||
}
|
||||
|
||||
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
self.device.read(writer, StatusFlags::empty())
|
||||
}
|
||||
|
||||
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
self.device.write(reader, StatusFlags::empty())
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
self.device.write(reader, StatusFlags::empty())
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
self.device.ioctl(cmd, arg)
|
||||
}
|
||||
|
||||
fn poll(&self, mask: IoEvents, poller: Option<&mut PollHandle>) -> IoEvents {
|
||||
self.device.poll(mask, poller)
|
||||
}
|
||||
|
||||
fn fs(&self) -> Arc<dyn FileSystem> {
|
||||
self.fs.upgrade().unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,17 +25,16 @@ use super::{
|
|||
utils::{make_hash_index, DosTimestamp},
|
||||
};
|
||||
use crate::{
|
||||
events::IoEvents,
|
||||
fs::{
|
||||
exfat::{dentry::ExfatDentryIterator, fat::ExfatChain, fs::ExfatFs},
|
||||
path::{is_dot, is_dot_or_dotdot, is_dotdot},
|
||||
utils::{
|
||||
mkmod, CachePage, DirentVisitor, Extension, Inode, InodeMode, InodeType, IoctlCmd,
|
||||
Metadata, MknodType, PageCache, PageCacheBackend, SymbolicLink,
|
||||
mkmod, CachePage, DirentVisitor, Extension, Inode, InodeIo, InodeMode, InodeType,
|
||||
Metadata, MknodType, PageCache, PageCacheBackend, StatusFlags, SymbolicLink,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
process::{signal::PollHandle, Gid, Uid},
|
||||
process::{Gid, Uid},
|
||||
vm::vmo::Vmo,
|
||||
};
|
||||
|
||||
|
|
@ -615,6 +614,193 @@ impl ExfatInodeInner {
|
|||
}
|
||||
|
||||
impl ExfatInode {
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
let inner = self.inner.upread();
|
||||
if inner.inode_type.is_directory() {
|
||||
return_errno!(Errno::EISDIR)
|
||||
}
|
||||
let (read_off, read_len) = {
|
||||
let file_size = inner.size;
|
||||
let start = file_size.min(offset);
|
||||
let end = file_size.min(offset + writer.avail());
|
||||
(start, end - start)
|
||||
};
|
||||
inner.page_cache.pages().read(read_off, writer)?;
|
||||
|
||||
inner.upgrade().update_atime()?;
|
||||
Ok(read_len)
|
||||
}
|
||||
|
||||
// The offset and the length of buffer must be multiples of the block size.
|
||||
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
let inner = self.inner.upread();
|
||||
if inner.inode_type.is_directory() {
|
||||
return_errno!(Errno::EISDIR)
|
||||
}
|
||||
if !is_block_aligned(offset) || !is_block_aligned(writer.avail()) {
|
||||
return_errno_with_message!(Errno::EINVAL, "not block-aligned");
|
||||
}
|
||||
|
||||
let sector_size = inner.fs().sector_size();
|
||||
|
||||
let (read_off, read_len) = {
|
||||
let file_size = inner.size;
|
||||
let start = file_size.min(offset).align_down(sector_size);
|
||||
let end = file_size
|
||||
.min(offset + writer.avail())
|
||||
.align_down(sector_size);
|
||||
(start, end - start)
|
||||
};
|
||||
|
||||
inner
|
||||
.page_cache
|
||||
.discard_range(read_off..read_off + read_len);
|
||||
|
||||
let mut buf_offset = 0;
|
||||
let bio_segment = BioSegment::alloc(1, BioDirection::FromDevice);
|
||||
|
||||
let start_pos = inner.start_chain.walk_to_cluster_at_offset(read_off)?;
|
||||
let cluster_size = inner.fs().cluster_size();
|
||||
let mut cur_cluster = start_pos.0.clone();
|
||||
let mut cur_offset = start_pos.1;
|
||||
for _ in Bid::from_offset(read_off)..Bid::from_offset(read_off + read_len) {
|
||||
let physical_bid =
|
||||
Bid::from_offset(cur_cluster.cluster_id() as usize * cluster_size + cur_offset);
|
||||
inner
|
||||
.fs()
|
||||
.block_device()
|
||||
.read_blocks(physical_bid, bio_segment.clone())?;
|
||||
bio_segment.reader().unwrap().read_fallible(writer)?;
|
||||
buf_offset += BLOCK_SIZE;
|
||||
|
||||
cur_offset += BLOCK_SIZE;
|
||||
if cur_offset >= cluster_size {
|
||||
cur_cluster = cur_cluster.walk(1)?;
|
||||
cur_offset %= BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
inner.upgrade().update_atime()?;
|
||||
Ok(read_len)
|
||||
}
|
||||
|
||||
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
let write_len = reader.remain();
|
||||
// We need to obtain the fs lock to resize the file.
|
||||
let new_size = {
|
||||
let mut inner = self.inner.write();
|
||||
if inner.inode_type.is_directory() {
|
||||
return_errno!(Errno::EISDIR)
|
||||
}
|
||||
|
||||
let file_size = inner.size;
|
||||
let file_allocated_size = inner.size_allocated;
|
||||
let new_size = offset + write_len;
|
||||
let fs = inner.fs();
|
||||
let fs_guard = fs.lock();
|
||||
if new_size > file_size {
|
||||
if new_size > file_allocated_size {
|
||||
inner.resize(new_size, &fs_guard)?;
|
||||
}
|
||||
inner.page_cache.resize(new_size)?;
|
||||
}
|
||||
new_size.max(file_size)
|
||||
};
|
||||
|
||||
// Locks released here, so that file write can be parallelized.
|
||||
let inner = self.inner.upread();
|
||||
inner.page_cache.pages().write(offset, reader)?;
|
||||
|
||||
// Update timestamps and size.
|
||||
{
|
||||
let mut inner = inner.upgrade();
|
||||
|
||||
inner.update_atime_and_mtime()?;
|
||||
inner.size = new_size;
|
||||
}
|
||||
|
||||
let inner = self.inner.read();
|
||||
|
||||
// Write data back.
|
||||
if inner.is_sync() {
|
||||
let fs = inner.fs();
|
||||
let fs_guard = fs.lock();
|
||||
inner.sync_all(&fs_guard)?;
|
||||
}
|
||||
|
||||
Ok(write_len)
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
let write_len = reader.remain();
|
||||
let inner = self.inner.upread();
|
||||
if inner.inode_type.is_directory() {
|
||||
return_errno!(Errno::EISDIR)
|
||||
}
|
||||
if !is_block_aligned(offset) || !is_block_aligned(write_len) {
|
||||
return_errno_with_message!(Errno::EINVAL, "not block-aligned");
|
||||
}
|
||||
|
||||
let file_size = inner.size;
|
||||
let file_allocated_size = inner.size_allocated;
|
||||
let end_offset = offset + write_len;
|
||||
|
||||
let start = offset.min(file_size);
|
||||
let end = end_offset.min(file_size);
|
||||
inner.page_cache.discard_range(start..end);
|
||||
|
||||
let new_size = {
|
||||
let mut inner = inner.upgrade();
|
||||
if end_offset > file_size {
|
||||
let fs = inner.fs();
|
||||
let fs_guard = fs.lock();
|
||||
if end_offset > file_allocated_size {
|
||||
inner.resize(end_offset, &fs_guard)?;
|
||||
}
|
||||
inner.page_cache.resize(end_offset)?;
|
||||
}
|
||||
file_size.max(end_offset)
|
||||
};
|
||||
|
||||
let inner = self.inner.upread();
|
||||
|
||||
let bio_segment = BioSegment::alloc(1, BioDirection::ToDevice);
|
||||
let start_pos = inner.start_chain.walk_to_cluster_at_offset(offset)?;
|
||||
let cluster_size = inner.fs().cluster_size();
|
||||
let mut cur_cluster = start_pos.0.clone();
|
||||
let mut cur_offset = start_pos.1;
|
||||
for _ in Bid::from_offset(offset)..Bid::from_offset(end_offset) {
|
||||
bio_segment.writer().unwrap().write_fallible(reader)?;
|
||||
let physical_bid =
|
||||
Bid::from_offset(cur_cluster.cluster_id() as usize * cluster_size + cur_offset);
|
||||
let fs = inner.fs();
|
||||
fs.block_device()
|
||||
.write_blocks(physical_bid, bio_segment.clone())?;
|
||||
|
||||
cur_offset += BLOCK_SIZE;
|
||||
if cur_offset >= cluster_size {
|
||||
cur_cluster = cur_cluster.walk(1)?;
|
||||
cur_offset %= BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut inner = inner.upgrade();
|
||||
inner.update_atime_and_mtime()?;
|
||||
inner.size = new_size;
|
||||
}
|
||||
|
||||
let inner = self.inner.read();
|
||||
// Sync this inode since size has changed.
|
||||
if inner.is_sync() {
|
||||
let fs = inner.fs();
|
||||
let fs_guard = fs.lock();
|
||||
inner.sync_metadata(&fs_guard)?;
|
||||
}
|
||||
|
||||
Ok(write_len)
|
||||
}
|
||||
|
||||
// TODO: Should be called when inode is evicted from fs.
|
||||
pub(super) fn reclaim_space(&self) -> Result<()> {
|
||||
let inner = self.inner.write();
|
||||
|
|
@ -1093,6 +1279,34 @@ fn check_corner_cases_for_rename(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
impl InodeIo for ExfatInode {
|
||||
fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
if status_flags.contains(StatusFlags::O_DIRECT) {
|
||||
self.read_direct_at(offset, writer)
|
||||
} else {
|
||||
self.read_at(offset, writer)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
reader: &mut VmReader,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
if status_flags.contains(StatusFlags::O_DIRECT) {
|
||||
self.write_direct_at(offset, reader)
|
||||
} else {
|
||||
self.write_at(offset, reader)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Inode for ExfatInode {
|
||||
fn ino(&self) -> u64 {
|
||||
self.inner.read().ino
|
||||
|
|
@ -1231,193 +1445,6 @@ impl Inode for ExfatInode {
|
|||
Some(self.inner.read().page_cache.pages().clone())
|
||||
}
|
||||
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
let inner = self.inner.upread();
|
||||
if inner.inode_type.is_directory() {
|
||||
return_errno!(Errno::EISDIR)
|
||||
}
|
||||
let (read_off, read_len) = {
|
||||
let file_size = inner.size;
|
||||
let start = file_size.min(offset);
|
||||
let end = file_size.min(offset + writer.avail());
|
||||
(start, end - start)
|
||||
};
|
||||
inner.page_cache.pages().read(read_off, writer)?;
|
||||
|
||||
inner.upgrade().update_atime()?;
|
||||
Ok(read_len)
|
||||
}
|
||||
|
||||
// The offset and the length of buffer must be multiples of the block size.
|
||||
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
let inner = self.inner.upread();
|
||||
if inner.inode_type.is_directory() {
|
||||
return_errno!(Errno::EISDIR)
|
||||
}
|
||||
if !is_block_aligned(offset) || !is_block_aligned(writer.avail()) {
|
||||
return_errno_with_message!(Errno::EINVAL, "not block-aligned");
|
||||
}
|
||||
|
||||
let sector_size = inner.fs().sector_size();
|
||||
|
||||
let (read_off, read_len) = {
|
||||
let file_size = inner.size;
|
||||
let start = file_size.min(offset).align_down(sector_size);
|
||||
let end = file_size
|
||||
.min(offset + writer.avail())
|
||||
.align_down(sector_size);
|
||||
(start, end - start)
|
||||
};
|
||||
|
||||
inner
|
||||
.page_cache
|
||||
.discard_range(read_off..read_off + read_len);
|
||||
|
||||
let mut buf_offset = 0;
|
||||
let bio_segment = BioSegment::alloc(1, BioDirection::FromDevice);
|
||||
|
||||
let start_pos = inner.start_chain.walk_to_cluster_at_offset(read_off)?;
|
||||
let cluster_size = inner.fs().cluster_size();
|
||||
let mut cur_cluster = start_pos.0.clone();
|
||||
let mut cur_offset = start_pos.1;
|
||||
for _ in Bid::from_offset(read_off)..Bid::from_offset(read_off + read_len) {
|
||||
let physical_bid =
|
||||
Bid::from_offset(cur_cluster.cluster_id() as usize * cluster_size + cur_offset);
|
||||
inner
|
||||
.fs()
|
||||
.block_device()
|
||||
.read_blocks(physical_bid, bio_segment.clone())?;
|
||||
bio_segment.reader().unwrap().read_fallible(writer)?;
|
||||
buf_offset += BLOCK_SIZE;
|
||||
|
||||
cur_offset += BLOCK_SIZE;
|
||||
if cur_offset >= cluster_size {
|
||||
cur_cluster = cur_cluster.walk(1)?;
|
||||
cur_offset %= BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
inner.upgrade().update_atime()?;
|
||||
Ok(read_len)
|
||||
}
|
||||
|
||||
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
let write_len = reader.remain();
|
||||
// We need to obtain the fs lock to resize the file.
|
||||
let new_size = {
|
||||
let mut inner = self.inner.write();
|
||||
if inner.inode_type.is_directory() {
|
||||
return_errno!(Errno::EISDIR)
|
||||
}
|
||||
|
||||
let file_size = inner.size;
|
||||
let file_allocated_size = inner.size_allocated;
|
||||
let new_size = offset + write_len;
|
||||
let fs = inner.fs();
|
||||
let fs_guard = fs.lock();
|
||||
if new_size > file_size {
|
||||
if new_size > file_allocated_size {
|
||||
inner.resize(new_size, &fs_guard)?;
|
||||
}
|
||||
inner.page_cache.resize(new_size)?;
|
||||
}
|
||||
new_size.max(file_size)
|
||||
};
|
||||
|
||||
// Locks released here, so that file write can be parallelized.
|
||||
let inner = self.inner.upread();
|
||||
inner.page_cache.pages().write(offset, reader)?;
|
||||
|
||||
// Update timestamps and size.
|
||||
{
|
||||
let mut inner = inner.upgrade();
|
||||
|
||||
inner.update_atime_and_mtime()?;
|
||||
inner.size = new_size;
|
||||
}
|
||||
|
||||
let inner = self.inner.read();
|
||||
|
||||
// Write data back.
|
||||
if inner.is_sync() {
|
||||
let fs = inner.fs();
|
||||
let fs_guard = fs.lock();
|
||||
inner.sync_all(&fs_guard)?;
|
||||
}
|
||||
|
||||
Ok(write_len)
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
let write_len = reader.remain();
|
||||
let inner = self.inner.upread();
|
||||
if inner.inode_type.is_directory() {
|
||||
return_errno!(Errno::EISDIR)
|
||||
}
|
||||
if !is_block_aligned(offset) || !is_block_aligned(write_len) {
|
||||
return_errno_with_message!(Errno::EINVAL, "not block-aligned");
|
||||
}
|
||||
|
||||
let file_size = inner.size;
|
||||
let file_allocated_size = inner.size_allocated;
|
||||
let end_offset = offset + write_len;
|
||||
|
||||
let start = offset.min(file_size);
|
||||
let end = end_offset.min(file_size);
|
||||
inner.page_cache.discard_range(start..end);
|
||||
|
||||
let new_size = {
|
||||
let mut inner = inner.upgrade();
|
||||
if end_offset > file_size {
|
||||
let fs = inner.fs();
|
||||
let fs_guard = fs.lock();
|
||||
if end_offset > file_allocated_size {
|
||||
inner.resize(end_offset, &fs_guard)?;
|
||||
}
|
||||
inner.page_cache.resize(end_offset)?;
|
||||
}
|
||||
file_size.max(end_offset)
|
||||
};
|
||||
|
||||
let inner = self.inner.upread();
|
||||
|
||||
let bio_segment = BioSegment::alloc(1, BioDirection::ToDevice);
|
||||
let start_pos = inner.start_chain.walk_to_cluster_at_offset(offset)?;
|
||||
let cluster_size = inner.fs().cluster_size();
|
||||
let mut cur_cluster = start_pos.0.clone();
|
||||
let mut cur_offset = start_pos.1;
|
||||
for _ in Bid::from_offset(offset)..Bid::from_offset(end_offset) {
|
||||
bio_segment.writer().unwrap().write_fallible(reader)?;
|
||||
let physical_bid =
|
||||
Bid::from_offset(cur_cluster.cluster_id() as usize * cluster_size + cur_offset);
|
||||
let fs = inner.fs();
|
||||
fs.block_device()
|
||||
.write_blocks(physical_bid, bio_segment.clone())?;
|
||||
|
||||
cur_offset += BLOCK_SIZE;
|
||||
if cur_offset >= cluster_size {
|
||||
cur_cluster = cur_cluster.walk(1)?;
|
||||
cur_offset %= BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut inner = inner.upgrade();
|
||||
inner.update_atime_and_mtime()?;
|
||||
inner.size = new_size;
|
||||
}
|
||||
|
||||
let inner = self.inner.read();
|
||||
// Sync this inode since size has changed.
|
||||
if inner.is_sync() {
|
||||
let fs = inner.fs();
|
||||
let fs_guard = fs.lock();
|
||||
inner.sync_metadata(&fs_guard)?;
|
||||
}
|
||||
|
||||
Ok(write_len)
|
||||
}
|
||||
|
||||
fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> {
|
||||
let fs = self.inner.read().fs();
|
||||
let fs_guard = fs.lock();
|
||||
|
|
@ -1679,10 +1706,6 @@ impl Inode for ExfatInode {
|
|||
return_errno_with_message!(Errno::EINVAL, "unsupported operation")
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
return_errno_with_message!(Errno::EINVAL, "unsupported operation")
|
||||
}
|
||||
|
||||
fn sync_all(&self) -> Result<()> {
|
||||
let inner = self.inner.read();
|
||||
let fs = inner.fs();
|
||||
|
|
@ -1705,11 +1728,6 @@ impl Inode for ExfatInode {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents {
|
||||
let events = IoEvents::IN | IoEvents::OUT;
|
||||
events & mask
|
||||
}
|
||||
|
||||
fn is_dentry_cacheable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#![expect(unused_variables)]
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use crate::{
|
||||
fs::{
|
||||
ext2::{FilePerm, Inode as Ext2Inode},
|
||||
utils::{
|
||||
DirentVisitor, Extension, FallocMode, FileSystem, Inode, InodeMode, InodeType,
|
||||
IoctlCmd, Metadata, MknodType, SymbolicLink, XattrName, XattrNamespace, XattrSetFlags,
|
||||
DirentVisitor, Extension, FallocMode, FileSystem, Inode, InodeIo, InodeMode, InodeType,
|
||||
Metadata, MknodType, StatusFlags, SymbolicLink, XattrName, XattrNamespace,
|
||||
XattrSetFlags,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -17,6 +16,34 @@ use crate::{
|
|||
vm::vmo::Vmo,
|
||||
};
|
||||
|
||||
impl InodeIo for Ext2Inode {
|
||||
fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
if status_flags.contains(StatusFlags::O_DIRECT) {
|
||||
self.read_direct_at(offset, writer)
|
||||
} else {
|
||||
self.read_at(offset, writer)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
reader: &mut VmReader,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
if status_flags.contains(StatusFlags::O_DIRECT) {
|
||||
self.write_direct_at(offset, reader)
|
||||
} else {
|
||||
self.write_at(offset, reader)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Inode for Ext2Inode {
|
||||
fn size(&self) -> usize {
|
||||
self.file_size() as _
|
||||
|
|
@ -93,22 +120,6 @@ impl Inode for Ext2Inode {
|
|||
Some(self.page_cache())
|
||||
}
|
||||
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
self.read_at(offset, writer)
|
||||
}
|
||||
|
||||
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
self.read_direct_at(offset, writer)
|
||||
}
|
||||
|
||||
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
self.write_at(offset, reader)
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
self.write_direct_at(offset, reader)
|
||||
}
|
||||
|
||||
fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> {
|
||||
Ok(self.create(name, type_, mode.into())?)
|
||||
}
|
||||
|
|
@ -169,10 +180,6 @@ impl Inode for Ext2Inode {
|
|||
self.fallocate(mode, offset, len)
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
Err(Error::new(Errno::EINVAL))
|
||||
}
|
||||
|
||||
fn sync_all(&self) -> Result<()> {
|
||||
self.sync_all()?;
|
||||
self.fs().block_device().sync()?;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use core::sync::atomic::{AtomicU32, Ordering};
|
|||
|
||||
pub use dyn_cap::InodeHandle;
|
||||
|
||||
use super::utils::InodeIo;
|
||||
use crate::{
|
||||
events::IoEvents,
|
||||
fs::{
|
||||
|
|
@ -34,71 +35,91 @@ struct HandleInner {
|
|||
|
||||
impl HandleInner {
|
||||
pub(self) fn read(&self, writer: &mut VmWriter) -> Result<usize> {
|
||||
if let Some(ref file_io) = self.file_io {
|
||||
return file_io.read(writer, self.status_flags());
|
||||
}
|
||||
let (inode_io, is_offset_aware) = self.inode_io_and_is_offset_aware();
|
||||
let status_flags = self.status_flags();
|
||||
|
||||
if !self.path.inode().is_seekable() {
|
||||
return self.read_at(0, writer);
|
||||
if !is_offset_aware {
|
||||
return inode_io.read_at(0, writer, status_flags);
|
||||
}
|
||||
|
||||
let mut offset = self.offset.lock();
|
||||
|
||||
let len = self.read_at(*offset, writer)?;
|
||||
|
||||
let len = inode_io.read_at(*offset, writer, status_flags)?;
|
||||
*offset += len;
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
pub(self) fn write(&self, reader: &mut VmReader) -> Result<usize> {
|
||||
if let Some(ref file_io) = self.file_io {
|
||||
return file_io.write(reader, self.status_flags());
|
||||
}
|
||||
let (inode_io, is_offset_aware) = self.inode_io_and_is_offset_aware();
|
||||
let status_flags = self.status_flags();
|
||||
|
||||
if !self.path.inode().is_seekable() {
|
||||
return self.write_at(0, reader);
|
||||
if !is_offset_aware {
|
||||
return inode_io.write_at(0, reader, status_flags);
|
||||
}
|
||||
|
||||
let mut offset = self.offset.lock();
|
||||
|
||||
if self.status_flags().contains(StatusFlags::O_APPEND) {
|
||||
// FIXME: How can we deal with the `O_APPEND` flag if `file_io` is set?
|
||||
if status_flags.contains(StatusFlags::O_APPEND) && self.file_io.is_none() {
|
||||
// FIXME: `O_APPEND` should ensure that new content is appended even if another process
|
||||
// is writing to the file concurrently.
|
||||
*offset = self.path.size();
|
||||
}
|
||||
|
||||
let len = self.write_at(*offset, reader)?;
|
||||
|
||||
let len = inode_io.write_at(*offset, reader, status_flags)?;
|
||||
*offset += len;
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
pub(self) fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
if let Some(ref _file_io) = self.file_io {
|
||||
todo!("support read_at for FileIo");
|
||||
fn inode_io_and_is_offset_aware(&self) -> (&dyn InodeIo, bool) {
|
||||
if let Some(ref file_io) = self.file_io {
|
||||
let is_offset_aware = file_io.is_offset_aware();
|
||||
return (file_io.as_ref(), is_offset_aware);
|
||||
}
|
||||
|
||||
if self.status_flags().contains(StatusFlags::O_DIRECT) {
|
||||
self.path.inode().read_direct_at(offset, writer)
|
||||
} else {
|
||||
self.path.inode().read_at(offset, writer)
|
||||
}
|
||||
let inode = self.path.inode();
|
||||
let is_offset_aware = inode.type_().is_seekable();
|
||||
(inode.as_ref(), is_offset_aware)
|
||||
}
|
||||
|
||||
pub(self) fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
let inode_io = self.inode_io_and_check_seekable()?;
|
||||
let status_flags = self.status_flags();
|
||||
|
||||
inode_io.read_at(offset, writer, status_flags)
|
||||
}
|
||||
|
||||
pub(self) fn write_at(&self, mut offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
if let Some(ref _file_io) = self.file_io {
|
||||
todo!("support write_at for FileIo");
|
||||
}
|
||||
|
||||
let inode_io = self.inode_io_and_check_seekable()?;
|
||||
let status_flags = self.status_flags();
|
||||
if status_flags.contains(StatusFlags::O_APPEND) {
|
||||
// If the file has the O_APPEND flag, the offset is ignored
|
||||
|
||||
// FIXME: How can we deal with the `O_APPEND` flag if `file_io` is set?
|
||||
if status_flags.contains(StatusFlags::O_APPEND) && self.file_io.is_none() {
|
||||
// If the file has the `O_APPEND` flag, the offset is ignored.
|
||||
// FIXME: `O_APPEND` should ensure that new content is appended even if another process
|
||||
// is writing to the file concurrently.
|
||||
offset = self.path.size();
|
||||
}
|
||||
|
||||
if status_flags.contains(StatusFlags::O_DIRECT) {
|
||||
self.path.inode().write_direct_at(offset, reader)
|
||||
} else {
|
||||
self.path.inode().write_at(offset, reader)
|
||||
inode_io.write_at(offset, reader, status_flags)
|
||||
}
|
||||
|
||||
fn inode_io_and_check_seekable(&self) -> Result<&dyn InodeIo> {
|
||||
if let Some(ref file_io) = self.file_io {
|
||||
file_io.check_seekable()?;
|
||||
return Ok(file_io.as_ref());
|
||||
}
|
||||
|
||||
let inode = self.path.inode();
|
||||
if !inode.type_().is_seekable() {
|
||||
return_errno_with_message!(
|
||||
Errno::ESPIPE,
|
||||
"the inode cannot be read or written at a specific offset"
|
||||
);
|
||||
}
|
||||
Ok(inode.as_ref())
|
||||
}
|
||||
|
||||
pub(self) fn seek(&self, pos: SeekFrom) -> Result<usize> {
|
||||
|
|
@ -136,7 +157,8 @@ impl HandleInner {
|
|||
return file_io.poll(mask, poller);
|
||||
}
|
||||
|
||||
self.path.inode().poll(mask, poller)
|
||||
let events = IoEvents::IN | IoEvents::OUT;
|
||||
events & mask
|
||||
}
|
||||
|
||||
pub(self) fn fallocate(&self, mode: FallocMode, offset: usize, len: usize) -> Result<()> {
|
||||
|
|
@ -154,7 +176,7 @@ impl HandleInner {
|
|||
return file_io.ioctl(cmd, arg);
|
||||
}
|
||||
|
||||
self.path.inode().ioctl(cmd, arg)
|
||||
return_errno_with_message!(Errno::ENOTTY, "ioctl is not supported");
|
||||
}
|
||||
|
||||
pub(self) fn mappable(&self) -> Result<Mappable> {
|
||||
|
|
@ -265,16 +287,12 @@ impl Debug for HandleInner {
|
|||
///
|
||||
/// This trait is typically implemented for special files like devices or
|
||||
/// named pipes (FIFOs), which have behaviors different from regular on-disk files.
|
||||
//
|
||||
// TODO: The `status_flags` parameter in `read` and `write` may need to be stored directly
|
||||
// in the `FileIo`. We need further refactoring to find an appropriate way to enable `FileIo`
|
||||
// to utilize the information in the `HandleInner`.
|
||||
pub trait FileIo: Pollable + Send + Sync + 'static {
|
||||
/// Reads data from the file into the given `VmWriter`.
|
||||
fn read(&self, writer: &mut VmWriter, status_flags: StatusFlags) -> Result<usize>;
|
||||
pub trait FileIo: Pollable + InodeIo + Send + Sync + 'static {
|
||||
/// Checks whether the `seek()` operation should fail.
|
||||
fn check_seekable(&self) -> Result<()>;
|
||||
|
||||
/// Writes data from the given `VmReader` into the file.
|
||||
fn write(&self, reader: &mut VmReader, status_flags: StatusFlags) -> Result<usize>;
|
||||
/// Returns whether the `read()`/`write()` operation should use and advance the offset.
|
||||
fn is_offset_aware(&self) -> bool;
|
||||
|
||||
// See `FileLike::mappable`.
|
||||
fn mappable(&self) -> Result<Mappable> {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use crate::{
|
|||
registry::{FsProperties, FsType},
|
||||
utils::{
|
||||
mkmod, AccessMode, DirentCounter, DirentVisitor, FallocMode, FileSystem, FsFlags,
|
||||
Inode, InodeMode, InodeType, IoctlCmd, Metadata, MknodType, StatusFlags, SuperBlock,
|
||||
Inode, InodeIo, InodeMode, InodeType, Metadata, MknodType, StatusFlags, SuperBlock,
|
||||
SymbolicLink, XattrName, XattrNamespace, XattrSetFlags, NAME_MAX, XATTR_VALUE_MAX_LEN,
|
||||
},
|
||||
},
|
||||
|
|
@ -280,34 +280,30 @@ impl OverlayInode {
|
|||
/// Writes data to the target inode, if it resides in the lower layer,
|
||||
/// it will be copied up to the upper layer.
|
||||
/// The corresponding parent directories will be created also if they do not exist.
|
||||
pub fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
pub fn write_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
reader: &mut VmReader,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
if self.type_ == InodeType::Dir {
|
||||
return_errno!(Errno::EISDIR);
|
||||
}
|
||||
let upper = self.build_upper_recursively_if_needed()?;
|
||||
upper.write_at(offset, reader)
|
||||
upper.write_at(offset, reader, status_flags)
|
||||
}
|
||||
|
||||
pub fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
pub fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
if self.type_ == InodeType::Dir {
|
||||
return_errno!(Errno::EISDIR);
|
||||
}
|
||||
let upper = self.build_upper_recursively_if_needed()?;
|
||||
upper.write_direct_at(offset, reader)
|
||||
}
|
||||
|
||||
pub fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
if self.type_ == InodeType::Dir {
|
||||
return_errno!(Errno::EISDIR);
|
||||
}
|
||||
self.get_top_valid_inode().read_at(offset, writer)
|
||||
}
|
||||
|
||||
pub fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
if self.type_ == InodeType::Dir {
|
||||
return_errno!(Errno::EISDIR);
|
||||
}
|
||||
self.get_top_valid_inode().read_direct_at(offset, writer)
|
||||
self.get_top_valid_inode()
|
||||
.read_at(offset, writer, status_flags)
|
||||
}
|
||||
|
||||
/// Returns the children objects in a unified view.
|
||||
|
|
@ -497,13 +493,6 @@ impl OverlayInode {
|
|||
pub fn sync_data(&self) -> Result<()> {
|
||||
self.upper().map_or(Ok(()), |upper| upper.sync_data())
|
||||
}
|
||||
|
||||
pub fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
self.upper().map_or_else(
|
||||
|| Err(Error::with_message(Errno::ENOTTY, "ioctl is not supported")),
|
||||
|upper| upper.ioctl(cmd, arg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.get_top_valid_inode()")]
|
||||
|
|
@ -828,10 +817,10 @@ impl OverlayInode {
|
|||
.alloc_segment(lower_size.align_up(BLOCK_SIZE) / BLOCK_SIZE)?;
|
||||
|
||||
let mut writer = data_buf.writer().to_fallible();
|
||||
let read_len = lower.read_at(0, &mut writer)?;
|
||||
let read_len = lower.read_at(0, &mut writer, StatusFlags::empty())?;
|
||||
|
||||
let mut reader = data_buf.reader().to_fallible();
|
||||
let _ = upper.write_at(0, reader.limit(read_len))?;
|
||||
let _ = upper.write_at(0, reader.limit(read_len), StatusFlags::empty())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -906,6 +895,22 @@ fn is_opaque_dir(inode: &Arc<dyn Inode>) -> Result<bool> {
|
|||
Ok(value == WHITEOUT_AND_OPAQUE_XATTR_VALUE)
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self")]
|
||||
impl InodeIo for OverlayInode {
|
||||
fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize>;
|
||||
fn write_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
reader: &mut VmReader,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize>;
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self")]
|
||||
impl Inode for OverlayInode {
|
||||
fn size(&self) -> usize;
|
||||
|
|
@ -926,10 +931,6 @@ impl Inode for OverlayInode {
|
|||
fn ctime(&self) -> Duration;
|
||||
fn set_ctime(&self, time: Duration);
|
||||
fn page_cache(&self) -> Option<Arc<Vmo>>;
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize>;
|
||||
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize>;
|
||||
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize>;
|
||||
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize>;
|
||||
fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>>;
|
||||
fn mknod(&self, name: &str, mode: InodeMode, type_: MknodType) -> Result<Arc<dyn Inode>>;
|
||||
fn open(
|
||||
|
|
@ -945,7 +946,6 @@ impl Inode for OverlayInode {
|
|||
fn rename(&self, old_name: &str, target: &Arc<dyn Inode>, new_name: &str) -> Result<()>;
|
||||
fn read_link(&self) -> Result<SymbolicLink>;
|
||||
fn write_link(&self, target: &str) -> Result<()>;
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32>;
|
||||
fn sync_all(&self) -> Result<()>;
|
||||
fn sync_data(&self) -> Result<()>;
|
||||
fn fallocate(&self, mode: FallocMode, offset: usize, len: usize) -> Result<()>;
|
||||
|
|
@ -1219,7 +1219,11 @@ mod tests {
|
|||
let f2 = l2.new_fs_child("f2", InodeType::File, mode).unwrap();
|
||||
let f2_inode = f2.inode();
|
||||
f2_inode
|
||||
.write_at(0, &mut VmReader::from([8u8; 4].as_slice()).to_fallible())
|
||||
.write_at(
|
||||
0,
|
||||
&mut VmReader::from([8u8; 4].as_slice()).to_fallible(),
|
||||
StatusFlags::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
f2_inode.set_group(Gid::new(77)).unwrap();
|
||||
f2_inode
|
||||
|
|
@ -1361,8 +1365,12 @@ mod tests {
|
|||
|
||||
let mut data = [0u8; 4];
|
||||
let f2 = root.lookup("f2").unwrap();
|
||||
f2.read_at(0, &mut VmWriter::from(data.as_mut_slice()).to_fallible())
|
||||
.unwrap();
|
||||
f2.read_at(
|
||||
0,
|
||||
&mut VmWriter::from(data.as_mut_slice()).to_fallible(),
|
||||
StatusFlags::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(data, [8u8; 4]);
|
||||
|
||||
let d1 = root.lookup("d1").unwrap();
|
||||
|
|
@ -1444,8 +1452,12 @@ mod tests {
|
|||
f1.set_atime(Duration::default());
|
||||
f1.sync_data().unwrap();
|
||||
let mut data = [0u8; 1];
|
||||
f1.read_at(0, &mut VmWriter::from(data.as_mut_slice()).to_fallible())
|
||||
.unwrap();
|
||||
f1.read_at(
|
||||
0,
|
||||
&mut VmWriter::from(data.as_mut_slice()).to_fallible(),
|
||||
StatusFlags::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(data, [3u8; 1]);
|
||||
|
||||
let d1 = root.lookup("d1").unwrap();
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use crate::{
|
|||
events::IoEvents,
|
||||
fs::{
|
||||
inode_handle::FileIo,
|
||||
utils::{AccessMode, StatusFlags},
|
||||
utils::{AccessMode, InodeIo, StatusFlags},
|
||||
},
|
||||
prelude::*,
|
||||
process::signal::{PollHandle, Pollable},
|
||||
|
|
@ -81,8 +81,13 @@ impl Drop for NamedPipeHandle {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileIo for NamedPipeHandle {
|
||||
fn read(&self, writer: &mut VmWriter, status_flags: StatusFlags) -> Result<usize> {
|
||||
impl InodeIo for NamedPipeHandle {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
if status_flags.contains(StatusFlags::O_NONBLOCK) {
|
||||
self.try_read(writer)
|
||||
} else {
|
||||
|
|
@ -90,7 +95,12 @@ impl FileIo for NamedPipeHandle {
|
|||
}
|
||||
}
|
||||
|
||||
fn write(&self, reader: &mut VmReader, status_flags: StatusFlags) -> Result<usize> {
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
reader: &mut VmReader,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
if status_flags.contains(StatusFlags::O_NONBLOCK) {
|
||||
self.try_write(reader)
|
||||
} else {
|
||||
|
|
@ -99,6 +109,16 @@ impl FileIo for NamedPipeHandle {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileIo for NamedPipeHandle {
|
||||
fn check_seekable(&self) -> Result<()> {
|
||||
return_errno_with_message!(Errno::ESPIPE, "the inode is a FIFO file")
|
||||
}
|
||||
|
||||
fn is_offset_aware(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// A named pipe (FIFO) that provides inter-process communication.
|
||||
///
|
||||
/// Named pipes are special files that appear in the filesystem and provide
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ use crate::{
|
|||
fs::{
|
||||
path::{is_dot, is_dotdot},
|
||||
utils::{
|
||||
DirEntryVecExt, DirentVisitor, FileSystem, Inode, InodeMode, InodeType, Metadata,
|
||||
MknodType,
|
||||
DirEntryVecExt, DirentVisitor, FileSystem, Inode, InodeIo, InodeMode, InodeType,
|
||||
Metadata, MknodType, StatusFlags,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -71,6 +71,26 @@ impl<D: DirOps> ProcDir<D> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<D: DirOps + 'static> InodeIo for ProcDir<D> {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_writer: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_reader: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.common")]
|
||||
impl<D: DirOps + 'static> Inode for ProcDir<D> {
|
||||
fn size(&self) -> usize;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ use inherit_methods_macro::inherit_methods;
|
|||
|
||||
use super::{Common, ProcFs};
|
||||
use crate::{
|
||||
fs::utils::{FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata, SymbolicLink},
|
||||
fs::utils::{
|
||||
FileSystem, Inode, InodeIo, InodeMode, InodeType, Metadata, StatusFlags, SymbolicLink,
|
||||
},
|
||||
prelude::*,
|
||||
process::{Gid, Uid},
|
||||
};
|
||||
|
|
@ -36,6 +38,26 @@ impl<F: FileOps> ProcFile<F> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<F: FileOps + 'static> InodeIo for ProcFile<F> {
|
||||
fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
self.inner.read_at(offset, writer)
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
reader: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
self.inner.write_at(offset, reader)
|
||||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.common")]
|
||||
impl<F: FileOps + 'static> Inode for ProcFile<F> {
|
||||
fn size(&self) -> usize;
|
||||
|
|
@ -63,22 +85,6 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
|
|||
InodeType::File
|
||||
}
|
||||
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
self.inner.read_at(offset, writer)
|
||||
}
|
||||
|
||||
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
self.read_at(offset, writer)
|
||||
}
|
||||
|
||||
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
self.inner.write_at(offset, reader)
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
self.write_at(offset, reader)
|
||||
}
|
||||
|
||||
fn read_link(&self) -> Result<SymbolicLink> {
|
||||
Err(Error::new(Errno::EINVAL))
|
||||
}
|
||||
|
|
@ -87,10 +93,6 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
|
|||
Err(Error::new(Errno::EINVAL))
|
||||
}
|
||||
|
||||
fn ioctl(&self, _cmd: IoctlCmd, _arg: usize) -> Result<i32> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn is_dentry_cacheable(&self) -> bool {
|
||||
!self.common.is_volatile()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ use inherit_methods_macro::inherit_methods;
|
|||
|
||||
use super::{Common, ProcFs};
|
||||
use crate::{
|
||||
fs::utils::{FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata, SymbolicLink},
|
||||
fs::utils::{
|
||||
FileSystem, Inode, InodeIo, InodeMode, InodeType, Metadata, StatusFlags, SymbolicLink,
|
||||
},
|
||||
prelude::*,
|
||||
process::{Gid, Uid},
|
||||
};
|
||||
|
|
@ -37,6 +39,26 @@ impl<S: SymOps> ProcSym<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: SymOps + 'static> InodeIo for ProcSym<S> {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_writer: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_reader: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.common")]
|
||||
impl<S: SymOps + 'static> Inode for ProcSym<S> {
|
||||
fn size(&self) -> usize;
|
||||
|
|
@ -64,22 +86,6 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
|
|||
InodeType::SymLink
|
||||
}
|
||||
|
||||
fn read_at(&self, _offset: usize, _writer: &mut VmWriter) -> Result<usize> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn read_direct_at(&self, _offset: usize, _writer: &mut VmWriter) -> Result<usize> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn write_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn read_link(&self) -> Result<SymbolicLink> {
|
||||
self.inner.read_link()
|
||||
}
|
||||
|
|
@ -88,10 +94,6 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
|
|||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn ioctl(&self, _cmd: IoctlCmd, _arg: usize) -> Result<i32> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn is_dentry_cacheable(&self) -> bool {
|
||||
!self.common.is_volatile()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use core::time::Duration;
|
|||
|
||||
use spin::Once;
|
||||
|
||||
use super::utils::{InodeIo, StatusFlags};
|
||||
use crate::{
|
||||
fs::{
|
||||
registry::{FsProperties, FsType},
|
||||
|
|
@ -210,6 +211,32 @@ impl PseudoInode {
|
|||
}
|
||||
}
|
||||
|
||||
impl InodeIo for PseudoInode {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_writer: &mut VmWriter,
|
||||
_status: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
return_errno_with_message!(
|
||||
Errno::ESPIPE,
|
||||
"pseudo inodes cannot be read at a specific offset"
|
||||
);
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_reader: &mut VmReader,
|
||||
_status: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
return_errno_with_message!(
|
||||
Errno::ESPIPE,
|
||||
"pseudo inodes cannot be written at a specific offset"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Inode for PseudoInode {
|
||||
fn size(&self) -> usize {
|
||||
self.metadata.lock().size
|
||||
|
|
@ -288,34 +315,6 @@ impl Inode for PseudoInode {
|
|||
self.metadata.lock().ctime = time;
|
||||
}
|
||||
|
||||
fn read_at(&self, _offset: usize, _writer: &mut VmWriter) -> Result<usize> {
|
||||
return_errno_with_message!(
|
||||
Errno::ESPIPE,
|
||||
"pseudo inodes cannot be read at a specific offset"
|
||||
);
|
||||
}
|
||||
|
||||
fn read_direct_at(&self, _offset: usize, _writer: &mut VmWriter) -> Result<usize> {
|
||||
return_errno_with_message!(
|
||||
Errno::ESPIPE,
|
||||
"pseudo inodes cannot be read at a specific offset"
|
||||
);
|
||||
}
|
||||
|
||||
fn write_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
|
||||
return_errno_with_message!(
|
||||
Errno::ESPIPE,
|
||||
"pseudo inodes cannot be written at a specific offset"
|
||||
);
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
|
||||
return_errno_with_message!(
|
||||
Errno::ESPIPE,
|
||||
"pseudo inodes cannot be written at a specific offset"
|
||||
);
|
||||
}
|
||||
|
||||
fn fs(&self) -> Arc<dyn FileSystem> {
|
||||
self.fs.upgrade().unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ use ostd::{
|
|||
|
||||
use super::{memfd::MemfdInode, xattr::RamXattr, *};
|
||||
use crate::{
|
||||
events::IoEvents,
|
||||
fs::{
|
||||
device::Device,
|
||||
inode_handle::FileIo,
|
||||
|
|
@ -25,13 +24,13 @@ use crate::{
|
|||
registry::{FsProperties, FsType},
|
||||
utils::{
|
||||
mkmod, AccessMode, CStr256, CachePage, DirentVisitor, Extension, FallocMode,
|
||||
FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata, MknodType,
|
||||
FileSystem, FsFlags, Inode, InodeIo, InodeMode, InodeType, Metadata, MknodType,
|
||||
PageCache, PageCacheBackend, Permission, StatusFlags, SuperBlock, SymbolicLink,
|
||||
XattrName, XattrNamespace, XattrSetFlags,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
process::{signal::PollHandle, Gid, Uid},
|
||||
process::{Gid, Uid},
|
||||
time::clocks::RealTimeCoarseClock,
|
||||
vm::vmo::Vmo,
|
||||
};
|
||||
|
|
@ -539,14 +538,13 @@ impl PageCacheBackend for RamInode {
|
|||
}
|
||||
}
|
||||
|
||||
impl Inode for RamInode {
|
||||
fn page_cache(&self) -> Option<Arc<Vmo>> {
|
||||
self.inner
|
||||
.as_file()
|
||||
.map(|page_cache| page_cache.pages().clone())
|
||||
}
|
||||
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
impl InodeIo for RamInode {
|
||||
fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
let read_len = match &self.inner {
|
||||
Inner::File(page_cache) => {
|
||||
let (offset, read_len) = {
|
||||
|
|
@ -567,11 +565,12 @@ impl Inode for RamInode {
|
|||
Ok(read_len)
|
||||
}
|
||||
|
||||
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
self.read_at(offset, writer)
|
||||
}
|
||||
|
||||
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
fn write_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
reader: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
let written_len = match self.typ {
|
||||
InodeType::File => {
|
||||
let page_cache = self.inner.as_file().unwrap();
|
||||
|
|
@ -600,9 +599,13 @@ impl Inode for RamInode {
|
|||
};
|
||||
Ok(written_len)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
self.write_at(offset, reader)
|
||||
impl Inode for RamInode {
|
||||
fn page_cache(&self) -> Option<Arc<Vmo>> {
|
||||
self.inner
|
||||
.as_file()
|
||||
.map(|page_cache| page_cache.pages().clone())
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
|
|
@ -1139,11 +1142,6 @@ impl Inode for RamInode {
|
|||
}
|
||||
}
|
||||
|
||||
fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents {
|
||||
let events = IoEvents::IN | IoEvents::OUT;
|
||||
events & mask
|
||||
}
|
||||
|
||||
fn fs(&self) -> Arc<dyn FileSystem> {
|
||||
Weak::upgrade(&self.fs).unwrap()
|
||||
}
|
||||
|
|
@ -1180,17 +1178,6 @@ impl Inode for RamInode {
|
|||
}
|
||||
}
|
||||
|
||||
fn ioctl(&self, _cmd: IoctlCmd, _arg: usize) -> Result<i32> {
|
||||
return_errno_with_message!(Errno::ENOTTY, "ioctl is not supported");
|
||||
}
|
||||
|
||||
fn is_seekable(&self) -> bool {
|
||||
!matches!(
|
||||
self.typ,
|
||||
InodeType::NamedPipe | InodeType::CharDevice | InodeType::Dir | InodeType::Socket
|
||||
)
|
||||
}
|
||||
|
||||
fn extension(&self) -> Option<&Extension> {
|
||||
Some(&self.extension)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ use crate::{
|
|||
tmpfs::TmpFs,
|
||||
utils::{
|
||||
chmod, mkmod, AccessMode, CachePage, CreationFlags, Extension, FallocMode, FileSystem,
|
||||
Inode, InodeMode, InodeType, IoctlCmd, Metadata, OpenArgs, PageCacheBackend, SeekFrom,
|
||||
StatusFlags, XattrName, XattrNamespace, XattrSetFlags,
|
||||
Inode, InodeIo, InodeMode, InodeType, IoctlCmd, Metadata, OpenArgs, PageCacheBackend,
|
||||
SeekFrom, StatusFlags, XattrName, XattrNamespace, XattrSetFlags,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -107,40 +107,20 @@ impl PageCacheBackend for MemfdInode {
|
|||
}
|
||||
|
||||
#[inherit_methods(from = "self.inode")]
|
||||
impl Inode for MemfdInode {
|
||||
fn metadata(&self) -> Metadata;
|
||||
fn size(&self) -> usize;
|
||||
fn atime(&self) -> Duration;
|
||||
fn set_atime(&self, time: Duration);
|
||||
fn mtime(&self) -> Duration;
|
||||
fn set_mtime(&self, time: Duration);
|
||||
fn ctime(&self) -> Duration;
|
||||
fn set_ctime(&self, time: Duration);
|
||||
fn ino(&self) -> u64;
|
||||
fn type_(&self) -> InodeType;
|
||||
fn mode(&self) -> Result<InodeMode>;
|
||||
fn owner(&self) -> Result<Uid>;
|
||||
fn set_owner(&self, uid: Uid) -> Result<()>;
|
||||
fn group(&self) -> Result<Gid>;
|
||||
fn set_group(&self, gid: Gid) -> Result<()>;
|
||||
fn page_cache(&self) -> Option<Arc<Vmo>>;
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize>;
|
||||
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize>;
|
||||
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize>;
|
||||
fn poll(&self, mask: IoEvents, poller: Option<&mut PollHandle>) -> IoEvents;
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32>;
|
||||
fn extension(&self) -> Option<&Extension>;
|
||||
fn set_xattr(
|
||||
impl InodeIo for MemfdInode {
|
||||
fn read_at(
|
||||
&self,
|
||||
name: XattrName,
|
||||
value_reader: &mut VmReader,
|
||||
flags: XattrSetFlags,
|
||||
) -> Result<()>;
|
||||
fn get_xattr(&self, name: XattrName, value_writer: &mut VmWriter) -> Result<usize>;
|
||||
fn list_xattr(&self, namespace: XattrNamespace, list_writer: &mut VmWriter) -> Result<usize>;
|
||||
fn remove_xattr(&self, name: XattrName) -> Result<()>;
|
||||
offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize>;
|
||||
|
||||
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
fn write_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
reader: &mut VmReader,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
if !reader.has_remain() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
|
@ -173,8 +153,38 @@ impl Inode for MemfdInode {
|
|||
}
|
||||
}
|
||||
|
||||
self.inode.write_at(offset, reader)
|
||||
self.inode.write_at(offset, reader, status_flags)
|
||||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.inode")]
|
||||
impl Inode for MemfdInode {
|
||||
fn metadata(&self) -> Metadata;
|
||||
fn size(&self) -> usize;
|
||||
fn atime(&self) -> Duration;
|
||||
fn set_atime(&self, time: Duration);
|
||||
fn mtime(&self) -> Duration;
|
||||
fn set_mtime(&self, time: Duration);
|
||||
fn ctime(&self) -> Duration;
|
||||
fn set_ctime(&self, time: Duration);
|
||||
fn ino(&self) -> u64;
|
||||
fn type_(&self) -> InodeType;
|
||||
fn mode(&self) -> Result<InodeMode>;
|
||||
fn owner(&self) -> Result<Uid>;
|
||||
fn set_owner(&self, uid: Uid) -> Result<()>;
|
||||
fn group(&self) -> Result<Gid>;
|
||||
fn set_group(&self, gid: Gid) -> Result<()>;
|
||||
fn page_cache(&self) -> Option<Arc<Vmo>>;
|
||||
fn extension(&self) -> Option<&Extension>;
|
||||
fn set_xattr(
|
||||
&self,
|
||||
name: XattrName,
|
||||
value_reader: &mut VmReader,
|
||||
flags: XattrSetFlags,
|
||||
) -> Result<()>;
|
||||
fn get_xattr(&self, name: XattrName, value_writer: &mut VmWriter) -> Result<usize>;
|
||||
fn list_xattr(&self, namespace: XattrNamespace, list_writer: &mut VmWriter) -> Result<usize>;
|
||||
fn remove_xattr(&self, name: XattrName) -> Result<()>;
|
||||
|
||||
fn resize(&self, new_size: usize) -> Result<()> {
|
||||
let seals = self.seals.lock();
|
||||
|
|
@ -337,8 +347,9 @@ impl MemfdFile {
|
|||
}
|
||||
|
||||
impl Pollable for MemfdFile {
|
||||
fn poll(&self, mask: IoEvents, poller: Option<&mut PollHandle>) -> IoEvents {
|
||||
self.memfd_inode.poll(mask, poller)
|
||||
fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents {
|
||||
let events = IoEvents::IN | IoEvents::OUT;
|
||||
events & mask
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -357,13 +368,16 @@ impl FileLike for MemfdFile {
|
|||
return_errno_with_message!(Errno::EBADF, "the file is not opened readable");
|
||||
}
|
||||
|
||||
self.memfd_inode.read_at(offset, writer)
|
||||
self.memfd_inode
|
||||
.read_at(offset, writer, self.status_flags())
|
||||
}
|
||||
|
||||
fn write(&self, reader: &mut VmReader) -> Result<usize> {
|
||||
let mut offset = self.offset.lock();
|
||||
|
||||
if self.status_flags().contains(StatusFlags::O_APPEND) {
|
||||
// FIXME: `O_APPEND` should ensure that new content is appended even if another process
|
||||
// is writing to the file concurrently.
|
||||
*offset = self.memfd_inode.size();
|
||||
}
|
||||
|
||||
|
|
@ -378,12 +392,14 @@ impl FileLike for MemfdFile {
|
|||
return_errno_with_message!(Errno::EBADF, "the file is not opened writable");
|
||||
}
|
||||
|
||||
if self.status_flags().contains(StatusFlags::O_APPEND) {
|
||||
// If the file has the O_APPEND flag, the offset is ignored
|
||||
let status_flags = self.status_flags();
|
||||
if status_flags.contains(StatusFlags::O_APPEND) {
|
||||
// If the file has the `O_APPEND` flag, the offset is ignored.
|
||||
// FIXME: `O_APPEND` should ensure that new content is appended even if another process
|
||||
// is writing to the file concurrently.
|
||||
offset = self.memfd_inode.size();
|
||||
}
|
||||
|
||||
self.memfd_inode.write_at(offset, reader)
|
||||
self.memfd_inode.write_at(offset, reader, status_flags)
|
||||
}
|
||||
|
||||
fn resize(&self, new_size: usize) -> Result<()> {
|
||||
|
|
@ -442,12 +458,12 @@ impl FileLike for MemfdFile {
|
|||
Ok(Mappable::Inode(self.memfd_inode.clone()))
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
fn ioctl(&self, _cmd: IoctlCmd, _arg: usize) -> Result<i32> {
|
||||
if self.rights.is_empty() {
|
||||
return_errno_with_message!(Errno::EBADF, "the file is opened as a path");
|
||||
}
|
||||
|
||||
self.memfd_inode.ioctl(cmd, arg)
|
||||
return_errno_with_message!(Errno::ENOTTY, "ioctl is not supported");
|
||||
}
|
||||
|
||||
fn inode(&self) -> &Arc<dyn Inode> {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use ostd::{
|
|||
use crate::{
|
||||
fs::{
|
||||
sysfs::{self, fs::SysFs},
|
||||
utils::{mkmod, DirentVisitor, FileSystem, InodeType},
|
||||
utils::{mkmod, DirentVisitor, FileSystem, InodeType, StatusFlags},
|
||||
},
|
||||
prelude::*,
|
||||
time::clocks::init_for_ktest as time_init_for_ktest,
|
||||
|
|
@ -367,7 +367,7 @@ fn test_sysfs_read_attr() {
|
|||
let mut buf = [0u8; 64];
|
||||
let mut writer = VmWriter::from(&mut buf[..]).to_fallible();
|
||||
let bytes_read = r_attr_inode
|
||||
.read_at(0, &mut writer)
|
||||
.read_at(0, &mut writer, StatusFlags::empty())
|
||||
.expect("read_at failed");
|
||||
|
||||
assert!(bytes_read > 0);
|
||||
|
|
@ -376,7 +376,7 @@ fn test_sysfs_read_attr() {
|
|||
|
||||
// Reading a directory should fail (expect EINVAL as per inode.rs)
|
||||
let mut writer = VmWriter::from(&mut buf[..]).to_fallible(); // Reset writer
|
||||
let result = leaf1_dir_inode.read_at(0, &mut writer);
|
||||
let result = leaf1_dir_inode.read_at(0, &mut writer, StatusFlags::empty());
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
|
|
@ -401,7 +401,7 @@ fn test_sysfs_write_attr() {
|
|||
let new_val = "new_value";
|
||||
let mut reader = VmReader::from(new_val.as_bytes()).to_fallible();
|
||||
let bytes_written = rw_attr_inode
|
||||
.write_at(0, &mut reader)
|
||||
.write_at(0, &mut reader, StatusFlags::empty())
|
||||
.expect("write_at failed");
|
||||
assert_eq!(bytes_written, new_val.len());
|
||||
|
||||
|
|
@ -409,19 +409,19 @@ fn test_sysfs_write_attr() {
|
|||
let mut buf = [0u8; 64];
|
||||
let mut writer = VmWriter::from(&mut buf[..]).to_fallible();
|
||||
let bytes_read = rw_attr_inode
|
||||
.read_at(0, &mut writer)
|
||||
.read_at(0, &mut writer, StatusFlags::empty())
|
||||
.expect("read_at failed");
|
||||
let content = core::str::from_utf8(&buf[..bytes_read]).unwrap();
|
||||
assert_eq!(content, new_val);
|
||||
|
||||
// Write to r_attr1 (should fail - EIO expected from underlying PermissionDenied)
|
||||
let mut reader = VmReader::from("attempt_write".as_bytes()).to_fallible();
|
||||
let result = r_attr_inode.write_at(0, &mut reader);
|
||||
let result = r_attr_inode.write_at(0, &mut reader, StatusFlags::empty());
|
||||
assert!(result.is_err());
|
||||
|
||||
// Writing to a directory should fail (expect EINVAL as per inode.rs)
|
||||
let mut reader = VmReader::from("attempt_write".as_bytes()).to_fallible();
|
||||
let result = leaf1_dir_inode.write_at(0, &mut reader);
|
||||
let result = leaf1_dir_inode.write_at(0, &mut reader, StatusFlags::empty());
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,10 @@ use core2::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult,
|
|||
use ostd::task::Task;
|
||||
|
||||
use super::{
|
||||
AccessMode, DirentVisitor, FallocMode, FileSystem, InodeMode, IoctlCmd, XattrName,
|
||||
XattrNamespace, XattrSetFlags,
|
||||
AccessMode, DirentVisitor, FallocMode, FileSystem, InodeMode, XattrName, XattrNamespace,
|
||||
XattrSetFlags,
|
||||
};
|
||||
use crate::{
|
||||
events::IoEvents,
|
||||
fs::{
|
||||
device::{Device, DeviceType},
|
||||
inode_handle::FileIo,
|
||||
|
|
@ -21,10 +20,7 @@ use crate::{
|
|||
utils::StatusFlags,
|
||||
},
|
||||
prelude::*,
|
||||
process::{
|
||||
credentials::capabilities::CapSet, posix_thread::AsPosixThread, signal::PollHandle, Gid,
|
||||
Uid,
|
||||
},
|
||||
process::{credentials::capabilities::CapSet, posix_thread::AsPosixThread, Gid, Uid},
|
||||
time::clocks::RealTimeCoarseClock,
|
||||
vm::vmo::Vmo,
|
||||
};
|
||||
|
|
@ -56,6 +52,10 @@ impl InodeType {
|
|||
*self == InodeType::BlockDevice || *self == InodeType::CharDevice
|
||||
}
|
||||
|
||||
pub fn is_seekable(&self) -> bool {
|
||||
*self != InodeType::NamedPipe && *self != Self::Socket
|
||||
}
|
||||
|
||||
/// Parse the inode type in the `mode` from syscall, and convert it into `InodeType`.
|
||||
pub fn from_raw_mode(mut mode: u16) -> Result<Self> {
|
||||
const TYPE_MASK: u16 = 0o170000;
|
||||
|
|
@ -243,7 +243,29 @@ impl From<Arc<dyn Device>> for MknodType {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Inode: Any + Sync + Send {
|
||||
/// I/O operations in an [`Inode`].
|
||||
///
|
||||
/// This abstracts the common I/O operations used by both [`Inode`] (for regular files) and
|
||||
/// [`FileIo`] (for special files).
|
||||
pub trait InodeIo {
|
||||
/// Reads data from the file into the given `VmWriter`.
|
||||
fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
writer: &mut VmWriter,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize>;
|
||||
|
||||
/// Writes data from the given `VmReader` into the file.
|
||||
fn write_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
reader: &mut VmReader,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<usize>;
|
||||
}
|
||||
|
||||
pub trait Inode: Any + InodeIo + Send + Sync {
|
||||
fn size(&self) -> usize;
|
||||
|
||||
fn resize(&self, new_size: usize) -> Result<()>;
|
||||
|
|
@ -282,22 +304,6 @@ pub trait Inode: Any + Sync + Send {
|
|||
None
|
||||
}
|
||||
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
|
||||
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
|
||||
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
|
||||
fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> {
|
||||
Err(Error::new(Errno::ENOTDIR))
|
||||
}
|
||||
|
|
@ -346,10 +352,6 @@ pub trait Inode: Any + Sync + Send {
|
|||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
|
||||
fn sync_all(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -364,11 +366,6 @@ pub trait Inode: Any + Sync + Send {
|
|||
return_errno!(Errno::EOPNOTSUPP);
|
||||
}
|
||||
|
||||
fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents {
|
||||
let events = IoEvents::IN | IoEvents::OUT;
|
||||
events & mask
|
||||
}
|
||||
|
||||
fn fs(&self) -> Arc<dyn FileSystem>;
|
||||
|
||||
/// Returns whether a VFS dentry for this inode should be put into the dentry cache.
|
||||
|
|
@ -392,10 +389,6 @@ pub trait Inode: Any + Sync + Send {
|
|||
true
|
||||
}
|
||||
|
||||
fn is_seekable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Get the extension of this inode
|
||||
fn extension(&self) -> Option<&Extension> {
|
||||
None
|
||||
|
|
@ -503,22 +496,22 @@ impl dyn Inode {
|
|||
|
||||
pub fn read_bytes_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
let mut writer = VmWriter::from(buf).to_fallible();
|
||||
self.read_at(offset, &mut writer)
|
||||
self.read_at(offset, &mut writer, StatusFlags::empty())
|
||||
}
|
||||
|
||||
pub fn write_bytes_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
||||
let mut reader = VmReader::from(buf).to_fallible();
|
||||
self.write_at(offset, &mut reader)
|
||||
self.write_at(offset, &mut reader, StatusFlags::empty())
|
||||
}
|
||||
|
||||
pub fn read_bytes_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
let mut writer = VmWriter::from(buf).to_fallible();
|
||||
self.read_direct_at(offset, &mut writer)
|
||||
self.read_at(offset, &mut writer, StatusFlags::O_DIRECT)
|
||||
}
|
||||
|
||||
pub fn write_bytes_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
||||
let mut reader = VmReader::from(buf).to_fallible();
|
||||
self.write_direct_at(offset, &mut reader)
|
||||
self.write_at(offset, &mut reader, StatusFlags::O_DIRECT)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -533,7 +526,7 @@ impl Write for InodeWriter<'_> {
|
|||
let mut reader = VmReader::from(buf).to_fallible();
|
||||
let write_len = self
|
||||
.inner
|
||||
.write_at(self.offset, &mut reader)
|
||||
.write_at(self.offset, &mut reader, StatusFlags::empty())
|
||||
.map_err(|_| IoError::new(IoErrorKind::WriteZero, "failed to write buffer"))?;
|
||||
self.offset += write_len;
|
||||
Ok(write_len)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ pub use falloc_mode::FallocMode;
|
|||
pub use file_creation_mask::{AtomicFileCreationMask, FileCreationMask};
|
||||
pub use flock::{FlockItem, FlockList, FlockType};
|
||||
pub use fs::{FileSystem, FsFlags, SuperBlock};
|
||||
pub use inode::{Extension, Inode, InodeType, Metadata, MknodType, Permission, SymbolicLink};
|
||||
pub use inode::{
|
||||
Extension, Inode, InodeIo, InodeType, Metadata, MknodType, Permission, SymbolicLink,
|
||||
};
|
||||
pub use inode_mode::InodeMode;
|
||||
pub(crate) use inode_mode::{chmod, mkmod, perms_to_mask, who_and_perms_to_mask, who_to_mask};
|
||||
pub use ioctl::IoctlCmd;
|
||||
|
|
|
|||
|
|
@ -13,18 +13,17 @@ use aster_systree::{
|
|||
SysAttr, SysBranchNode, SysNode, SysNodeId, SysNodeType, SysObj, SysStr, SysSymlink,
|
||||
};
|
||||
|
||||
use super::InodeIo;
|
||||
use crate::{
|
||||
events::IoEvents,
|
||||
fs::{
|
||||
inode_handle::FileIo,
|
||||
utils::{
|
||||
mkmod, AccessMode, DirentVisitor, FallocMode, FileSystem, Inode, InodeMode, InodeType,
|
||||
IoctlCmd, Metadata, MknodType, StatusFlags, SymbolicLink,
|
||||
Metadata, MknodType, StatusFlags, SymbolicLink,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
process::{signal::PollHandle, Gid, Uid},
|
||||
return_errno, return_errno_with_message,
|
||||
process::{Gid, Uid},
|
||||
time::{clocks::RealTimeCoarseClock, Clock},
|
||||
};
|
||||
|
||||
|
|
@ -279,6 +278,42 @@ pub(in crate::fs) enum SysTreeNodeKind {
|
|||
Symlink(Arc<dyn SysSymlink>),
|
||||
}
|
||||
|
||||
impl<KInode: SysTreeInodeTy + Send + Sync + 'static> InodeIo for KInode {
|
||||
default fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
buf: &mut VmWriter,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
let SysTreeNodeKind::Attr(attr, leaf) = &self.node_kind() else {
|
||||
return Err(Error::new(Errno::EINVAL));
|
||||
};
|
||||
|
||||
let len = leaf.read_attr_at(attr.name(), offset, buf)?;
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
default fn write_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
buf: &mut VmReader,
|
||||
_status_flags: StatusFlags,
|
||||
) -> Result<usize> {
|
||||
let SysTreeNodeKind::Attr(attr, leaf) = &self.node_kind() else {
|
||||
return Err(Error::new(Errno::EINVAL));
|
||||
};
|
||||
|
||||
let len = if offset == 0 {
|
||||
leaf.write_attr(attr.name(), buf)?
|
||||
} else {
|
||||
leaf.write_attr_at(attr.name(), offset, buf)?
|
||||
};
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<KInode: SysTreeInodeTy + Send + Sync + 'static> Inode for KInode {
|
||||
default fn type_(&self) -> InodeType {
|
||||
self.metadata().type_
|
||||
|
|
@ -354,38 +389,6 @@ impl<KInode: SysTreeInodeTy + Send + Sync + 'static> Inode for KInode {
|
|||
None
|
||||
}
|
||||
|
||||
default fn read_at(&self, offset: usize, buf: &mut VmWriter) -> Result<usize> {
|
||||
self.read_direct_at(offset, buf)
|
||||
}
|
||||
|
||||
default fn read_direct_at(&self, offset: usize, buf: &mut VmWriter) -> Result<usize> {
|
||||
let SysTreeNodeKind::Attr(attr, leaf) = &self.node_kind() else {
|
||||
return Err(Error::new(Errno::EINVAL));
|
||||
};
|
||||
|
||||
let len = leaf.read_attr_at(attr.name(), offset, buf)?;
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
default fn write_at(&self, offset: usize, buf: &mut VmReader) -> Result<usize> {
|
||||
self.write_direct_at(offset, buf)
|
||||
}
|
||||
|
||||
default fn write_direct_at(&self, offset: usize, buf: &mut VmReader) -> Result<usize> {
|
||||
let SysTreeNodeKind::Attr(attr, leaf) = &self.node_kind() else {
|
||||
return Err(Error::new(Errno::EINVAL));
|
||||
};
|
||||
|
||||
let len = if offset == 0 {
|
||||
leaf.write_attr(attr.name(), buf)?
|
||||
} else {
|
||||
leaf.write_attr_at(attr.name(), offset, buf)?
|
||||
};
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
default fn create(
|
||||
&self,
|
||||
name: &str,
|
||||
|
|
@ -561,10 +564,6 @@ impl<KInode: SysTreeInodeTy + Send + Sync + 'static> Inode for KInode {
|
|||
None
|
||||
}
|
||||
|
||||
default fn ioctl(&self, _cmd: IoctlCmd, _arg: usize) -> Result<i32> {
|
||||
Err(Error::new(Errno::ENOTTY))
|
||||
}
|
||||
|
||||
default fn sync_all(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -577,19 +576,6 @@ impl<KInode: SysTreeInodeTy + Send + Sync + 'static> Inode for KInode {
|
|||
Err(Error::new(Errno::EOPNOTSUPP))
|
||||
}
|
||||
|
||||
default fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents {
|
||||
let mut events = IoEvents::empty();
|
||||
if let SysTreeNodeKind::Attr(attr, _) = &self.node_kind() {
|
||||
if attr.perms().can_read() {
|
||||
events |= IoEvents::IN;
|
||||
}
|
||||
if attr.perms().can_write() {
|
||||
events |= IoEvents::OUT;
|
||||
}
|
||||
}
|
||||
events & mask
|
||||
}
|
||||
|
||||
default fn is_dentry_cacheable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue