mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-25 10:23:23 +00:00
Improve the read/write efficiency of Vmo
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
f4ea23b72c
commit
25b7007ffa
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user