mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 08:53:29 +00:00
Limit the number of segments in single bio request
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
a883b65187
commit
c6aa9f9ee8
@ -212,6 +212,9 @@ impl From<aster_block::bio::BioEnqueueError> for Error {
|
||||
aster_block::bio::BioEnqueueError::Refused => {
|
||||
Error::with_message(Errno::EBUSY, "Refuse to enqueue the bio")
|
||||
}
|
||||
aster_block::bio::BioEnqueueError::TooBig => {
|
||||
Error::with_message(Errno::EINVAL, "Bio is too big")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +95,10 @@ mod test {
|
||||
bio.complete(BioStatus::Complete);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn max_nr_segments_per_bio(&self) -> usize {
|
||||
usize::MAX
|
||||
}
|
||||
}
|
||||
/// Exfat disk image
|
||||
static EXFAT_IMAGE: &[u8] = include_bytes!("../../../../../regression/build/exfat.img");
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -43,7 +43,11 @@ impl BlockDevice {
|
||||
|
||||
let block_device = Arc::new(Self {
|
||||
device,
|
||||
queue: BioRequestSingleQueue::new(),
|
||||
// Each bio request includes an additional 1 request and 1 response descriptor,
|
||||
// therefore this upper bound is set to (QUEUE_SIZE - 2).
|
||||
queue: BioRequestSingleQueue::with_max_nr_segments_per_bio(
|
||||
(DeviceInner::QUEUE_SIZE - 2) as usize,
|
||||
),
|
||||
});
|
||||
|
||||
aster_block::register_device(device_id, block_device);
|
||||
@ -74,6 +78,10 @@ impl aster_block::BlockDevice for BlockDevice {
|
||||
fn enqueue(&self, bio: SubmittedBio) -> Result<(), BioEnqueueError> {
|
||||
self.queue.enqueue(bio)
|
||||
}
|
||||
|
||||
fn max_nr_segments_per_bio(&self) -> usize {
|
||||
self.queue.max_nr_segments_per_bio()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
Reference in New Issue
Block a user