Limit the number of segments in single bio request

This commit is contained in:
LI Qing
2024-06-04 16:26:36 +08:00
committed by Tate, Hongliang Tian
parent a883b65187
commit c6aa9f9ee8
6 changed files with 51 additions and 2 deletions

View File

@ -136,6 +136,8 @@ pub enum BioEnqueueError {
IsFull,
/// Refuse to enqueue the bio
Refused,
/// Too big bio
TooBig,
}
impl From<BioEnqueueError> for aster_frame::Error {

View File

@ -55,6 +55,8 @@ pub const SECTOR_SIZE: usize = 512;
pub trait BlockDevice: Send + Sync + Any + Debug {
/// Enqueues a new `SubmittedBio` to the block device.
fn enqueue(&self, bio: SubmittedBio) -> Result<(), BioEnqueueError>;
/// Returns the upper limit for the number of segments per bio.
fn max_nr_segments_per_bio(&self) -> usize;
}
impl dyn BlockDevice {

View File

@ -20,18 +20,30 @@ pub struct BioRequestSingleQueue {
queue: Mutex<VecDeque<BioRequest>>,
num_requests: AtomicUsize,
wait_queue: WaitQueue,
max_nr_segments_per_bio: usize,
}
impl BioRequestSingleQueue {
/// Creates an empty queue.
pub fn new() -> Self {
Self::with_max_nr_segments_per_bio(usize::MAX)
}
/// Creates an empty queue with the upper bound for the number of segments in a bio.
pub fn with_max_nr_segments_per_bio(max_nr_segments_per_bio: usize) -> Self {
Self {
queue: Mutex::new(VecDeque::new()),
num_requests: AtomicUsize::new(0),
wait_queue: WaitQueue::new(),
max_nr_segments_per_bio,
}
}
/// Returns the upper limit for the number of segments per bio.
pub fn max_nr_segments_per_bio(&self) -> usize {
self.max_nr_segments_per_bio
}
/// Returns the number of requests currently in this queue.
pub fn num_requests(&self) -> usize {
self.num_requests.load(Ordering::Relaxed)
@ -45,9 +57,15 @@ impl BioRequestSingleQueue {
///
/// This method will wake up the waiter if a new `BioRequest` is enqueued.
pub fn enqueue(&self, bio: SubmittedBio) -> Result<(), BioEnqueueError> {
if bio.segments().len() >= self.max_nr_segments_per_bio {
return Err(BioEnqueueError::TooBig);
}
let mut queue = self.queue.lock();
if let Some(request) = queue.front_mut() {
if request.can_merge(&bio) {
if request.can_merge(&bio)
&& request.num_segments() + bio.segments().len() <= self.max_nr_segments_per_bio
{
request.merge_bio(bio);
return Ok(());
}
@ -123,6 +141,8 @@ pub struct BioRequest {
type_: BioType,
/// The range of target sectors on the device
sid_range: Range<Sid>,
/// The number of segments
num_segments: usize,
/// The submitted bios
bios: VecDeque<SubmittedBio>,
}
@ -143,6 +163,11 @@ impl BioRequest {
self.bios.iter()
}
/// Returns the number of segments.
pub fn num_segments(&self) -> usize {
self.num_segments
}
/// Returns `true` if can merge the `SubmittedBio`, `false` otherwise.
pub fn can_merge(&self, rq_bio: &SubmittedBio) -> bool {
if rq_bio.type_() != self.type_ {
@ -163,6 +188,8 @@ impl BioRequest {
pub fn merge_bio(&mut self, rq_bio: SubmittedBio) {
assert!(self.can_merge(&rq_bio));
let rq_bio_nr_segments = rq_bio.segments().len();
if rq_bio.sid_range().start == self.sid_range.end {
self.sid_range.end = rq_bio.sid_range().end;
self.bios.push_back(rq_bio);
@ -170,6 +197,8 @@ impl BioRequest {
self.sid_range.start = rq_bio.sid_range().start;
self.bios.push_front(rq_bio);
}
self.num_segments += rq_bio_nr_segments;
}
}
@ -178,6 +207,7 @@ impl From<SubmittedBio> for BioRequest {
Self {
type_: bio.type_(),
sid_range: bio.sid_range().clone(),
num_segments: bio.segments().len(),
bios: {
let mut bios = VecDeque::with_capacity(1);
bios.push_front(bio);