Improve the read/write efficiency of Vmo

This commit is contained in:
Chen Chengjun
2024-05-11 15:08:52 +08:00
committed by Tate, Hongliang Tian
parent f4ea23b72c
commit 25b7007ffa
3 changed files with 36 additions and 15 deletions

View File

@ -84,7 +84,7 @@ impl Vmo<Rights> {
/// The method requires the Write right. /// The method requires the Write right.
pub fn commit(&self, range: Range<usize>) -> Result<()> { pub fn commit(&self, range: Range<usize>) -> Result<()> {
self.check_rights(Rights::WRITE)?; self.check_rights(Rights::WRITE)?;
self.0.commit(range, false)?; self.0.commit_and_operate(&range, |_| {}, false)?;
Ok(()) Ok(())
} }

View File

@ -7,7 +7,7 @@ use core::ops::Range;
use align_ext::AlignExt; use align_ext::AlignExt;
use aster_frame::{ use aster_frame::{
collections::xarray::{CursorMut, XArray, XMark}, collections::xarray::{CursorMut, XArray, XMark},
vm::{VmAllocOptions, VmFrame, VmFrameVec, VmIo}, vm::{VmAllocOptions, VmFrame, VmReader, VmWriter},
}; };
use aster_rights::Rights; use aster_rights::Rights;
@ -301,27 +301,35 @@ impl Vmo_ {
}) })
} }
/// Commit a range of pages in the VMO, returns the pages in this range. /// Commit a range of pages in the VMO, and perform the operation
pub fn commit(&self, range: Range<usize>, will_write: bool) -> Result<VmFrameVec> { /// on each page in the range in turn.
pub fn commit_and_operate<F>(
&self,
range: &Range<usize>,
mut operate: F,
will_write: bool,
) -> Result<()>
where
F: FnMut(VmFrame),
{
self.pages.with(|pages, size| { self.pages.with(|pages, size| {
if range.end > size { if range.end > size {
return_errno_with_message!(Errno::EINVAL, "operated range exceeds the vmo size"); return_errno_with_message!(Errno::EINVAL, "operated range exceeds the vmo size");
} }
let raw_page_idx_range = get_page_idx_range(&range); let raw_page_idx_range = get_page_idx_range(range);
let page_idx_range = (raw_page_idx_range.start + self.page_idx_offset) let page_idx_range = (raw_page_idx_range.start + self.page_idx_offset)
..(raw_page_idx_range.end + self.page_idx_offset); ..(raw_page_idx_range.end + self.page_idx_offset);
let mut frames = VmFrameVec::new_with_capacity(page_idx_range.len());
let is_cow_vmo = pages.is_marked(VmoMark::CowVmo); let is_cow_vmo = pages.is_marked(VmoMark::CowVmo);
let mut cursor = pages.cursor_mut(page_idx_range.start as u64); let mut cursor = pages.cursor_mut(page_idx_range.start as u64);
for page_idx in page_idx_range { for page_idx in page_idx_range {
let committed_page = let committed_page =
self.commit_with_cursor(&mut cursor, is_cow_vmo, will_write)?; self.commit_with_cursor(&mut cursor, is_cow_vmo, will_write)?;
frames.push(committed_page); operate(committed_page);
cursor.next(); cursor.next();
} }
Ok(frames) Ok(())
}) })
} }
@ -337,18 +345,31 @@ impl Vmo_ {
pub fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> { pub fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
let read_len = buf.len(); let read_len = buf.len();
let read_range = offset..(offset + read_len); let read_range = offset..(offset + read_len);
let frames = self.commit(read_range, false)?; let mut read_offset = offset % PAGE_SIZE;
let read_offset = offset % PAGE_SIZE; let mut buf_writer: VmWriter = buf.into();
Ok(frames.read_bytes(read_offset, buf)?)
let read = move |page: VmFrame| {
page.reader().skip(read_offset).read(&mut buf_writer);
read_offset = 0;
};
self.commit_and_operate(&read_range, read, false)
} }
/// Write the specified amount of buffer content starting from the target offset in the VMO. /// Write the specified amount of buffer content starting from the target offset in the VMO.
pub fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> { pub fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
let write_len = buf.len(); let write_len = buf.len();
let write_range = offset..(offset + write_len); let write_range = offset..(offset + write_len);
let frames = self.commit(write_range.clone(), true)?; let mut write_offset = offset % PAGE_SIZE;
let write_offset = offset % PAGE_SIZE; let mut buf_reader: VmReader = buf.into();
frames.write_bytes(write_offset, buf)?;
let write = move |page: VmFrame| {
page.writer().skip(write_offset).write(&mut buf_reader);
write_offset = 0;
};
self.commit_and_operate(&write_range, write, true)?;
let is_cow_vmo = self.is_cow_vmo(); let is_cow_vmo = self.is_cow_vmo();
if let Some(pager) = &self.pager if let Some(pager) = &self.pager
&& !is_cow_vmo && !is_cow_vmo

View File

@ -84,7 +84,7 @@ impl<R: TRights> Vmo<TRightSet<R>> {
/// The method requires the Write right. /// The method requires the Write right.
#[require(R > Write)] #[require(R > Write)]
pub fn commit(&self, range: Range<usize>) -> Result<()> { pub fn commit(&self, range: Range<usize>) -> Result<()> {
self.0.commit(range, false)?; self.0.commit_and_operate(&range, |_| {}, false)?;
Ok(()) Ok(())
} }