mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-24 01:43:22 +00:00
Refactor all io APIs of vfs based on VmReader
/VmWriter
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
837c7bebb6
commit
dce796cdde
@ -5,7 +5,10 @@
|
||||
use core::{mem::size_of, ops::Range};
|
||||
|
||||
use crate::{
|
||||
mm::{kspace::LINEAR_MAPPING_BASE_VADDR, paddr_to_vaddr, HasPaddr, Paddr, Vaddr, VmIo},
|
||||
mm::{
|
||||
kspace::LINEAR_MAPPING_BASE_VADDR, paddr_to_vaddr, HasPaddr, Paddr, Vaddr, VmIo, VmReader,
|
||||
VmWriter,
|
||||
},
|
||||
Error, Pod, Result,
|
||||
};
|
||||
|
||||
@ -17,25 +20,27 @@ pub struct IoMem {
|
||||
}
|
||||
|
||||
impl VmIo for IoMem {
|
||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> crate::Result<()> {
|
||||
self.check_range(offset, buf.len())?;
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> crate::Result<()> {
|
||||
let read_len = writer.avail();
|
||||
self.check_range(offset, read_len)?;
|
||||
unsafe {
|
||||
core::ptr::copy(
|
||||
(self.virtual_address + offset) as *const u8,
|
||||
buf.as_mut_ptr(),
|
||||
buf.len(),
|
||||
writer.cursor(),
|
||||
read_len,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> crate::Result<()> {
|
||||
self.check_range(offset, buf.len())?;
|
||||
fn write(&self, offset: usize, reader: &mut VmReader) -> crate::Result<()> {
|
||||
let write_len = reader.remain();
|
||||
self.check_range(offset, write_len)?;
|
||||
unsafe {
|
||||
core::ptr::copy(
|
||||
buf.as_ptr(),
|
||||
reader.cursor(),
|
||||
(self.virtual_address + offset) as *mut u8,
|
||||
buf.len(),
|
||||
write_len,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
|
@ -167,12 +167,12 @@ impl Drop for DmaCoherentInner {
|
||||
}
|
||||
|
||||
impl VmIo for DmaCoherent {
|
||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
||||
self.inner.vm_segment.read_bytes(offset, buf)
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> {
|
||||
self.inner.vm_segment.read(offset, writer)
|
||||
}
|
||||
|
||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
||||
self.inner.vm_segment.write_bytes(offset, buf)
|
||||
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> {
|
||||
self.inner.vm_segment.write(offset, reader)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,19 +202,19 @@ impl Drop for DmaStreamInner {
|
||||
|
||||
impl VmIo for DmaStream {
|
||||
/// Reads data into the buffer.
|
||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<(), Error> {
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<(), Error> {
|
||||
if self.inner.direction == DmaDirection::ToDevice {
|
||||
return Err(Error::AccessDenied);
|
||||
}
|
||||
self.inner.vm_segment.read_bytes(offset, buf)
|
||||
self.inner.vm_segment.read(offset, writer)
|
||||
}
|
||||
|
||||
/// Writes data from the buffer.
|
||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<(), Error> {
|
||||
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<(), Error> {
|
||||
if self.inner.direction == DmaDirection::FromDevice {
|
||||
return Err(Error::AccessDenied);
|
||||
}
|
||||
self.inner.vm_segment.write_bytes(offset, buf)
|
||||
self.inner.vm_segment.write(offset, reader)
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,18 +282,18 @@ impl<'a> DmaStreamSlice<'a> {
|
||||
}
|
||||
|
||||
impl VmIo for DmaStreamSlice<'_> {
|
||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<(), Error> {
|
||||
if buf.len() + offset > self.len {
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<(), Error> {
|
||||
if writer.avail() + offset > self.len {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
self.stream.read_bytes(self.offset + offset, buf)
|
||||
self.stream.read(self.offset + offset, writer)
|
||||
}
|
||||
|
||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<(), Error> {
|
||||
if buf.len() + offset > self.len {
|
||||
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<(), Error> {
|
||||
if reader.remain() + offset > self.len {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
self.stream.write_bytes(self.offset + offset, buf)
|
||||
self.stream.write(self.offset + offset, reader)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
mm::{
|
||||
io::{VmIo, VmReader, VmWriter},
|
||||
io::{FallibleVmRead, FallibleVmWrite, VmIo, VmReader, VmWriter},
|
||||
paddr_to_vaddr, HasPaddr, Paddr, PAGE_SIZE,
|
||||
},
|
||||
Error, Result,
|
||||
@ -133,42 +133,55 @@ impl<'a> Frame {
|
||||
}
|
||||
|
||||
impl VmIo for Frame {
|
||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> {
|
||||
let read_len = writer.avail().min(self.size().saturating_sub(offset));
|
||||
// Do bound check with potential integer overflow in mind
|
||||
let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?;
|
||||
let max_offset = offset.checked_add(read_len).ok_or(Error::Overflow)?;
|
||||
if max_offset > self.size() {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
let len = self.reader().skip(offset).read(&mut buf.into());
|
||||
debug_assert!(len == buf.len());
|
||||
let len = self
|
||||
.reader()
|
||||
.skip(offset)
|
||||
.read_fallible(writer)
|
||||
.map_err(|(e, _)| e)?;
|
||||
debug_assert!(len == read_len);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
||||
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> {
|
||||
let write_len = reader.remain().min(self.size().saturating_sub(offset));
|
||||
// Do bound check with potential integer overflow in mind
|
||||
let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?;
|
||||
let max_offset = offset.checked_add(write_len).ok_or(Error::Overflow)?;
|
||||
if max_offset > self.size() {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
let len = self.writer().skip(offset).write(&mut buf.into());
|
||||
debug_assert!(len == buf.len());
|
||||
let len = self
|
||||
.writer()
|
||||
.skip(offset)
|
||||
.write_fallible(reader)
|
||||
.map_err(|(e, _)| e)?;
|
||||
debug_assert!(len == write_len);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl VmIo for alloc::vec::Vec<Frame> {
|
||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> {
|
||||
// Do bound check with potential integer overflow in mind
|
||||
let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?;
|
||||
let max_offset = offset.checked_add(writer.avail()).ok_or(Error::Overflow)?;
|
||||
if max_offset > self.len() * PAGE_SIZE {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
|
||||
let num_skip_pages = offset / PAGE_SIZE;
|
||||
let mut start = offset % PAGE_SIZE;
|
||||
let mut buf_writer: VmWriter<Infallible> = buf.into();
|
||||
for frame in self.iter().skip(num_skip_pages) {
|
||||
let read_len = frame.reader().skip(start).read(&mut buf_writer);
|
||||
let read_len = frame
|
||||
.reader()
|
||||
.skip(start)
|
||||
.read_fallible(writer)
|
||||
.map_err(|(e, _)| e)?;
|
||||
if read_len == 0 {
|
||||
break;
|
||||
}
|
||||
@ -177,18 +190,21 @@ impl VmIo for alloc::vec::Vec<Frame> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
||||
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> {
|
||||
// Do bound check with potential integer overflow in mind
|
||||
let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?;
|
||||
let max_offset = offset.checked_add(reader.remain()).ok_or(Error::Overflow)?;
|
||||
if max_offset > self.len() * PAGE_SIZE {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
|
||||
let num_skip_pages = offset / PAGE_SIZE;
|
||||
let mut start = offset % PAGE_SIZE;
|
||||
let mut buf_reader: VmReader<Infallible> = buf.into();
|
||||
for frame in self.iter().skip(num_skip_pages) {
|
||||
let write_len = frame.writer().skip(start).write(&mut buf_reader);
|
||||
let write_len = frame
|
||||
.writer()
|
||||
.skip(start)
|
||||
.write_fallible(reader)
|
||||
.map_err(|(e, _)| e)?;
|
||||
if write_len == 0 {
|
||||
break;
|
||||
}
|
||||
|
@ -9,7 +9,8 @@ use super::Frame;
|
||||
use crate::{
|
||||
mm::{
|
||||
page::{cont_pages::ContPages, meta::FrameMeta, Page},
|
||||
HasPaddr, Infallible, Paddr, VmIo, VmReader, VmWriter, PAGE_SIZE,
|
||||
FallibleVmRead, FallibleVmWrite, HasPaddr, Infallible, Paddr, VmIo, VmReader, VmWriter,
|
||||
PAGE_SIZE,
|
||||
},
|
||||
Error, Result,
|
||||
};
|
||||
@ -114,25 +115,35 @@ impl<'a> Segment {
|
||||
}
|
||||
|
||||
impl VmIo for Segment {
|
||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> {
|
||||
let read_len = writer.avail();
|
||||
// Do bound check with potential integer overflow in mind
|
||||
let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?;
|
||||
let max_offset = offset.checked_add(read_len).ok_or(Error::Overflow)?;
|
||||
if max_offset > self.nbytes() {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
let len = self.reader().skip(offset).read(&mut buf.into());
|
||||
debug_assert!(len == buf.len());
|
||||
let len = self
|
||||
.reader()
|
||||
.skip(offset)
|
||||
.read_fallible(writer)
|
||||
.map_err(|(e, _)| e)?;
|
||||
debug_assert!(len == read_len);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
||||
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> {
|
||||
let write_len = reader.remain();
|
||||
// Do bound check with potential integer overflow in mind
|
||||
let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?;
|
||||
let max_offset = offset.checked_add(reader.remain()).ok_or(Error::Overflow)?;
|
||||
if max_offset > self.nbytes() {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
let len = self.writer().skip(offset).write(&mut buf.into());
|
||||
debug_assert!(len == buf.len());
|
||||
let len = self
|
||||
.writer()
|
||||
.skip(offset)
|
||||
.write_fallible(reader)
|
||||
.map_err(|(e, _)| e)?;
|
||||
debug_assert!(len == write_len);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@
|
||||
//! user space, making it impossible to avoid data races). However, they may produce erroneous
|
||||
//! results, such as unexpected bytes being copied, but do not cause soundness problems.
|
||||
|
||||
use alloc::vec;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use align_ext::AlignExt;
|
||||
@ -69,14 +70,26 @@ use crate::{
|
||||
/// [`Segment`]: crate::mm::Segment
|
||||
/// [`Frame`]: crate::mm::Frame
|
||||
pub trait VmIo: Send + Sync {
|
||||
/// Reads requested data at a specified offset into a given `VmWriter`.
|
||||
///
|
||||
/// # No short reads
|
||||
///
|
||||
/// On success, the `writer` must be written with the requested data
|
||||
/// completely. If, for any reason, the requested data is only partially
|
||||
/// available, then the method shall return an error.
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()>;
|
||||
|
||||
/// Reads a specified number of bytes at a specified offset into a given buffer.
|
||||
///
|
||||
/// # No short reads
|
||||
///
|
||||
/// On success, the output `buf` must be filled with the requested data
|
||||
/// completely. If, for any reason, the requested data is only partially
|
||||
/// available, then the method shall return an error.
|
||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()>;
|
||||
/// Similar to [`read`].
|
||||
///
|
||||
/// [`read`]: VmIo::read
|
||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
||||
let mut writer = VmWriter::from(buf).to_fallible();
|
||||
self.read(offset, &mut writer)
|
||||
}
|
||||
|
||||
/// Reads a value of a specified type at a specified offset.
|
||||
fn read_val<T: Pod>(&self, offset: usize) -> Result<T> {
|
||||
@ -89,9 +102,9 @@ pub trait VmIo: Send + Sync {
|
||||
///
|
||||
/// # No short reads
|
||||
///
|
||||
/// Similar to [`read_bytes`].
|
||||
/// Similar to [`read`].
|
||||
///
|
||||
/// [`read_bytes`]: VmIo::read_bytes
|
||||
/// [`read`]: VmIo::read
|
||||
fn read_slice<T: Pod>(&self, offset: usize, slice: &mut [T]) -> Result<()> {
|
||||
let len_in_bytes = core::mem::size_of_val(slice);
|
||||
let ptr = slice as *mut [T] as *mut u8;
|
||||
@ -101,14 +114,26 @@ pub trait VmIo: Send + Sync {
|
||||
self.read_bytes(offset, buf)
|
||||
}
|
||||
|
||||
/// Writes all data from a given `VmReader` at a specified offset.
|
||||
///
|
||||
/// # No short writes
|
||||
///
|
||||
/// On success, the data from the `reader` must be read to the VM object entirely.
|
||||
/// If, for any reason, the input data can only be written partially,
|
||||
/// then the method shall return an error.
|
||||
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()>;
|
||||
|
||||
/// Writes a specified number of bytes from a given buffer at a specified offset.
|
||||
///
|
||||
/// # No short writes
|
||||
///
|
||||
/// On success, the input `buf` must be written to the VM object entirely.
|
||||
/// If, for any reason, the input data can only be written partially,
|
||||
/// then the method shall return an error.
|
||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()>;
|
||||
/// Similar to [`write`].
|
||||
///
|
||||
/// [`write`]: VmIo::write
|
||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
||||
let mut reader = VmReader::from(buf).to_fallible();
|
||||
self.write(offset, &mut reader)
|
||||
}
|
||||
|
||||
/// Writes a value of a specified type at a specified offset.
|
||||
fn write_val<T: Pod>(&self, offset: usize, new_val: &T) -> Result<()> {
|
||||
@ -120,9 +145,9 @@ pub trait VmIo: Send + Sync {
|
||||
///
|
||||
/// # No short write
|
||||
///
|
||||
/// Similar to [`write_bytes`].
|
||||
/// Similar to [`write`].
|
||||
///
|
||||
/// [`write_bytes`]: VmIo::write_bytes
|
||||
/// [`write`]: VmIo::write
|
||||
fn write_slice<T: Pod>(&self, offset: usize, slice: &[T]) -> Result<()> {
|
||||
let len_in_bytes = core::mem::size_of_val(slice);
|
||||
let ptr = slice as *const [T] as *const u8;
|
||||
@ -219,9 +244,11 @@ macro_rules! impl_vm_io_pointer {
|
||||
($typ:ty,$from:tt) => {
|
||||
#[inherit_methods(from = $from)]
|
||||
impl<T: VmIo> VmIo for $typ {
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()>;
|
||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()>;
|
||||
fn read_val<F: Pod>(&self, offset: usize) -> Result<F>;
|
||||
fn read_slice<F: Pod>(&self, offset: usize, slice: &mut [F]) -> Result<()>;
|
||||
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()>;
|
||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()>;
|
||||
fn write_val<F: Pod>(&self, offset: usize, new_val: &F) -> Result<()>;
|
||||
fn write_slice<F: Pod>(&self, offset: usize, slice: &[F]) -> Result<()>;
|
||||
@ -364,7 +391,7 @@ macro_rules! impl_read_fallible {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
// SAFETY: The source and destionation are subsets of memory ranges specified by
|
||||
// SAFETY: The source and destination are subsets of memory ranges specified by
|
||||
// the reader and writer, so they are either valid for reading and writing or in
|
||||
// user space.
|
||||
let copied_len = unsafe {
|
||||
@ -437,7 +464,7 @@ impl<'a> VmReader<'a, Infallible> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SAFETY: The source and destionation are subsets of memory ranges specified by the reader
|
||||
// SAFETY: The source and destination are subsets of memory ranges specified by the reader
|
||||
// and writer, so they are valid for reading and writing.
|
||||
unsafe {
|
||||
memcpy(writer.cursor, self.cursor, copy_len);
|
||||
@ -545,6 +572,25 @@ impl<'a> VmReader<'a, Fallible> {
|
||||
})?;
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
/// Collects all the remaining bytes into a `Vec<u8>`.
|
||||
///
|
||||
/// If the memory read failed, this method will return `Err`
|
||||
/// and the current reader's cursor remains pointing to
|
||||
/// the original starting position.
|
||||
pub fn collect(&mut self) -> Result<Vec<u8>> {
|
||||
let mut buf = vec![0u8; self.remain()];
|
||||
self.read_fallible(&mut buf.as_mut_slice().into())
|
||||
.map_err(|(err, copied_len)| {
|
||||
// SAFETY: The `copied_len` is the number of bytes read so far.
|
||||
// So the `cursor` can be moved back to the original position.
|
||||
unsafe {
|
||||
self.cursor = self.cursor.sub(copied_len);
|
||||
}
|
||||
err
|
||||
})?;
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Fallibility> VmReader<'a, Fallibility> {
|
||||
|
Reference in New Issue
Block a user