virtio-devices: Report errors from EpollHelperHandler::handle_event

Signed-off-by: Bo Chen <chen.bo@intel.com>
This commit is contained in:
Bo Chen 2022-08-11 18:30:13 -07:00 committed by Rob Bradford
parent a7f3620564
commit b1752994d5
13 changed files with 502 additions and 330 deletions

View File

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

View File

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

View File

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

View File

@ -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)?;
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -256,30 +256,39 @@ impl<S: VhostUserMasterReqHandler> VhostUserEpollHandler<S> {
}
impl<S: VhostUserMasterReqHandler> EpollHelperHandler for VhostUserEpollHandler<S> {
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(())
}
}

View File

@ -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<B> EpollHelperHandler for VsockEpollHandler<B>
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"
);
}

View File

@ -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();
}
}
}

View File

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