block, virtio-devices: Support request submission in batch

Cache and batch IO requests after parsing all
items in the queue, improving performance—especially
for small block sizes—by reducing per-request overhead.

Introduced two methods in the AsyncIo trait for batch
submission, with implementation in the raw disk backend.
This method should be called during/after parsing all block IO requests
in the available queue. If the batch submission is not enabled, by
default it does the old way of submitting requests.

Signed-off-by: Bo Chen <bchen@crusoe.ai>
Signed-off-by: Muminul Islam <muislam@microsoft.com>
This commit is contained in:
Muminul Islam
2025-08-13 00:43:36 +00:00
committed by Bo Chen
parent 67ab81874a
commit 245bce23fa
3 changed files with 81 additions and 10 deletions

View File

@@ -167,6 +167,8 @@ impl BlockEpollHandler {
fn process_queue_submit(&mut self) -> Result<()> {
let queue = &mut self.queue;
let mut batch_requests = Vec::new();
let mut batch_inflight_requests = Vec::new();
while let Some(mut desc_chain) = queue.pop_descriptor_chain(self.mem.memory()) {
let mut request = Request::parse(&mut desc_chain, self.access_platform.as_ref())
@@ -236,11 +238,21 @@ impl BlockEpollHandler {
if let Ok(ExecuteAsync {
async_complete: true,
..
batch_request,
}) = result
{
self.inflight_requests
.push_back((desc_chain.head_index(), request));
if let Some(batch_request) = batch_request {
match batch_request.request_type {
RequestType::In | RequestType::Out => batch_requests.push(batch_request),
_ => {
unreachable!(
"Unexpected batch request type: {:?}",
request.request_type
)
}
}
}
batch_inflight_requests.push((desc_chain.head_index(), request));
} else {
let status = match result {
Ok(_) => VIRTIO_BLK_S_OK,
@@ -266,6 +278,31 @@ impl BlockEpollHandler {
}
}
match self.disk_image.submit_batch_requests(&batch_requests) {
Ok(()) => {
self.inflight_requests.extend(batch_inflight_requests);
}
Err(e) => {
// If batch submission fails, report VIRTIO_BLK_S_IOERR for all requests.
for (user_data, request) in batch_inflight_requests {
warn!(
"Request failed with batch submission: {:x?} {:?}",
request, e
);
let desc_index = user_data;
let mem = self.mem.memory();
mem.write_obj(VIRTIO_BLK_S_IOERR as u8, request.status_addr)
.map_err(Error::RequestStatus)?;
queue
.add_used(mem.deref(), desc_index, 0)
.map_err(Error::QueueAddUsed)?;
queue
.enable_notification(mem.deref())
.map_err(Error::QueueEnableNotification)?;
}
}
}
Ok(())
}