virtio-devices: vhost_user: Correctly shutdown epoll thread

If the epoll thread is paused, which would be expected as a part of live
migration/snapshot-restore unpause the thread so that it can receive the
kill event. This mirrors the reset() behaviour of virtio devices. It is
important here so as to close the connection with the vhost-user-backend
to allow same host and --local migration and since after getting the
device state the vhost-user backend should no longer be used.

As a result of this change we can do --local and same-host migration
with virtio-fs.

Signed-off-by: Rob Bradford <rbradford@meta.com>
This commit is contained in:
Rob Bradford
2026-03-31 05:54:12 -07:00
parent 63aeb597ef
commit 68691db37b

View File

@@ -3,7 +3,7 @@
use std::ops::Deref;
use std::os::unix::io::AsRawFd;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Barrier, Mutex};
use std::{io, thread};
@@ -425,6 +425,22 @@ impl VhostUserCommon {
}
pub fn shutdown(&mut self) {
// Signal the epoll thread to exit, unpause it (it may be parked
// if the VM was paused for migration), then wait for it to finish.
// This ensures the thread drops its Arc<VhostUserHandle>, fully
// closing the vhost-user socket so the backend can accept a new
// connection from the destination.
if let Some(kill_evt) = self.virtio_common.kill_evt.take() {
let _ = kill_evt.write(1);
}
self.virtio_common.paused.store(false, Ordering::SeqCst);
if let Some(t) = self.epoll_thread.as_ref() {
t.thread().unpark();
}
if let Some(t) = self.epoll_thread.take() {
let _ = t.join();
}
// Remove socket path if needed
if self.server {
let _ = std::fs::remove_file(&self.socket_path);