virtio-devices: vhost_user: skip resume for disconnected backends

resume() mirrors pause() for backend communication: it skips the
vhost-user backend call when the device is already disconnected, and it
marks newly failed resume_vhost_user() calls disconnected only when the
classifier identifies transport loss.

Signed-off-by: Dylan Reid <dgreid@fb.com>
This commit is contained in:
Dylan Reid
2026-05-08 17:29:08 -07:00
committed by Bo Chen
parent f56bfdaeb7
commit 99ec20ff97
2 changed files with 40 additions and 7 deletions

View File

@@ -681,18 +681,45 @@ impl VhostUserCommon {
Ok(())
}
pub fn resume(&mut self) -> std::result::Result<(), MigratableError> {
if let Some(vu) = &self.vu {
vu.lock().unwrap().resume_vhost_user().map_err(|e| {
MigratableError::Resume(anyhow!("Error resuming vhost-user backend: {e:?}"))
})?;
fn resume_internal(&mut self) -> std::result::Result<(), MigratableError> {
// Skip the resume_vhost_user call if the backend is disconnected. Process the queue
// interrupts to kick any paused workers.
if self.disconnected.load(Ordering::Relaxed) {
return Err(MigratableError::DeviceDisconnected(
self.socket_path.clone(),
));
}
if let Some(vu) = &self.vu
&& let Err(e) = vu.lock().unwrap().resume_vhost_user()
{
if e.is_transport_lost() {
self.disconnected.store(true, Ordering::Relaxed);
return Err(MigratableError::DeviceDisconnected(
self.socket_path.clone(),
));
}
return Err(MigratableError::Resume(anyhow!(
"Error resuming vhost-user backend for socket {}: {e:?}",
self.socket_path
)));
}
Ok(())
}
pub fn resume(&mut self) -> std::result::Result<(), MigratableError> {
let ret = self.resume_internal();
// Always run the interrupt loop so workers don't get stuck.
for i in 0..self.vu_num_queues {
self.virtio_common
.trigger_interrupt(crate::VirtioInterruptType::Queue(i as u16))
.ok();
}
Ok(())
ret
}
pub fn state<C: Default>(

View File

@@ -5553,7 +5553,13 @@ impl Pausable for DeviceManager {
fn resume(&mut self) -> result::Result<(), MigratableError> {
for (_, device_node) in self.device_tree.lock().unwrap().iter() {
if let Some(migratable) = &device_node.migratable {
migratable.lock().unwrap().resume()?;
match migratable.lock().unwrap().resume() {
Ok(()) => {}
Err(MigratableError::DeviceDisconnected(id)) => {
warn!("Skipping resume for disconnected device {id}");
}
Err(e) => return Err(e),
}
}
}
Ok(())