virtio-devices: Make pause idempotent to prevent deadlock

Previously, calling pause() when already paused would wait on a barrier
for worker threads that were already parked, causing a deadlock.

This situation occurs when the VMM thread holds a device mutex while
calling an operation that triggers pause(), and a vCPU thread
simultaneously needs that same mutex for MMIO access. With slow I/O
backends (like RBD/Ceph), the timing window for this race is larger,
making the deadlock more likely to occur, see [0].

Make pause() idempotent by checking the paused state atomically and
returning early if already paused, avoiding the barrier wait.

[0] https://github.com/cloud-hypervisor/cloud-hypervisor/pull/7948#discussion_r305052509

Signed-off-by: Vincent Thomas <vincent@v-thomas.com>
This commit is contained in:
Vincent Thomas
2026-04-09 14:46:08 +00:00
committed by Rob Bradford
parent 67cf328a9e
commit e5dbf5242e

View File

@@ -340,7 +340,13 @@ impl Pausable for VirtioCommon {
"Pausing virtio-{}",
VirtioDeviceType::from(self.device_type)
);
self.paused.store(true, Ordering::SeqCst);
// If already paused, return early to avoid deadlock waiting on barrier
// for worker threads that are already parked.
if self.paused.swap(true, Ordering::SeqCst) {
return Ok(());
}
if let Some(pause_evt) = &self.pause_evt {
pause_evt
.write(1)