mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices: vhost_user: classify disconnected backend errors
Add two explicit disconnected-backend error paths before wiring them into the call sites. MigratableError::DeviceDisconnected is the lifecycle sentinel for operations that were skipped because a component is already known to be disconnected. It lets the caller log and continue without treating it as a VMM-fatal condition. Error::BackendDisconnected is the vhost-user-local error used when VhostUserCommon refuses to call a backend after its disconnected flag is set. The transport classifier treats socket close/reset/EOF and vhost-user partial-message/disconnected cases as transport loss, while backend NACKs, invalid protocol state, and retry-able socket errors remain ordinary operation failures. Signed-off-by: Dylan Reid <dgreid@fb.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::io::ErrorKind;
|
||||
use std::ops::Deref;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
@@ -16,7 +17,7 @@ use vhost::Error as VhostError;
|
||||
use vhost::vhost_user::message::{
|
||||
VhostUserInflight, VhostUserProtocolFeatures, VhostUserVirtioFeatures,
|
||||
};
|
||||
use vhost::vhost_user::{FrontendReqHandler, VhostUserFrontendReqHandler};
|
||||
use vhost::vhost_user::{Error as VhostUserError, FrontendReqHandler, VhostUserFrontendReqHandler};
|
||||
use virtio_queue::{Error as QueueError, Queue};
|
||||
use vm_memory::guest_memory::Error as MmapError;
|
||||
use vm_memory::mmap::MmapRegionError;
|
||||
@@ -73,6 +74,8 @@ pub enum Error {
|
||||
VhostUserOpen(#[source] VhostError),
|
||||
#[error("Connection to socket failed")]
|
||||
VhostUserConnect(#[source] VhostError),
|
||||
#[error("Backend disconnected for socket {0}")]
|
||||
BackendDisconnected(String),
|
||||
#[error("Get features failed")]
|
||||
VhostUserGetFeatures(#[source] VhostError),
|
||||
#[error("Get queue max number failed")]
|
||||
@@ -176,6 +179,72 @@ pub enum Error {
|
||||
}
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
fn io_error_is_connection_lost(error: &io::Error) -> bool {
|
||||
matches!(
|
||||
error.kind(),
|
||||
ErrorKind::BrokenPipe
|
||||
| ErrorKind::ConnectionAborted
|
||||
| ErrorKind::ConnectionReset
|
||||
| ErrorKind::NotConnected
|
||||
| ErrorKind::UnexpectedEof
|
||||
)
|
||||
}
|
||||
|
||||
fn vhost_user_error_is_transport_lost(error: &VhostUserError) -> bool {
|
||||
match error {
|
||||
VhostUserError::Disconnected
|
||||
| VhostUserError::PartialMessage
|
||||
| VhostUserError::SocketBroken(_)
|
||||
| VhostUserError::SocketConnect(_) => true,
|
||||
VhostUserError::SocketError(e) => io_error_is_connection_lost(e),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn vhost_error_is_transport_lost(error: &VhostError) -> bool {
|
||||
match error {
|
||||
VhostError::VhostUserProtocol(e) => vhost_user_error_is_transport_lost(e),
|
||||
VhostError::IOError(e) => io_error_is_connection_lost(e),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
fn is_transport_lost(&self) -> bool {
|
||||
match self {
|
||||
Error::VhostUserConnect(_) | Error::BackendDisconnected(_) => true,
|
||||
Error::VhostUserCreateFrontend(e)
|
||||
| Error::VhostUserOpen(e)
|
||||
| Error::VhostUserGetFeatures(e)
|
||||
| Error::VhostUserGetQueueMaxNum(e)
|
||||
| Error::VhostUserGetProtocolFeatures(e)
|
||||
| Error::VhostUserGetVringBase(e)
|
||||
| Error::VhostUserSetOwner(e)
|
||||
| Error::VhostUserResetOwner(e)
|
||||
| Error::VhostUserSetFeatures(e)
|
||||
| Error::VhostUserSetProtocolFeatures(e)
|
||||
| Error::VhostUserSetMemTable(e)
|
||||
| Error::VhostUserSetVringNum(e)
|
||||
| Error::VhostUserSetVringAddr(e)
|
||||
| Error::VhostUserSetVringBase(e)
|
||||
| Error::VhostUserSetVringCall(e)
|
||||
| Error::VhostUserSetVringKick(e)
|
||||
| Error::VhostUserSetVringEnable(e)
|
||||
| Error::VhostUserSetBackendRequestFd(e)
|
||||
| Error::VhostUserAddMemReg(e)
|
||||
| Error::VhostUserGetConfig(e)
|
||||
| Error::VhostUserSetConfig(e)
|
||||
| Error::VhostUserGetInflight(e)
|
||||
| Error::VhostUserSetInflight(e)
|
||||
| Error::VhostUserSetLogBase(e)
|
||||
| Error::VhostUserSetDeviceStateFd(e)
|
||||
| Error::VhostUserCheckDeviceState(e) => vhost_error_is_transport_lost(e),
|
||||
Error::FrontendReqHandlerCreation(e) => vhost_user_error_is_transport_lost(e),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const DEFAULT_VIRTIO_FEATURES: u64 = (1 << VIRTIO_F_RING_INDIRECT_DESC)
|
||||
| (1 << VIRTIO_F_RING_EVENT_IDX)
|
||||
| (1 << VIRTIO_F_VERSION_1)
|
||||
|
||||
@@ -92,6 +92,9 @@ pub enum MigratableError {
|
||||
|
||||
#[error("Failed to release a disk lock")]
|
||||
UnlockError(#[source] anyhow::Error),
|
||||
|
||||
#[error("Lifecycle operation skipped for disconnected component {0}")]
|
||||
DeviceDisconnected(String),
|
||||
}
|
||||
|
||||
/// A Pausable component can be paused and resumed.
|
||||
|
||||
Reference in New Issue
Block a user