From b1752994d597f2137f424952fa8fa7696a44e232 Mon Sep 17 00:00:00 2001 From: Bo Chen Date: Thu, 11 Aug 2022 18:30:13 -0700 Subject: [PATCH] virtio-devices: Report errors from EpollHelperHandler::handle_event Signed-off-by: Bo Chen --- virtio-devices/src/balloon.rs | 94 ++++++++++------- virtio-devices/src/block.rs | 70 ++++++++----- virtio-devices/src/console.rs | 111 ++++++++++++-------- virtio-devices/src/epoll_helper.rs | 21 ++-- virtio-devices/src/iommu.rs | 53 ++++++---- virtio-devices/src/mem.rs | 85 +++++++++------- virtio-devices/src/net.rs | 147 ++++++++++++++++----------- virtio-devices/src/pmem.rs | 34 ++++--- virtio-devices/src/rng.rs | 33 +++--- virtio-devices/src/vhost_user/mod.rs | 33 +++--- virtio-devices/src/vsock/device.rs | 105 ++++++++++--------- virtio-devices/src/vsock/mod.rs | 4 +- virtio-devices/src/watchdog.rs | 42 ++++---- 13 files changed, 502 insertions(+), 330 deletions(-) diff --git a/virtio-devices/src/balloon.rs b/virtio-devices/src/balloon.rs index 8aedf484c..976e823e4 100644 --- a/virtio-devices/src/balloon.rs +++ b/virtio-devices/src/balloon.rs @@ -18,6 +18,7 @@ use crate::{ VirtioDeviceType, VirtioInterrupt, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1, }; +use anyhow::anyhow; use libc::EFD_NONBLOCK; use seccompiler::SeccompAction; use std::io; @@ -330,14 +331,18 @@ impl BalloonEpollHandler { } impl EpollHelperHandler for BalloonEpollHandler { - fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { + fn handle_event( + &mut self, + _helper: &mut EpollHelper, + event: &epoll::Event, + ) -> result::Result<(), EpollHelperError> { let ev_type = event.data as u16; match ev_type { RESIZE_EVENT => { - if let Err(e) = self.resize_receiver.evt.read() { - error!("Failed to get resize event: {:?}", e); - return true; - } + self.resize_receiver.evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get resize event: {:?}", e)) + })?; + let mut signal_error = false; let r = { let mut config = self.config.lock().unwrap(); @@ -350,57 +355,78 @@ impl EpollHelperHandler for BalloonEpollHandler { Ok(()) } }; + let ret_err = anyhow!("{:?}", r); if let Err(e) = &r { // This error will send back to resize caller. error!("Handle resize event get error: {:?}", e); } + if let Err(e) = self.resize_receiver.send(r) { - error!("Sending \"resize\" generated error: {:?}", e); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Sending \"resize\" generated error: {:?}", + e + ))); } if signal_error { - return true; + return Err(EpollHelperError::HandleEvent(ret_err)); } } INFLATE_QUEUE_EVENT => { - if let Err(e) = self.inflate_queue_evt.read() { - error!("Failed to get inflate queue event: {:?}", e); - return true; - } else if let Err(e) = self.process_queue(0) { - error!("Failed to signal used inflate queue: {:?}", e); - return true; - } + self.inflate_queue_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to get inflate queue event: {:?}", + e + )) + })?; + self.process_queue(0).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used inflate queue: {:?}", + e + )) + })?; } DEFLATE_QUEUE_EVENT => { - if let Err(e) = self.deflate_queue_evt.read() { - error!("Failed to get deflate queue event: {:?}", e); - return true; - } else if let Err(e) = self.process_queue(1) { - error!("Failed to signal used deflate queue: {:?}", e); - return true; - } + self.deflate_queue_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to get deflate queue event: {:?}", + e + )) + })?; + self.process_queue(1).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used deflate queue: {:?}", + e + )) + })?; } REPORTING_QUEUE_EVENT => { if let Some(reporting_queue_evt) = self.reporting_queue_evt.as_ref() { - if let Err(e) = reporting_queue_evt.read() { - error!("Failed to get reporting queue event: {:?}", e); - return true; - } else if let Err(e) = self.process_reporting_queue(2) { - error!("Failed to signal used inflate queue: {:?}", e); - return true; - } + reporting_queue_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to get reporting queue event: {:?}", + e + )) + })?; + self.process_reporting_queue(2).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used inflate queue: {:?}", + e + )) + })?; } else { - error!("Invalid reporting queue event as no eventfd registered"); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Invalid reporting queue event as no eventfd registered" + ))); } } _ => { - error!("Unknown event for virtio-balloon"); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unknown event for virtio-balloon" + ))); } } - false + Ok(()) } } diff --git a/virtio-devices/src/block.rs b/virtio-devices/src/block.rs index e62f115a3..51726bc20 100644 --- a/virtio-devices/src/block.rs +++ b/virtio-devices/src/block.rs @@ -18,6 +18,7 @@ use crate::seccomp_filters::Thread; use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::VirtioInterrupt; +use anyhow::anyhow; use block_util::{ async_io::AsyncIo, async_io::AsyncIoError, async_io::DiskFile, build_disk_image_id, Request, RequestType, VirtioBlockConfig, @@ -277,14 +278,17 @@ impl BlockEpollHandler { } impl EpollHelperHandler for BlockEpollHandler { - fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { + fn handle_event( + &mut self, + _helper: &mut EpollHelper, + event: &epoll::Event, + ) -> result::Result<(), EpollHelperError> { let ev_type = event.data as u16; match ev_type { QUEUE_AVAIL_EVENT => { - if let Err(e) = self.queue_evt.read() { - error!("Failed to get queue event: {:?}", e); - return true; - } + self.queue_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get queue event: {:?}", e)) + })?; let rate_limit_reached = self.rate_limiter.as_ref().map_or(false, |r| r.is_blocked()); @@ -295,36 +299,43 @@ impl EpollHelperHandler for BlockEpollHandler { Ok(needs_notification) => { if needs_notification { if let Err(e) = self.signal_used_queue() { - error!("Failed to signal used queue: {:?}", e); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + ))); } } } Err(e) => { - error!("Failed to process queue (submit): {:?}", e); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Failed to process queue (submit): {:?}", + e + ))); } } } } COMPLETION_EVENT => { - if let Err(e) = self.disk_image.notifier().read() { - error!("Failed to get queue event: {:?}", e); - return true; - } + self.disk_image.notifier().read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get queue event: {:?}", e)) + })?; match self.process_queue_complete() { Ok(needs_notification) => { if needs_notification { if let Err(e) = self.signal_used_queue() { - error!("Failed to signal used queue: {:?}", e); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + ))); } } } Err(e) => { - error!("Failed to process queue (complete): {:?}", e); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Failed to process queue (complete): {:?}", + e + ))); } } } @@ -337,28 +348,35 @@ impl EpollHelperHandler for BlockEpollHandler { Ok(needs_notification) => { if needs_notification { if let Err(e) = self.signal_used_queue() { - error!("Failed to signal used queue: {:?}", e); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + ))); } } } Err(e) => { - error!("Failed to process queue (submit): {:?}", e); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Failed to process queue (submit): {:?}", + e + ))); } } } } else { - error!("Unexpected 'RATE_LIMITER_EVENT' when rate_limiter is not enabled."); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unexpected 'RATE_LIMITER_EVENT' when rate_limiter is not enabled." + ))); } } _ => { - error!("Unexpected event: {}", ev_type); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unexpected event: {}", + ev_type + ))); } } - false + Ok(()) } } diff --git a/virtio-devices/src/console.rs b/virtio-devices/src/console.rs index 38f4358e7..89f9e229b 100644 --- a/virtio-devices/src/console.rs +++ b/virtio-devices/src/console.rs @@ -11,6 +11,7 @@ use crate::seccomp_filters::Thread; use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::VirtioInterrupt; +use anyhow::anyhow; use libc::{EFD_NONBLOCK, TIOCGWINSZ}; use seccompiler::SeccompAction; use std::cmp; @@ -233,57 +234,76 @@ impl ConsoleEpollHandler { } impl EpollHelperHandler for ConsoleEpollHandler { - fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { + fn handle_event( + &mut self, + _helper: &mut EpollHelper, + event: &epoll::Event, + ) -> result::Result<(), EpollHelperError> { let ev_type = event.data as u16; match ev_type { INPUT_QUEUE_EVENT => { - if let Err(e) = self.input_queue_evt.read() { - error!("Failed to get queue event: {:?}", e); - return true; - } else if self.process_input_queue() { - if let Err(e) = self.signal_used_queue(0) { - error!("Failed to signal used queue: {:?}", e); - return true; - } + self.input_queue_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get queue event: {:?}", e)) + })?; + if self.process_input_queue() { + self.signal_used_queue(0).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + )) + })?; } } OUTPUT_QUEUE_EVENT => { - if let Err(e) = self.output_queue_evt.read() { - error!("Failed to get queue event: {:?}", e); - return true; - } else if self.process_output_queue() { - if let Err(e) = self.signal_used_queue(1) { - error!("Failed to signal used queue: {:?}", e); - return true; - } + self.output_queue_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get queue event: {:?}", e)) + })?; + if self.process_output_queue() { + self.signal_used_queue(1).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + )) + })?; } } INPUT_EVENT => { - if let Err(e) = self.input_evt.read() { - error!("Failed to get input event: {:?}", e); - return true; - } else if self.process_input_queue() { - if let Err(e) = self.signal_used_queue(0) { - error!("Failed to signal used queue: {:?}", e); - return true; - } + self.input_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get input event: {:?}", e)) + })?; + if self.process_input_queue() { + self.signal_used_queue(0).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + )) + })?; } } CONFIG_EVENT => { - if let Err(e) = self.config_evt.read() { - error!("Failed to get config event: {:?}", e); - return true; - } else if let Err(e) = self.interrupt_cb.trigger(VirtioInterruptType::Config) { - error!("Failed to signal console driver: {:?}", e); - return true; - } + self.config_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get config event: {:?}", e)) + })?; + self.interrupt_cb + .trigger(VirtioInterruptType::Config) + .map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal console driver: {:?}", + e + )) + })?; } RESIZE_EVENT => { - if let Err(e) = self.resize_pipe.as_ref().unwrap().read_exact(&mut [0]) { - error!("Failed to get resize event: {:?}", e); - return true; - } - + self.resize_pipe + .as_ref() + .unwrap() + .read_exact(&mut [0]) + .map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to get resize event: {:?}", + e + )) + })?; self.resizer.update_console_size(); } FILE_EVENT => { @@ -295,19 +315,22 @@ impl EpollHelperHandler for ConsoleEpollHandler { } if self.process_input_queue() { - if let Err(e) = self.signal_used_queue(0) { - error!("Failed to signal used queue: {:?}", e); - return true; - } + self.signal_used_queue(0).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + )) + })?; } } } _ => { - error!("Unknown event for virtio-console"); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unknown event for virtio-console" + ))); } } - false + Ok(()) } } diff --git a/virtio-devices/src/epoll_helper.rs b/virtio-devices/src/epoll_helper.rs index 2588ef0a0..844d991f6 100644 --- a/virtio-devices/src/epoll_helper.rs +++ b/virtio-devices/src/epoll_helper.rs @@ -13,6 +13,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Barrier}; use std::thread; +use thiserror::Error; use vmm_sys_util::eventfd::EventFd; pub struct EpollHelper { @@ -20,13 +21,20 @@ pub struct EpollHelper { epoll_file: File, } -#[derive(Debug)] +#[derive(Error, Debug)] pub enum EpollHelperError { + #[error("Failed to create Fd: {0}")] CreateFd(std::io::Error), + #[error("Failed to epoll_ctl: {0}")] Ctl(std::io::Error), + #[error("IO error: {0}")] IoError(std::io::Error), + #[error("Failed to epoll_wait: {0}")] Wait(std::io::Error), + #[error("Failed to get virtio-queue index: {0}")] QueueRingIndex(virtio_queue::Error), + #[error("Failed to handle virtio device events: {0}")] + HandleEvent(anyhow::Error), } pub const EPOLL_HELPER_EVENT_PAUSE: u16 = 0; @@ -34,8 +42,11 @@ pub const EPOLL_HELPER_EVENT_KILL: u16 = 1; pub const EPOLL_HELPER_EVENT_LAST: u16 = 15; pub trait EpollHelperHandler { - // Return true if the loop execution should be stopped - fn handle_event(&mut self, helper: &mut EpollHelper, event: &epoll::Event) -> bool; + fn handle_event( + &mut self, + helper: &mut EpollHelper, + event: &epoll::Event, + ) -> Result<(), EpollHelperError>; } impl EpollHelper { @@ -155,9 +166,7 @@ impl EpollHelper { let _ = self.pause_evt.read(); } _ => { - if handler.handle_event(self, event) { - return Ok(()); - } + handler.handle_event(self, event)?; } } } diff --git a/virtio-devices/src/iommu.rs b/virtio-devices/src/iommu.rs index 275c7e844..3d3d0deab 100644 --- a/virtio-devices/src/iommu.rs +++ b/virtio-devices/src/iommu.rs @@ -11,6 +11,7 @@ use crate::seccomp_filters::Thread; use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::{DmaRemapping, VirtioInterrupt, VirtioInterruptType}; +use anyhow::anyhow; use seccompiler::SeccompAction; use std::collections::BTreeMap; use std::fmt::{self, Display}; @@ -725,37 +726,49 @@ impl IommuEpollHandler { } impl EpollHelperHandler for IommuEpollHandler { - fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { + fn handle_event( + &mut self, + _helper: &mut EpollHelper, + event: &epoll::Event, + ) -> result::Result<(), EpollHelperError> { let ev_type = event.data as u16; match ev_type { REQUEST_Q_EVENT => { - if let Err(e) = self.queue_evts[0].read() { - error!("Failed to get queue event: {:?}", e); - return true; - } else if self.request_queue() { - if let Err(e) = self.signal_used_queue(0) { - error!("Failed to signal used queue: {:?}", e); - return true; - } + self.queue_evts[0].read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get queue event: {:?}", e)) + })?; + + if self.request_queue() { + self.signal_used_queue(0).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + )) + })?; } } EVENT_Q_EVENT => { - if let Err(e) = self.queue_evts[1].read() { - error!("Failed to get queue event: {:?}", e); - return true; - } else if self.event_queue() { - if let Err(e) = self.signal_used_queue(1) { - error!("Failed to signal used queue: {:?}", e); - return true; - } + self.queue_evts[1].read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get queue event: {:?}", e)) + })?; + + if self.event_queue() { + self.signal_used_queue(1).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + )) + })?; } } _ => { - error!("Unexpected event: {}", ev_type); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unexpected event: {}", + ev_type + ))); } } - false + Ok(()) } } diff --git a/virtio-devices/src/mem.rs b/virtio-devices/src/mem.rs index 523957391..f7cf82af0 100644 --- a/virtio-devices/src/mem.rs +++ b/virtio-devices/src/mem.rs @@ -724,54 +724,65 @@ impl MemEpollHandler { } impl EpollHelperHandler for MemEpollHandler { - fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { + fn handle_event( + &mut self, + _helper: &mut EpollHelper, + event: &epoll::Event, + ) -> result::Result<(), EpollHelperError> { let ev_type = event.data as u16; match ev_type { RESIZE_EVENT => { - if let Err(e) = self.resize.evt.read() { - error!("Failed to get resize event: {:?}", e); - return true; - } else { - let size = self.resize.size(); - let mut config = self.config.lock().unwrap(); - let mut signal_error = false; - let mut r = config.resize(size); - r = match r { - Err(e) => Err(e), - _ => match self.signal(VirtioInterruptType::Config) { - Err(e) => { - signal_error = true; - Err(Error::ResizeTriggerFail(e)) - } - _ => Ok(()), - }, - }; - if let Err(e) = self.resize.send(r) { - error!("Sending \"resize\" response: {:?}", e); - return true; - } - if signal_error { - return true; - } + self.resize.evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get resize event: {:?}", e)) + })?; + + let size = self.resize.size(); + let mut config = self.config.lock().unwrap(); + let mut signal_error = false; + let mut r = config.resize(size); + r = match r { + Err(e) => Err(e), + _ => match self.signal(VirtioInterruptType::Config) { + Err(e) => { + signal_error = true; + Err(Error::ResizeTriggerFail(e)) + } + _ => Ok(()), + }, + }; + let ret_err = anyhow!("{:?}", r); + if let Err(e) = self.resize.send(r) { + return Err(EpollHelperError::HandleEvent(anyhow!( + "Sending \"resize\" response: {:?}", + e + ))); + } + if signal_error { + return Err(EpollHelperError::HandleEvent(anyhow!(ret_err))); } } QUEUE_AVAIL_EVENT => { - if let Err(e) = self.queue_evt.read() { - error!("Failed to get queue event: {:?}", e); - return true; - } else if self.process_queue() { - if let Err(e) = self.signal(VirtioInterruptType::Queue(0)) { - error!("Failed to signal used queue: {:?}", e); - return true; - } + self.queue_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get queue event: {:?}", e)) + })?; + + if self.process_queue() { + self.signal(VirtioInterruptType::Queue(0)).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + )) + })?; } } _ => { - error!("Unexpected event: {}", ev_type); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unexpected event: {}", + ev_type + ))); } } - false + Ok(()) } } diff --git a/virtio-devices/src/net.rs b/virtio-devices/src/net.rs index 9ca979653..4bcfda506 100644 --- a/virtio-devices/src/net.rs +++ b/virtio-devices/src/net.rs @@ -15,6 +15,7 @@ use crate::seccomp_filters::Thread; use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::VirtioInterrupt; +use anyhow::anyhow; use net_util::CtrlQueue; use net_util::{ build_net_config_space, build_net_config_space_with_mq, open_tap, @@ -84,44 +85,55 @@ impl NetCtrlEpollHandler { } impl EpollHelperHandler for NetCtrlEpollHandler { - fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { + fn handle_event( + &mut self, + _helper: &mut EpollHelper, + event: &epoll::Event, + ) -> result::Result<(), EpollHelperError> { let ev_type = event.data as u16; match ev_type { CTRL_QUEUE_EVENT => { let mem = self.mem.memory(); - if let Err(e) = self.queue_evt.read() { - error!("Failed to get control queue event: {:?}", e); - return true; - } - if let Err(e) = - self.ctrl_q - .process(mem.deref(), &mut self.queue, self.access_platform.as_ref()) - { - error!("Failed to process control queue: {:?}", e); - return true; - } else { - match self.queue.needs_notification(mem.deref()) { - Ok(true) => { - if let Err(e) = self.signal_used_queue(self.queue_index) { - error!("Error signalling that control queue was used: {:?}", e); - return true; - } - } - Ok(false) => {} - Err(e) => { - error!("Error getting notification state of control queue: {}", e); - return true; - } + self.queue_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to get control queue event: {:?}", + e + )) + })?; + self.ctrl_q + .process(mem.deref(), &mut self.queue, self.access_platform.as_ref()) + .map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to process control queue: {:?}", + e + )) + })?; + match self.queue.needs_notification(mem.deref()) { + Ok(true) => { + self.signal_used_queue(self.queue_index).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Error signalling that control queue was used: {:?}", + e + )) + })?; } - } + Ok(false) => {} + Err(e) => { + return Err(EpollHelperError::HandleEvent(anyhow!( + "Error getting notification state of control queue: {}", + e + ))); + } + }; } _ => { - error!("Unknown event for virtio-net control queue"); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unknown event for virtio-net control queue" + ))); } } - false + Ok(()) } } @@ -290,15 +302,18 @@ impl NetEpollHandler { } impl EpollHelperHandler for NetEpollHandler { - fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { + fn handle_event( + &mut self, + _helper: &mut EpollHelper, + event: &epoll::Event, + ) -> result::Result<(), EpollHelperError> { let ev_type = event.data as u16; match ev_type { RX_QUEUE_EVENT => { self.driver_awake = true; - if let Err(e) = self.handle_rx_event() { - error!("Error processing RX queue: {:?}", e); - return true; - } + self.handle_rx_event().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Error processing RX queue: {:?}", e)) + })?; } TX_QUEUE_EVENT => { let queue_evt = &self.queue_evt_pair[1]; @@ -306,22 +321,22 @@ impl EpollHelperHandler for NetEpollHandler { error!("Failed to get tx queue event: {:?}", e); } self.driver_awake = true; - if let Err(e) = self.handle_tx_event() { - error!("Error processing TX queue: {:?}", e); - return true; - } + self.handle_tx_event().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Error processing TX queue: {:?}", e)) + })?; } TX_TAP_EVENT => { - if let Err(e) = self.handle_tx_event() { - error!("Error processing TX queue (TAP event): {:?}", e); - return true; - } + self.handle_tx_event().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Error processing TX queue (TAP event): {:?}", + e + )) + })?; } RX_TAP_EVENT => { - if let Err(e) = self.handle_rx_tap_event() { - error!("Error processing tap queue: {:?}", e); - return true; - } + self.handle_rx_tap_event().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Error processing tap queue: {:?}", e)) + })?; } RX_RATE_LIMITER_EVENT => { if let Some(rate_limiter) = &mut self.net.rx_rate_limiter { @@ -336,20 +351,25 @@ impl EpollHelperHandler for NetEpollHandler { epoll::Events::EPOLLIN, u64::from(self.net.tap_rx_event_id), ) { - error!("Error register_listener with `RX_RATE_LIMITER_EVENT`: {:?}", e); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Error register_listener with `RX_RATE_LIMITER_EVENT`: {:?}", + e + ))); } self.net.rx_tap_listening = true; } } Err(e) => { - error!("Error from 'rate_limiter.event_handler()': {:?}", e); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Error from 'rate_limiter.event_handler()': {:?}", + e + ))); } } } else { - error!("Unexpected RX_RATE_LIMITER_EVENT"); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unexpected RX_RATE_LIMITER_EVENT" + ))); } } TX_RATE_LIMITER_EVENT => { @@ -360,26 +380,33 @@ impl EpollHelperHandler for NetEpollHandler { Ok(_) => { self.driver_awake = true; if let Err(e) = self.process_tx() { - error!("Error processing TX queue: {:?}", e); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Error processing TX queue: {:?}", + e + ))); } } Err(e) => { - error!("Error from 'rate_limiter.event_handler()': {:?}", e); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Error from 'rate_limiter.event_handler()': {:?}", + e + ))); } } } else { - error!("Unexpected TX_RATE_LIMITER_EVENT"); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unexpected TX_RATE_LIMITER_EVENT" + ))); } } _ => { - error!("Unknown event: {}", ev_type); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unexpected event: {}", + ev_type + ))); } } - false + Ok(()) } } diff --git a/virtio-devices/src/pmem.rs b/virtio-devices/src/pmem.rs index e52fbddf4..8fceb1a08 100644 --- a/virtio-devices/src/pmem.rs +++ b/virtio-devices/src/pmem.rs @@ -16,6 +16,7 @@ use crate::seccomp_filters::Thread; use crate::thread_helper::spawn_virtio_thread; use crate::{GuestMemoryMmap, MmapRegion}; use crate::{VirtioInterrupt, VirtioInterruptType}; +use anyhow::anyhow; use seccompiler::SeccompAction; use std::fmt::{self, Display}; use std::fs::File; @@ -241,26 +242,35 @@ impl PmemEpollHandler { } impl EpollHelperHandler for PmemEpollHandler { - fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { + fn handle_event( + &mut self, + _helper: &mut EpollHelper, + event: &epoll::Event, + ) -> result::Result<(), EpollHelperError> { let ev_type = event.data as u16; match ev_type { QUEUE_AVAIL_EVENT => { - if let Err(e) = self.queue_evt.read() { - error!("Failed to get queue event: {:?}", e); - return true; - } else if self.process_queue() { - if let Err(e) = self.signal_used_queue() { - error!("Failed to signal used queue: {:?}", e); - return true; - } + self.queue_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get queue event: {:?}", e)) + })?; + + if self.process_queue() { + self.signal_used_queue().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + )) + })?; } } _ => { - error!("Unexpected event: {}", ev_type); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unexpected event: {}", + ev_type + ))); } } - false + Ok(()) } } diff --git a/virtio-devices/src/rng.rs b/virtio-devices/src/rng.rs index 50fdad92b..1552264dd 100644 --- a/virtio-devices/src/rng.rs +++ b/virtio-devices/src/rng.rs @@ -12,6 +12,7 @@ use crate::seccomp_filters::Thread; use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::{VirtioInterrupt, VirtioInterruptType}; +use anyhow::anyhow; use seccompiler::SeccompAction; use std::fs::File; use std::io; @@ -103,26 +104,34 @@ impl RngEpollHandler { } impl EpollHelperHandler for RngEpollHandler { - fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { + fn handle_event( + &mut self, + _helper: &mut EpollHelper, + event: &epoll::Event, + ) -> result::Result<(), EpollHelperError> { let ev_type = event.data as u16; match ev_type { QUEUE_AVAIL_EVENT => { - if let Err(e) = self.queue_evt.read() { - error!("Failed to get queue event: {:?}", e); - return true; - } else if self.process_queue() { - if let Err(e) = self.signal_used_queue() { - error!("Failed to signal used queue: {:?}", e); - return true; - } + self.queue_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get queue event: {:?}", e)) + })?; + if self.process_queue() { + self.signal_used_queue().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + )) + })?; } } _ => { - error!("Unexpected event: {}", ev_type); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unexpected event: {}", + ev_type + ))); } } - false + Ok(()) } } diff --git a/virtio-devices/src/vhost_user/mod.rs b/virtio-devices/src/vhost_user/mod.rs index 0df4fe3bb..08daf48fb 100644 --- a/virtio-devices/src/vhost_user/mod.rs +++ b/virtio-devices/src/vhost_user/mod.rs @@ -256,30 +256,39 @@ impl VhostUserEpollHandler { } impl EpollHelperHandler for VhostUserEpollHandler { - fn handle_event(&mut self, helper: &mut EpollHelper, event: &epoll::Event) -> bool { + fn handle_event( + &mut self, + helper: &mut EpollHelper, + event: &epoll::Event, + ) -> std::result::Result<(), EpollHelperError> { let ev_type = event.data as u16; match ev_type { HUP_CONNECTION_EVENT => { - if let Err(e) = self.reconnect(helper) { - error!("failed to reconnect vhost-user backend: {:?}", e); - return true; - } + self.reconnect(helper).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "failed to reconnect vhost-user backend: {:?}", + e + )) + })?; } SLAVE_REQ_EVENT => { if let Some(slave_req_handler) = self.slave_req_handler.as_mut() { - if let Err(e) = slave_req_handler.handle_request() { - error!("Failed to handle request from vhost-user backend: {:?}", e); - return true; - } + slave_req_handler.handle_request().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to handle request from vhost-user backend: {:?}", + e + )) + })?; } } _ => { - error!("Unknown event for vhost-user thread"); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unknown event for vhost-user thread" + ))); } } - false + Ok(()) } } diff --git a/virtio-devices/src/vsock/device.rs b/virtio-devices/src/vsock/device.rs index 280c3a5c2..841ab14d3 100644 --- a/virtio-devices/src/vsock/device.rs +++ b/virtio-devices/src/vsock/device.rs @@ -37,6 +37,7 @@ use crate::{ EpollHelperHandler, VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IN_ORDER, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1, }; +use anyhow::anyhow; use byteorder::{ByteOrder, LittleEndian}; use seccompiler::SeccompAction; use std::io; @@ -222,13 +223,17 @@ impl EpollHelperHandler for VsockEpollHandler where B: VsockBackend, { - fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { + fn handle_event( + &mut self, + _helper: &mut EpollHelper, + event: &epoll::Event, + ) -> result::Result<(), EpollHelperError> { let evset = match epoll::Events::from_bits(event.events) { Some(evset) => evset, None => { let evbits = event.events; warn!("epoll: ignoring unknown event set: 0x{:x}", evbits); - return false; + return Ok(()); } }; @@ -236,43 +241,45 @@ where match ev_type { RX_QUEUE_EVENT => { debug!("vsock: RX queue event"); - if let Err(e) = self.queue_evts[0].read() { - error!("Failed to get RX queue event: {:?}", e); - return true; - } else if self.backend.read().unwrap().has_pending_rx() { - if let Err(e) = self.process_rx() { - error!("Failed to process RX queue: {:?}", e); - return true; - } + self.queue_evts[0].read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get RX queue event: {:?}", e)) + })?; + if self.backend.read().unwrap().has_pending_rx() { + self.process_rx().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to process RX queue: {:?}", + e + )) + })?; } } TX_QUEUE_EVENT => { debug!("vsock: TX queue event"); - if let Err(e) = self.queue_evts[1].read() { - error!("Failed to get TX queue event: {:?}", e); - return true; - } else { - if let Err(e) = self.process_tx() { - error!("Failed to process TX queue: {:?}", e); - return true; - } - // The backend may have queued up responses to the packets we sent during TX queue - // processing. If that happened, we need to fetch those responses and place them - // into RX buffers. - if self.backend.read().unwrap().has_pending_rx() { - if let Err(e) = self.process_rx() { - error!("Failed to process RX queue: {:?}", e); - return true; - } - } + self.queue_evts[1].read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get TX queue event: {:?}", e)) + })?; + + self.process_tx().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to process TX queue: {:?}", e)) + })?; + + // The backend may have queued up responses to the packets we sent during TX queue + // processing. If that happened, we need to fetch those responses and place them + // into RX buffers. + if self.backend.read().unwrap().has_pending_rx() { + self.process_rx().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to process RX queue: {:?}", + e + )) + })?; } } EVT_QUEUE_EVENT => { debug!("vsock: EVT queue event"); - if let Err(e) = self.queue_evts[2].read() { - error!("Failed to get EVT queue event: {:?}", e); - return true; - } + self.queue_evts[2].read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get EVT queue event: {:?}", e)) + })?; } BACKEND_EVENT => { debug!("vsock: backend event"); @@ -282,24 +289,26 @@ where // In particular, if `self.backend.send_pkt()` halted the TX queue processing (by // returning an error) at some point in the past, now is the time to try walking the // TX queue again. - if let Err(e) = self.process_tx() { - error!("Failed to process TX queue: {:?}", e); - return true; - } + self.process_tx().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to process TX queue: {:?}", e)) + })?; if self.backend.read().unwrap().has_pending_rx() { - if let Err(e) = self.process_rx() { - error!("Failed to process RX queue: {:?}", e); - return true; - } + self.process_rx().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to process RX queue: {:?}", + e + )) + })?; } } _ => { - error!("Unknown event for virtio-vsock"); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unknown event for virtio-vsock" + ))); } } - false + Ok(()) } } @@ -714,7 +723,7 @@ mod tests { EpollHelper::new(&ctx.handler.kill_evt, &ctx.handler.pause_evt).unwrap(); assert!( - ctx.handler.handle_event(&mut epoll_helper, &event), + ctx.handler.handle_event(&mut epoll_helper, &event).is_err(), "handle_event() should have failed" ); } @@ -783,7 +792,7 @@ mod tests { EpollHelper::new(&ctx.handler.kill_evt, &ctx.handler.pause_evt).unwrap(); assert!( - ctx.handler.handle_event(&mut epoll_helper, &event), + ctx.handler.handle_event(&mut epoll_helper, &event).is_err(), "handle_event() should have failed" ); } @@ -803,7 +812,7 @@ mod tests { EpollHelper::new(&ctx.handler.kill_evt, &ctx.handler.pause_evt).unwrap(); assert!( - ctx.handler.handle_event(&mut epoll_helper, &event), + ctx.handler.handle_event(&mut epoll_helper, &event).is_err(), "handle_event() should have failed" ); } @@ -824,7 +833,7 @@ mod tests { let event = epoll::Event::new(events, BACKEND_EVENT as u64); let mut epoll_helper = EpollHelper::new(&ctx.handler.kill_evt, &ctx.handler.pause_evt).unwrap(); - ctx.handler.handle_event(&mut epoll_helper, &event); + assert!(ctx.handler.handle_event(&mut epoll_helper, &event).is_ok()); // The backend should've received this event. assert_eq!( @@ -850,7 +859,7 @@ mod tests { let event = epoll::Event::new(events, BACKEND_EVENT as u64); let mut epoll_helper = EpollHelper::new(&ctx.handler.kill_evt, &ctx.handler.pause_evt).unwrap(); - ctx.handler.handle_event(&mut epoll_helper, &event); + assert!(ctx.handler.handle_event(&mut epoll_helper, &event).is_ok()); // The backend should've received this event. assert_eq!( @@ -875,7 +884,7 @@ mod tests { EpollHelper::new(&ctx.handler.kill_evt, &ctx.handler.pause_evt).unwrap(); assert!( - ctx.handler.handle_event(&mut epoll_helper, &event), + ctx.handler.handle_event(&mut epoll_helper, &event).is_err(), "handle_event() should have failed" ); } diff --git a/virtio-devices/src/vsock/mod.rs b/virtio-devices/src/vsock/mod.rs index 62295eec8..f9d22831d 100644 --- a/virtio-devices/src/vsock/mod.rs +++ b/virtio-devices/src/vsock/mod.rs @@ -353,7 +353,7 @@ mod tests { let event = epoll::Event::new(events, TX_QUEUE_EVENT as u64); let mut epoll_helper = EpollHelper::new(&self.handler.kill_evt, &self.handler.pause_evt).unwrap(); - self.handler.handle_event(&mut epoll_helper, &event); + self.handler.handle_event(&mut epoll_helper, &event).ok(); } pub fn signal_rxq_event(&mut self) { self.handler.queue_evts[0].write(1).unwrap(); @@ -361,7 +361,7 @@ mod tests { let event = epoll::Event::new(events, RX_QUEUE_EVENT as u64); let mut epoll_helper = EpollHelper::new(&self.handler.kill_evt, &self.handler.pause_evt).unwrap(); - self.handler.handle_event(&mut epoll_helper, &event); + self.handler.handle_event(&mut epoll_helper, &event).ok(); } } } diff --git a/virtio-devices/src/watchdog.rs b/virtio-devices/src/watchdog.rs index 602bbbf3d..6f023ce5e 100644 --- a/virtio-devices/src/watchdog.rs +++ b/virtio-devices/src/watchdog.rs @@ -121,28 +121,35 @@ impl WatchdogEpollHandler { } impl EpollHelperHandler for WatchdogEpollHandler { - fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { + fn handle_event( + &mut self, + _helper: &mut EpollHelper, + event: &epoll::Event, + ) -> result::Result<(), EpollHelperError> { let ev_type = event.data as u16; match ev_type { QUEUE_AVAIL_EVENT => { - if let Err(e) = self.queue_evt.read() { - error!("Failed to get queue event: {:?}", e); - return true; - } else if self.process_queue() { - if let Err(e) = self.signal_used_queue() { - error!("Failed to signal used queue: {:?}", e); - return true; - } + self.queue_evt.read().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Failed to get queue event: {:?}", e)) + })?; + + if self.process_queue() { + self.signal_used_queue().map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to signal used queue: {:?}", + e + )) + })?; } } TIMER_EXPIRED_EVENT => { // When reading from the timerfd you get 8 bytes indicating // the number of times this event has elapsed since the last read. let mut buf = vec![0; 8]; - if let Err(e) = self.timer.read_exact(&mut buf) { - error!("Error reading from timer fd: {:}", e); - return true; - } + self.timer.read_exact(&mut buf).map_err(|e| { + EpollHelperError::HandleEvent(anyhow!("Error reading from timer fd: {:}", e)) + })?; + if let Some(last_ping_time) = self.last_ping_time.lock().unwrap().as_ref() { let now = Instant::now(); let gap = now.duration_since(*last_ping_time).as_secs(); @@ -151,14 +158,15 @@ impl EpollHelperHandler for WatchdogEpollHandler { self.reset_evt.write(1).ok(); } } - return false; } _ => { - error!("Unexpected event: {}", ev_type); - return true; + return Err(EpollHelperError::HandleEvent(anyhow!( + "Unexpected event: {}", + ev_type + ))); } } - false + Ok(()) } }