Fix Segment::from_unused which lacks a panic

This commit is contained in:
Zhang Junyang
2025-01-08 10:11:27 +08:00
committed by Tate, Hongliang Tian
parent b59cd9cea2
commit 1bbed2e077
3 changed files with 30 additions and 10 deletions

View File

@ -104,6 +104,7 @@ impl FrameAllocOptions {
start * PAGE_SIZE..start * PAGE_SIZE + nframes * PAGE_SIZE, start * PAGE_SIZE..start * PAGE_SIZE + nframes * PAGE_SIZE,
metadata_fn, metadata_fn,
) )
.unwrap()
}) })
.ok_or(Error::NoMemory)?; .ok_or(Error::NoMemory)?;

View File

@ -480,6 +480,7 @@ pub(crate) fn init() -> Segment<MetaPageMeta> {
Segment::from_unused(meta_pages..meta_pages + nr_meta_pages * PAGE_SIZE, |_| { Segment::from_unused(meta_pages..meta_pages + nr_meta_pages * PAGE_SIZE, |_| {
MetaPageMeta {} MetaPageMeta {}
}) })
.unwrap()
} }
fn alloc_meta_frames(tot_nr_frames: usize) -> (usize, Paddr) { fn alloc_meta_frames(tot_nr_frames: usize) -> (usize, Paddr) {

View File

@ -2,9 +2,13 @@
//! A contiguous range of frames. //! A contiguous range of frames.
use core::{mem::ManuallyDrop, ops::Range}; use core::{mem::ManuallyDrop, ops::Range, sync::atomic::Ordering};
use super::{inc_frame_ref_count, meta::AnyFrameMeta, Frame}; use super::{
inc_frame_ref_count,
meta::{AnyFrameMeta, GetFrameError},
Frame,
};
use crate::mm::{AnyUFrameMeta, Paddr, PAGE_SIZE}; use crate::mm::{AnyUFrameMeta, Paddr, PAGE_SIZE};
/// A contiguous range of homogeneous physical memory frames. /// A contiguous range of homogeneous physical memory frames.
@ -67,22 +71,36 @@ impl<M: AnyFrameMeta> Segment<M> {
/// The closure receives the physical address of the frame and returns the /// The closure receives the physical address of the frame and returns the
/// metadata, which is similar to [`core::array::from_fn`]. /// metadata, which is similar to [`core::array::from_fn`].
/// ///
/// It returns an error if:
/// - the physical address is invalid or not aligned;
/// - any of the frames cannot be created with a specific reason.
///
/// # Panics /// # Panics
/// ///
/// The function panics if: /// It panics if the range is empty.
/// - the physical address is invalid or not aligned; pub fn from_unused<F>(range: Range<Paddr>, mut metadata_fn: F) -> Result<Self, GetFrameError>
/// - any of the frames are already in use.
pub fn from_unused<F>(range: Range<Paddr>, mut metadata_fn: F) -> Self
where where
F: FnMut(Paddr) -> M, F: FnMut(Paddr) -> M,
{ {
for paddr in range.clone().step_by(PAGE_SIZE) { if range.start % PAGE_SIZE != 0 || range.end % PAGE_SIZE != 0 {
let _ = ManuallyDrop::new(Frame::<M>::from_unused(paddr, metadata_fn(paddr))); return Err(GetFrameError::NotAligned);
} }
Self { if range.end >= super::MAX_PADDR.load(Ordering::Relaxed) {
range, return Err(GetFrameError::OutOfBound);
}
assert!(range.start < range.end);
// Construct a segment early to recycle previously forgotten frames if
// the subsequent operations fails in the middle.
let mut segment = Self {
range: range.start..range.start,
_marker: core::marker::PhantomData, _marker: core::marker::PhantomData,
};
for paddr in range.step_by(PAGE_SIZE) {
let frame = Frame::<M>::from_unused(paddr, metadata_fn(paddr))?;
let _ = ManuallyDrop::new(frame);
segment.range.end = paddr + PAGE_SIZE;
} }
Ok(segment)
} }
} }