virtio-devices: Abort vhost-user client connect on kill_evt

Client connect retried for a full minute on every failure and did not
watch kill_evt for early exit, unlike reconnect, so teardown and
permanent connect errors both stalled for CONNECT_TIMEOUT.

Update the client path to watch kill_evt for early abort, fail
non-retryable errors immediately, and surface timeout with a dedicated
error.

Partially Fixes #8052

Signed-off-by: Chinmoy <daschinmoyy21@gmail.com>
Assisted-by: GLM 5.2
This commit is contained in:
Chinmoy
2026-07-05 00:18:56 +05:30
committed by Rob Bradford
parent 9474c07526
commit c070d5dfa4
6 changed files with 40 additions and 19 deletions

View File

@@ -63,7 +63,7 @@ impl Blk {
&vu_cfg.socket,
num_queues as u64,
false,
None,
&exit_evt,
)?;
let (

View File

@@ -90,7 +90,7 @@ impl Fs {
// Connect to the vhost-user socket.
let mut vu =
VhostUserHandle::connect_vhost_user(false, path, num_queues as u64, false, None)?;
VhostUserHandle::connect_vhost_user(false, path, num_queues as u64, false, &exit_evt)?;
let (
avail_features,

View File

@@ -77,7 +77,7 @@ impl GenericVhostUser {
// Connect to the vhost-user socket.
let mut vu =
VhostUserHandle::connect_vhost_user(false, path, num_queues as u64, false, None)?;
VhostUserHandle::connect_vhost_user(false, path, num_queues as u64, false, &exit_evt)?;
let (
avail_features,

View File

@@ -179,6 +179,8 @@ pub enum Error {
EpollWait(#[source] io::Error),
#[error("Aborted vhost-user connect: kill event received")]
ConnectKilled,
#[error("Timed out waiting for vhost-user connection")]
VhostUserConnectTimeout,
}
type Result<T> = result::Result<T, Error>;
@@ -329,7 +331,7 @@ impl<S: VhostUserFrontendReqHandler> VhostUserEpollHandler<S> {
&self.socket_path,
self.queues.len() as u64,
true,
Some(&self.kill_evt),
&self.kill_evt,
) {
Ok(vu) => vu,
// Kill event fired during the connect retry loop; abandon the

View File

@@ -93,7 +93,7 @@ impl Net {
&vu_cfg.socket,
num_queues as u64,
false,
None,
&exit_evt,
)?;
let (

View File

@@ -17,9 +17,13 @@ use vhost::vhost_user::message::{
VhostUserProtocolFeatures, VhostUserVirtioFeatures,
};
use vhost::vhost_user::{
Frontend, FrontendReqHandler, VhostUserFrontend, VhostUserFrontendReqHandler,
Error as VhostUserError, Frontend, FrontendReqHandler, VhostUserFrontend,
VhostUserFrontendReqHandler,
};
use vhost::{
Error as VhostError, VhostBackend, VhostUserDirtyLogRegion, VhostUserMemoryRegionInfo,
VringConfigData,
};
use vhost::{VhostBackend, VhostUserDirtyLogRegion, VhostUserMemoryRegionInfo, VringConfigData};
use virtio_queue::desc::RawDescriptor;
use virtio_queue::{Queue, QueueT};
use vm_memory::guest_memory::Error as MmapError;
@@ -381,7 +385,7 @@ impl VhostUserHandle {
socket_path: &str,
num_queues: u64,
unlink_socket: bool,
kill_evt: Option<&EventFd>,
kill_evt: &EventFd,
) -> Result<Self> {
if server {
if unlink_socket {
@@ -427,15 +431,13 @@ impl VhostUserHandle {
)
.map_err(Error::EpollCtl)?;
if let Some(kill_evt) = kill_evt {
epoll
.ctl(
ControlOperation::Add,
kill_evt.as_raw_fd(),
EpollEvent::new(EventSet::IN, ConnectEvent::Kill as u64),
)
.map_err(Error::EpollCtl)?;
}
epoll
.ctl(
ControlOperation::Add,
kill_evt.as_raw_fd(),
EpollEvent::new(EventSet::IN, ConnectEvent::Kill as u64),
)
.map_err(Error::EpollCtl)?;
let start = Instant::now();
let mut events = [EpollEvent::default(); 1];
@@ -457,13 +459,30 @@ impl VhostUserHandle {
Err(e) => e,
};
if start.elapsed() >= CONNECT_TIMEOUT {
let retryable = match &err {
VhostError::VhostUserProtocol(VhostUserError::SocketConnect(io_err)) => {
matches!(
io_err.kind(),
io::ErrorKind::NotFound
| io::ErrorKind::Interrupted
| io::ErrorKind::ConnectionRefused
)
}
_ => false,
};
if !retryable {
error!(
"Failed connecting the backend after trying for 1 minute for socket {socket_path}: {err:?}"
"Failed connecting to vhost-user backend for socket {socket_path}: {err:?}"
);
return Err(Error::VhostUserConnect(err));
}
if start.elapsed() >= CONNECT_TIMEOUT {
error!("Timed out waiting for vhost-user connection on socket {socket_path}");
return Err(Error::VhostUserConnectTimeout);
}
loop {
match epoll.wait(-1, &mut events) {
Ok(_) => break,