diff --git a/virtio-devices/src/vhost_user/mod.rs b/virtio-devices/src/vhost_user/mod.rs index bb354406a..20c0b3c1f 100644 --- a/virtio-devices/src/vhost_user/mod.rs +++ b/virtio-devices/src/vhost_user/mod.rs @@ -207,6 +207,8 @@ pub struct VhostUserEpollHandler { pub server: bool, pub backend_req_handler: Option>, pub inflight: Option, + /// Flag set by the worker when the vhost-user backend is no longer reachable. + pub disconnected: Arc, } impl VhostUserEpollHandler { @@ -232,6 +234,18 @@ impl VhostUserEpollHandler { } fn reconnect(&mut self, helper: &mut EpollHelper) -> std::result::Result<(), EpollHelperError> { + let result = self.reconnect_inner(helper); + if result.is_err() { + // If reconnect fails, mark disconnected to avoid repeated failed socket calls. + self.disconnected.store(true, Ordering::Relaxed); + } + result + } + + fn reconnect_inner( + &mut self, + helper: &mut EpollHelper, + ) -> std::result::Result<(), EpollHelperError> { helper.del_event_custom( self.vu.lock().unwrap().socket_handle().as_raw_fd(), HUP_CONNECTION_EVENT, @@ -301,7 +315,7 @@ impl EpollHelperHandler for VhostUserEpollHandle event: &epoll::Event, ) -> std::result::Result<(), EpollHelperError> { let ev_type = event.data as u16; - match ev_type { + let result = match ev_type { HUP_CONNECTION_EVENT => { info!( "vhost-user backend for socket {} disconnected, attempting reconnection", @@ -312,25 +326,32 @@ impl EpollHelperHandler for VhostUserEpollHandle "failed to reconnect vhost-user backend for socket {}: {e:?}", self.socket_path )) - })?; + }) } BACKEND_REQ_EVENT => { if let Some(backend_req_handler) = self.backend_req_handler.as_mut() { - backend_req_handler.handle_request().map_err(|e| { - EpollHelperError::HandleEvent(anyhow!( - "Failed to handle request from vhost-user backend: {e:?}" - )) - })?; + backend_req_handler + .handle_request() + .map(|_| ()) + .map_err(|e| { + EpollHelperError::HandleEvent(anyhow!( + "Failed to handle request from vhost-user backend: {e:?}" + )) + }) + } else { + Ok(()) } } - _ => { - return Err(EpollHelperError::HandleEvent(anyhow!( - "Unknown event for vhost-user thread" - ))); - } - } + _ => Err(EpollHelperError::HandleEvent(anyhow!( + "Unknown event for vhost-user thread" + ))), + }; - Ok(()) + // If the backend hits and error it is unusable from this point on. + if result.is_err() { + self.disconnected.store(true, Ordering::Relaxed); + } + result } } @@ -374,6 +395,8 @@ pub struct VhostUserCommon { pub server: bool, pub vring_bases: Option>, pub epoll_thread: Option>, + /// Indicates that the backend is no longer reachable. Shared with EPollHandler. + pub disconnected: Arc, } impl VhostUserCommon { @@ -432,6 +455,7 @@ impl VhostUserCommon { server: self.server, backend_req_handler, inflight, + disconnected: self.disconnected.clone(), }) }