From 3d786624988ed50de1e53b616e887b0eec3c605d Mon Sep 17 00:00:00 2001 From: Gauthier Jolly Date: Wed, 28 May 2025 21:52:10 +0200 Subject: [PATCH] block: virtio-blk: report IO errors to the guest Instead of exiting on IO errors, report the errors to the guest with VIRTIO_BLK_S_IOERR. For example, the guest kernel will log something similar to this if the nbd behind /dev/vdc is unexpectedly disconnected: [ 166.033957] I/O error, dev vdc, sector 264 op 0x1:(WRITE) flags 0x9800 phys_seg 1 prio class 2 [ 166.035083] Aborting journal on device vdc-8. [ 166.037307] Buffer I/O error on dev vdc, logical block 9, lost sync page write [ 166.038471] JBD2: I/O error when updating journal superblock for vdc-8. [...] [ 174.234470] EXT4-fs (vdc): I/O error while writing superblock In case the rootfs is not located on the affected block device, this will not crash the guest. Fixes: #6995 Signed-off-by: Gauthier Jolly --- virtio-devices/src/block.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/virtio-devices/src/block.rs b/virtio-devices/src/block.rs index fc99649da..1589cda02 100644 --- a/virtio-devices/src/block.rs +++ b/virtio-devices/src/block.rs @@ -212,22 +212,29 @@ impl BlockEpollHandler { request.set_writeback(self.writeback.load(Ordering::Acquire)); - if request - .execute_async( - desc_chain.memory(), - self.disk_nsectors, - self.disk_image.as_mut(), - &self.serial, - desc_chain.head_index() as u64, - ) - .map_err(Error::RequestExecuting)? - { + let result = request.execute_async( + desc_chain.memory(), + self.disk_nsectors, + self.disk_image.as_mut(), + &self.serial, + desc_chain.head_index() as u64, + ); + + if let Ok(true) = result { self.inflight_requests .push_back((desc_chain.head_index(), request)); } else { + let status = match result { + Ok(_) => VIRTIO_BLK_S_OK, + Err(e) => { + warn!("Request failed: {:x?} {:?}", request, e); + VIRTIO_BLK_S_IOERR + } + }; + desc_chain .memory() - .write_obj(VIRTIO_BLK_S_OK as u8, request.status_addr) + .write_obj(status as u8, request.status_addr) .map_err(Error::RequestStatus)?; // If no asynchronous operation has been submitted, we can @@ -389,12 +396,12 @@ impl BlockEpollHandler { (VIRTIO_BLK_S_OK as u8, result as u32) } else { - error!( + warn!( "Request failed: {:x?} {:?}", request, io::Error::from_raw_os_error(-result) ); - return Err(Error::AsyncRequestFailure); + (VIRTIO_BLK_S_IOERR as u8, 0) }; mem.write_obj(status, request.status_addr)