Implement flush for virtio-blk

This commit is contained in:
Cautreoxit
2024-10-28 21:49:25 +08:00
committed by Tate, Hongliang Tian
parent 197d53c0ab
commit 32572e22d9
2 changed files with 66 additions and 1 deletions

View File

@ -83,6 +83,18 @@ impl dyn BlockDevice {
let bio = create_bio_from_frame(BioType::Write, bid, frame); let bio = create_bio_from_frame(BioType::Write, bid, frame);
bio.submit(self) bio.submit(self)
} }
/// Issues a sync request
pub fn sync(&self) -> Result<BioStatus, BioEnqueueError> {
let bio = Bio::new(
BioType::Flush,
Sid::from(Bid::from_offset(0)),
vec![],
Some(general_complete_fn),
);
let status = bio.submit_and_wait(self)?;
Ok(status)
}
} }
impl VmIo for dyn BlockDevice { impl VmIo for dyn BlockDevice {

View File

@ -63,7 +63,8 @@ impl BlockDevice {
match request.type_() { match request.type_() {
BioType::Read => self.device.read(request), BioType::Read => self.device.read(request),
BioType::Write => self.device.write(request), BioType::Write => self.device.write(request),
BioType::Flush | BioType::Discard => todo!(), BioType::Flush => self.device.flush(request),
BioType::Discard => todo!(),
} }
} }
@ -406,6 +407,58 @@ impl DeviceInner {
} }
} }
/// Flushes any cached data from the guest to the persistent storage on the host.
/// This will be ignored if the device doesn't support the `VIRTIO_BLK_F_FLUSH` feature.
fn flush(&self, bio_request: BioRequest) {
if self.transport.lock().device_features() & BlockFeatures::FLUSH.bits() == 0 {
bio_request.bios().for_each(|bio| {
bio.complete(BioStatus::Complete);
});
return;
}
let id = self.id_allocator.disable_irq().lock().alloc().unwrap();
let req_slice = {
let req_slice = DmaStreamSlice::new(&self.block_requests, id * REQ_SIZE, REQ_SIZE);
let req = BlockReq {
type_: ReqType::Flush as _,
reserved: 0,
sector: bio_request.sid_range().start.to_raw(),
};
req_slice.write_val(0, &req).unwrap();
req_slice.sync().unwrap();
req_slice
};
let resp_slice = {
let resp_slice = DmaStreamSlice::new(&self.block_responses, id * RESP_SIZE, RESP_SIZE);
resp_slice.write_val(0, &BlockResp::default()).unwrap();
resp_slice
};
let num_used_descs = 1;
loop {
let mut queue = self.queue.disable_irq().lock();
if num_used_descs > queue.available_desc() {
continue;
}
let token = queue
.add_dma_buf(&[&req_slice], &[&resp_slice])
.expect("add queue failed");
if queue.should_notify() {
queue.notify();
}
// Records the submitted request
let submitted_request = SubmittedRequest::new(id as u16, bio_request, Vec::new());
self.submitted_requests
.disable_irq()
.lock()
.insert(token, submitted_request);
return;
}
}
/// Performs DMA mapping for the segments in bio request. /// Performs DMA mapping for the segments in bio request.
fn dma_stream_map(bio_request: &BioRequest) -> Vec<(DmaStream, usize, usize)> { fn dma_stream_map(bio_request: &BioRequest) -> Vec<(DmaStream, usize, usize)> {
let dma_direction = match bio_request.type_() { let dma_direction = match bio_request.type_() {