From c070d5dfa4a9e24fb5e2020adad21dcf2546ae6f Mon Sep 17 00:00:00 2001 From: Chinmoy Date: Sun, 5 Jul 2026 00:18:56 +0530 Subject: [PATCH] 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 Assisted-by: GLM 5.2 --- virtio-devices/src/vhost_user/blk.rs | 2 +- virtio-devices/src/vhost_user/fs.rs | 2 +- .../src/vhost_user/generic_vhost_user.rs | 2 +- virtio-devices/src/vhost_user/mod.rs | 4 +- virtio-devices/src/vhost_user/net.rs | 2 +- .../src/vhost_user/vu_common_ctrl.rs | 47 +++++++++++++------ 6 files changed, 40 insertions(+), 19 deletions(-) diff --git a/virtio-devices/src/vhost_user/blk.rs b/virtio-devices/src/vhost_user/blk.rs index ba3622faf..7d84d08cb 100644 --- a/virtio-devices/src/vhost_user/blk.rs +++ b/virtio-devices/src/vhost_user/blk.rs @@ -63,7 +63,7 @@ impl Blk { &vu_cfg.socket, num_queues as u64, false, - None, + &exit_evt, )?; let ( diff --git a/virtio-devices/src/vhost_user/fs.rs b/virtio-devices/src/vhost_user/fs.rs index 3a13d3f0f..a3c0d6b69 100644 --- a/virtio-devices/src/vhost_user/fs.rs +++ b/virtio-devices/src/vhost_user/fs.rs @@ -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, diff --git a/virtio-devices/src/vhost_user/generic_vhost_user.rs b/virtio-devices/src/vhost_user/generic_vhost_user.rs index ae1b0f2e3..ea10f726f 100644 --- a/virtio-devices/src/vhost_user/generic_vhost_user.rs +++ b/virtio-devices/src/vhost_user/generic_vhost_user.rs @@ -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, diff --git a/virtio-devices/src/vhost_user/mod.rs b/virtio-devices/src/vhost_user/mod.rs index 22405ddbf..33566f15c 100644 --- a/virtio-devices/src/vhost_user/mod.rs +++ b/virtio-devices/src/vhost_user/mod.rs @@ -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 = result::Result; @@ -329,7 +331,7 @@ impl VhostUserEpollHandler { &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 diff --git a/virtio-devices/src/vhost_user/net.rs b/virtio-devices/src/vhost_user/net.rs index 7076a33f8..8d0f8ef8a 100644 --- a/virtio-devices/src/vhost_user/net.rs +++ b/virtio-devices/src/vhost_user/net.rs @@ -93,7 +93,7 @@ impl Net { &vu_cfg.socket, num_queues as u64, false, - None, + &exit_evt, )?; let ( diff --git a/virtio-devices/src/vhost_user/vu_common_ctrl.rs b/virtio-devices/src/vhost_user/vu_common_ctrl.rs index 995f23fd5..fa9a6a642 100644 --- a/virtio-devices/src/vhost_user/vu_common_ctrl.rs +++ b/virtio-devices/src/vhost_user/vu_common_ctrl.rs @@ -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 { 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,