mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices: block: Surface virtqueue iterator errors to the worker
queue.iter() errors used to be swallowed by handle_queue_iterator_error(), which marked the device as NEEDS_RESET and returned Ok so the worker kept running while disabled. spawn_virtio_thread now does the NEEDS_RESET marking when the worker exits with an error. Propagate the iterator error as Error::QueueIterator and escalate it to EpollHelperError::HandleEvent in process_queue_submit_and_signal so the worker exits. Per request errors stay logged. Drop the now unused handle_queue_iterator_error helper. No functional change for the guest. NEEDS_RESET is still set and the config interrupt is still raised on virtqueue corruption. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
committed by
Rob Bradford
parent
6669ec1b86
commit
0597e72974
@@ -50,7 +50,7 @@ use super::{
|
||||
};
|
||||
use crate::seccomp_filters::Thread;
|
||||
use crate::thread_helper::spawn_virtio_thread;
|
||||
use crate::{GuestMemoryMmap, VirtioInterrupt, device_needs_reset, mark_device_needs_reset};
|
||||
use crate::{GuestMemoryMmap, VirtioInterrupt, device_needs_reset};
|
||||
|
||||
const SECTOR_SHIFT: u8 = 9;
|
||||
pub const SECTOR_SIZE: u64 = 0x01 << SECTOR_SHIFT;
|
||||
@@ -207,20 +207,6 @@ impl BlockEpollHandler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_queue_iterator_error(&mut self, err: &virtio_queue::Error) {
|
||||
// The guest submitted a corrupted VirtQ request, and the error
|
||||
// was logged during queue processing. Ignoring it would let the
|
||||
// guest keep spamming the VMM with bad requests and trigger
|
||||
// excessive error logging, so mark the device as NEEDS_RESET to
|
||||
// stop request processing (see self.needs_reset() usage) until
|
||||
// the guest resets and reactivates the device.
|
||||
mark_device_needs_reset(
|
||||
&self.device_status,
|
||||
self.interrupt_cb.as_ref(),
|
||||
format_args!("virtqueue error: {err:?}"),
|
||||
);
|
||||
}
|
||||
|
||||
fn process_queue_submit(&mut self) -> Result<()> {
|
||||
if self.needs_reset() {
|
||||
return Ok(());
|
||||
@@ -238,15 +224,13 @@ impl BlockEpollHandler {
|
||||
break;
|
||||
}
|
||||
processed += 1;
|
||||
let mut desc_chain = match queue.iter(self.mem.memory()) {
|
||||
Ok(mut iter) => match iter.next() {
|
||||
Some(c) => c,
|
||||
None => break,
|
||||
},
|
||||
Err(err) => {
|
||||
self.handle_queue_iterator_error(&err);
|
||||
return Ok(());
|
||||
}
|
||||
let mut desc_chain = match queue
|
||||
.iter(self.mem.memory())
|
||||
.map_err(Error::QueueIterator)?
|
||||
.next()
|
||||
{
|
||||
Some(c) => c,
|
||||
None => break,
|
||||
};
|
||||
let mut request = Request::parse(&mut desc_chain, self.access_platform.as_deref())
|
||||
.map_err(Error::RequestParsing)?;
|
||||
@@ -408,9 +392,20 @@ impl BlockEpollHandler {
|
||||
}
|
||||
|
||||
fn process_queue_submit_and_signal(&mut self) -> result::Result<(), EpollHelperError> {
|
||||
// Per-request errors are logged but non-device fatal.
|
||||
if let Err(e) = self.process_queue_submit() {
|
||||
warn!("Failed to process queue (submit): {e:?}");
|
||||
match self.process_queue_submit() {
|
||||
Ok(()) => {}
|
||||
Err(e @ Error::QueueIterator(_)) => {
|
||||
// Iterator errors mean the guest virtqueue itself is corrupted.
|
||||
// Surface the failure so the worker exits and spawn_virtio_thread
|
||||
// marks the device as NEEDS_RESET.
|
||||
return Err(EpollHelperError::HandleEvent(anyhow!(
|
||||
"Failed to process queue (submit): {e:?}"
|
||||
)));
|
||||
}
|
||||
Err(e) => {
|
||||
// Per-request errors are logged but non-device fatal.
|
||||
warn!("Failed to process queue (submit): {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
self.try_signal_used_queue()
|
||||
|
||||
Reference in New Issue
Block a user