From 32572e22d9d9c7f49826a577484a0c57a6154f1e Mon Sep 17 00:00:00 2001 From: Cautreoxit Date: Mon, 28 Oct 2024 21:49:25 +0800 Subject: [PATCH] Implement flush for virtio-blk --- kernel/comps/block/src/impl_block_device.rs | 12 ++++ .../comps/virtio/src/device/block/device.rs | 55 ++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/kernel/comps/block/src/impl_block_device.rs b/kernel/comps/block/src/impl_block_device.rs index 64d6bd299..c8e7bf56a 100644 --- a/kernel/comps/block/src/impl_block_device.rs +++ b/kernel/comps/block/src/impl_block_device.rs @@ -83,6 +83,18 @@ impl dyn BlockDevice { let bio = create_bio_from_frame(BioType::Write, bid, frame); bio.submit(self) } + + /// Issues a sync request + pub fn sync(&self) -> Result { + 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 { diff --git a/kernel/comps/virtio/src/device/block/device.rs b/kernel/comps/virtio/src/device/block/device.rs index fefd2d4a0..b0116a6cf 100644 --- a/kernel/comps/virtio/src/device/block/device.rs +++ b/kernel/comps/virtio/src/device/block/device.rs @@ -63,7 +63,8 @@ impl BlockDevice { match request.type_() { BioType::Read => self.device.read(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. fn dma_stream_map(bio_request: &BioRequest) -> Vec<(DmaStream, usize, usize)> { let dma_direction = match bio_request.type_() {