diff --git a/Cargo.lock b/Cargo.lock index 4188a8166..32b84e77e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,6 +70,7 @@ checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" name = "aster-block" version = "0.1.0" dependencies = [ + "align_ext", "aster-frame", "aster-util", "bitflags 1.3.2", diff --git a/framework/aster-frame/src/vm/frame.rs b/framework/aster-frame/src/vm/frame.rs index aaaf7ac09..aa41b579a 100644 --- a/framework/aster-frame/src/vm/frame.rs +++ b/framework/aster-frame/src/vm/frame.rs @@ -314,17 +314,17 @@ impl Drop for VmFrame { /// ``` #[derive(Debug, Clone)] pub struct VmSegment { - inner: Arc, + inner: VmSegmentInner, range: Range, } -#[derive(Debug)] -struct Inner { - start_frame_index: Paddr, +#[derive(Debug, Clone)] +struct VmSegmentInner { + start_frame_index: Arc, nframes: usize, } -impl Inner { +impl VmSegmentInner { /// Creates the inner part of 'VmSegment'. /// /// # Safety @@ -333,14 +333,13 @@ impl Inner { unsafe fn new(paddr: Paddr, nframes: usize, flags: VmFrameFlags) -> Self { assert_eq!(paddr % PAGE_SIZE, 0); Self { - start_frame_index: (paddr / PAGE_SIZE).bitor(flags.bits), + start_frame_index: Arc::new((paddr / PAGE_SIZE).bitor(flags.bits)), nframes, } } fn start_frame_index(&self) -> usize { - self.start_frame_index - .bitand(VmFrameFlags::all().bits().not()) + (*self.start_frame_index).bitand(VmFrameFlags::all().bits().not()) } fn start_paddr(&self) -> Paddr { @@ -364,7 +363,7 @@ impl VmSegment { /// as part of either a `VmFrame` or `VmSegment`. pub(crate) unsafe fn new(paddr: Paddr, nframes: usize, flags: VmFrameFlags) -> Self { Self { - inner: Arc::new(Inner::new(paddr, nframes, flags)), + inner: VmSegmentInner::new(paddr, nframes, flags), range: 0..nframes, } } @@ -407,7 +406,7 @@ impl VmSegment { } fn need_dealloc(&self) -> bool { - (self.inner.start_frame_index & VmFrameFlags::NEED_DEALLOC.bits()) != 0 + (*self.inner.start_frame_index & VmFrameFlags::NEED_DEALLOC.bits()) != 0 } fn start_frame_index(&self) -> usize { @@ -459,7 +458,7 @@ impl VmIo for VmSegment { impl Drop for VmSegment { fn drop(&mut self) { - if self.need_dealloc() && Arc::strong_count(&self.inner) == 1 { + if self.need_dealloc() && Arc::strong_count(&self.inner.start_frame_index) == 1 { // Safety: the range of contiguous page frames is valid. unsafe { frame_allocator::dealloc_contiguous( @@ -471,6 +470,18 @@ impl Drop for VmSegment { } } +impl From for VmSegment { + fn from(frame: VmFrame) -> Self { + Self { + inner: VmSegmentInner { + start_frame_index: frame.frame_index.clone(), + nframes: 1, + }, + range: 0..1, + } + } +} + /// VmReader is a reader for reading data from a contiguous range of memory. /// /// # Example diff --git a/kernel/comps/block/Cargo.toml b/kernel/comps/block/Cargo.toml index 342719d13..f5bbfc822 100644 --- a/kernel/comps/block/Cargo.toml +++ b/kernel/comps/block/Cargo.toml @@ -10,6 +10,7 @@ bitflags = "1.3" spin = "0.9.4" pod = { git = "https://github.com/asterinas/pod", rev = "d7dba56" } aster-frame = { path = "../../../framework/aster-frame" } +align_ext = { path = "../../../framework/libs/align_ext" } aster-util = { path = "../../libs/aster-util" } int-to-c-enum = { path = "../../libs/int-to-c-enum" } component = { path = "../../libs/comp-sys/component" } diff --git a/kernel/comps/block/src/bio.rs b/kernel/comps/block/src/bio.rs index 4f24dd49b..b2e24690d 100644 --- a/kernel/comps/block/src/bio.rs +++ b/kernel/comps/block/src/bio.rs @@ -1,5 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 +use align_ext::AlignExt; use aster_frame::{ sync::WaitQueue, vm::{VmFrame, VmReader, VmSegment, VmWriter}, @@ -358,29 +359,27 @@ pub enum BioStatus { #[derive(Debug, Clone)] pub struct BioSegment { /// The contiguous pages on which this segment resides. - pages: Pages, - /// The offset (in bytes) relative to the first page. + pages: VmSegment, + /// The starting offset (in bytes) within the first page. + /// The offset should always be aligned to the sector size and + /// must not exceed the size of a single page. offset: AlignedUsize, - // The length (in bytes), may cross pages. + /// The total length (in bytes). + /// The length can span multiple pages and should be aligned to + /// the sector size. len: AlignedUsize, } const SECTOR_SIZE: u16 = super::SECTOR_SIZE as u16; -#[derive(Debug, Clone)] -enum Pages { - Frame(VmFrame), - Segment(VmSegment), -} - impl<'a> BioSegment { /// Constructs a new `BioSegment` from `VmSegment`. pub fn from_segment(segment: VmSegment, offset: usize, len: usize) -> Self { assert!(offset + len <= segment.nbytes()); Self { - pages: Pages::Segment(segment), - offset: AlignedUsize::::new(offset).unwrap(), + pages: segment.range(frame_range(&(offset..offset + len))), + offset: AlignedUsize::::new(offset % super::BLOCK_SIZE).unwrap(), len: AlignedUsize::::new(len).unwrap(), } } @@ -390,7 +389,7 @@ impl<'a> BioSegment { assert!(offset + len <= super::BLOCK_SIZE); Self { - pages: Pages::Frame(frame), + pages: VmSegment::from(frame), offset: AlignedUsize::::new(offset).unwrap(), len: AlignedUsize::::new(len).unwrap(), } @@ -406,25 +405,39 @@ impl<'a> BioSegment { self.len.value() } + /// Returns the offset (in bytes) within the first page. + pub fn offset(&self) -> usize { + self.offset.value() + } + + /// Returns the contiguous pages on which this segment resides. + pub fn pages(&self) -> &VmSegment { + &self.pages + } + /// Returns a reader to read data from it. pub fn reader(&'a self) -> VmReader<'a> { - let reader = match &self.pages { - Pages::Segment(segment) => segment.reader(), - Pages::Frame(frame) => frame.reader(), - }; - reader.skip(self.offset.value()).limit(self.len.value()) + self.pages + .reader() + .skip(self.offset.value()) + .limit(self.len.value()) } /// Returns a writer to write data into it. pub fn writer(&'a self) -> VmWriter<'a> { - let writer = match &self.pages { - Pages::Segment(segment) => segment.writer(), - Pages::Frame(frame) => frame.writer(), - }; - writer.skip(self.offset.value()).limit(self.len.value()) + self.pages + .writer() + .skip(self.offset.value()) + .limit(self.len.value()) } } +fn frame_range(byte_range: &Range) -> Range { + let start = byte_range.start.align_down(super::BLOCK_SIZE); + let end = byte_range.end.align_up(super::BLOCK_SIZE); + (start / super::BLOCK_SIZE)..(end / super::BLOCK_SIZE) +} + /// An aligned unsigned integer number. /// /// An instance of `AlignedUsize` is guaranteed to have a value that is a multiple