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 <contact@gjolly.fr>
This commit is contained in:
Gauthier Jolly 2025-05-28 21:52:10 +02:00 committed by Rob Bradford
parent 2bc8d51a60
commit 3d78662498

View file

@ -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)