mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-08-20 15:01:16 +00:00
vm-virtio: Ensure pause event is caught by every virtio thread
Each virtio thread was reading/draining the pause_evt pipe when detecting the associated event. Problem is, when a virtio device has multiple threads, they all share the same pause_evt pipe, which can prevent some threads from receiving the event. If the first thread to catch the event is quickly clearing the pipe, some other threads might simply miss the event and they will not enter the "paused" state as expected. This is a behavior that was spotted with virtio-net as it usually uses 2 threads by default (1 for TX/RX queues and 1 for the control queue). The way to solve this issue is by letting each thread drain the pipe during the resume codepath, that is after the thread has been unparked. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
86377127df
commit
a7f0f9dfea
@ -832,8 +832,6 @@ impl<T: DiskFile> BlockEpollHandler<T> {
|
|||||||
break 'epoll;
|
break 'epoll;
|
||||||
}
|
}
|
||||||
PAUSE_EVENT => {
|
PAUSE_EVENT => {
|
||||||
// Drain pause event
|
|
||||||
let _ = self.pause_evt.read();
|
|
||||||
debug!("PAUSE_EVENT received, pausing virtio-block epoll loop");
|
debug!("PAUSE_EVENT received, pausing virtio-block epoll loop");
|
||||||
// We loop here to handle spurious park() returns.
|
// We loop here to handle spurious park() returns.
|
||||||
// Until we have not resumed, the paused boolean will
|
// Until we have not resumed, the paused boolean will
|
||||||
@ -841,6 +839,11 @@ impl<T: DiskFile> BlockEpollHandler<T> {
|
|||||||
while paused.load(Ordering::SeqCst) {
|
while paused.load(Ordering::SeqCst) {
|
||||||
thread::park();
|
thread::park();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drain pause event after the device has been resumed.
|
||||||
|
// This ensures the pause event has been seen by each
|
||||||
|
// and every thread related to this virtio device.
|
||||||
|
let _ = self.pause_evt.read();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("Unknown event for virtio-block");
|
error!("Unknown event for virtio-block");
|
||||||
|
@ -313,8 +313,6 @@ impl ConsoleEpollHandler {
|
|||||||
break 'epoll;
|
break 'epoll;
|
||||||
}
|
}
|
||||||
PAUSE_EVENT => {
|
PAUSE_EVENT => {
|
||||||
// Drain pause event
|
|
||||||
let _ = self.pause_evt.read();
|
|
||||||
debug!("PAUSE_EVENT received, pausing virtio-console epoll loop");
|
debug!("PAUSE_EVENT received, pausing virtio-console epoll loop");
|
||||||
// We loop here to handle spurious park() returns.
|
// We loop here to handle spurious park() returns.
|
||||||
// Until we have not resumed, the paused boolean will
|
// Until we have not resumed, the paused boolean will
|
||||||
@ -322,6 +320,11 @@ impl ConsoleEpollHandler {
|
|||||||
while paused.load(Ordering::SeqCst) {
|
while paused.load(Ordering::SeqCst) {
|
||||||
thread::park();
|
thread::park();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drain pause event after the device has been resumed.
|
||||||
|
// This ensures the pause event has been seen by each
|
||||||
|
// and every thread related to this virtio device.
|
||||||
|
let _ = self.pause_evt.read();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("Unknown event for virtio-console");
|
error!("Unknown event for virtio-console");
|
||||||
|
@ -744,8 +744,6 @@ impl IommuEpollHandler {
|
|||||||
break 'epoll;
|
break 'epoll;
|
||||||
}
|
}
|
||||||
PAUSE_EVENT => {
|
PAUSE_EVENT => {
|
||||||
// Drain pause event
|
|
||||||
let _ = self.pause_evt.read();
|
|
||||||
debug!("PAUSE_EVENT received, pausing virtio-iommu epoll loop");
|
debug!("PAUSE_EVENT received, pausing virtio-iommu epoll loop");
|
||||||
// We loop here to handle spurious park() returns.
|
// We loop here to handle spurious park() returns.
|
||||||
// Until we have not resumed, the paused boolean will
|
// Until we have not resumed, the paused boolean will
|
||||||
@ -753,6 +751,11 @@ impl IommuEpollHandler {
|
|||||||
while paused.load(Ordering::SeqCst) {
|
while paused.load(Ordering::SeqCst) {
|
||||||
thread::park();
|
thread::park();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drain pause event after the device has been resumed.
|
||||||
|
// This ensures the pause event has been seen by each
|
||||||
|
// and every thread related to this virtio device.
|
||||||
|
let _ = self.pause_evt.read();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("Unknown event for virtio-iommu");
|
error!("Unknown event for virtio-iommu");
|
||||||
|
@ -747,6 +747,11 @@ impl MemEpollHandler {
|
|||||||
while paused.load(Ordering::SeqCst) {
|
while paused.load(Ordering::SeqCst) {
|
||||||
thread::park();
|
thread::park();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drain pause event after the device has been resumed.
|
||||||
|
// This ensures the pause event has been seen by each
|
||||||
|
// and every thread related to this virtio device.
|
||||||
|
let _ = self.pause_evt.read();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(DeviceError::EpollHander(String::from(
|
return Err(DeviceError::EpollHander(String::from(
|
||||||
|
@ -395,8 +395,6 @@ impl NetEpollHandler {
|
|||||||
break 'epoll;
|
break 'epoll;
|
||||||
}
|
}
|
||||||
PAUSE_EVENT => {
|
PAUSE_EVENT => {
|
||||||
// Drain pause event
|
|
||||||
let _ = self.pause_evt.read();
|
|
||||||
debug!("PAUSE_EVENT received, pausing virtio-net epoll loop");
|
debug!("PAUSE_EVENT received, pausing virtio-net epoll loop");
|
||||||
|
|
||||||
// We loop here to handle spurious park() returns.
|
// We loop here to handle spurious park() returns.
|
||||||
@ -405,6 +403,11 @@ impl NetEpollHandler {
|
|||||||
while paused.load(Ordering::SeqCst) {
|
while paused.load(Ordering::SeqCst) {
|
||||||
thread::park();
|
thread::park();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drain pause event after the device has been resumed.
|
||||||
|
// This ensures the pause event has been seen by each
|
||||||
|
// and every thread related to this virtio device.
|
||||||
|
let _ = self.pause_evt.read();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("Unknown event for virtio-net");
|
error!("Unknown event for virtio-net");
|
||||||
|
@ -316,8 +316,6 @@ impl NetCtrlEpollHandler {
|
|||||||
break 'epoll;
|
break 'epoll;
|
||||||
}
|
}
|
||||||
PAUSE_EVENT => {
|
PAUSE_EVENT => {
|
||||||
// Drain pause event
|
|
||||||
let _ = self.pause_evt.read();
|
|
||||||
debug!("PAUSE_EVENT received, pausing vhost-user epoll loop");
|
debug!("PAUSE_EVENT received, pausing vhost-user epoll loop");
|
||||||
// We loop here to handle spurious park() returns.
|
// We loop here to handle spurious park() returns.
|
||||||
// Until we have not resumed, the paused boolean will
|
// Until we have not resumed, the paused boolean will
|
||||||
@ -325,6 +323,11 @@ impl NetCtrlEpollHandler {
|
|||||||
while paused.load(Ordering::SeqCst) {
|
while paused.load(Ordering::SeqCst) {
|
||||||
std::thread::park();
|
std::thread::park();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drain pause event after the device has been resumed.
|
||||||
|
// This ensures the pause event has been seen by each
|
||||||
|
// and every thread related to this virtio device.
|
||||||
|
let _ = self.pause_evt.read();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("Unknown event for virtio-net");
|
error!("Unknown event for virtio-net");
|
||||||
|
@ -324,8 +324,6 @@ impl PmemEpollHandler {
|
|||||||
break 'epoll;
|
break 'epoll;
|
||||||
}
|
}
|
||||||
PAUSE_EVENT => {
|
PAUSE_EVENT => {
|
||||||
// Drain pause event
|
|
||||||
let _ = self.pause_evt.read();
|
|
||||||
debug!("PAUSE_EVENT received, pausing virtio-pmem epoll loop");
|
debug!("PAUSE_EVENT received, pausing virtio-pmem epoll loop");
|
||||||
// We loop here to handle spurious park() returns.
|
// We loop here to handle spurious park() returns.
|
||||||
// Until we have not resumed, the paused boolean will
|
// Until we have not resumed, the paused boolean will
|
||||||
@ -333,6 +331,11 @@ impl PmemEpollHandler {
|
|||||||
while paused.load(Ordering::SeqCst) {
|
while paused.load(Ordering::SeqCst) {
|
||||||
thread::park();
|
thread::park();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drain pause event after the device has been resumed.
|
||||||
|
// This ensures the pause event has been seen by each
|
||||||
|
// and every thread related to this virtio device.
|
||||||
|
let _ = self.pause_evt.read();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("Unknown event for virtio-block");
|
error!("Unknown event for virtio-block");
|
||||||
|
@ -167,8 +167,6 @@ impl RngEpollHandler {
|
|||||||
break 'epoll;
|
break 'epoll;
|
||||||
}
|
}
|
||||||
PAUSE_EVENT => {
|
PAUSE_EVENT => {
|
||||||
// Drain pause event
|
|
||||||
let _ = self.pause_evt.read();
|
|
||||||
debug!("PAUSE_EVENT received, pausing virtio-rng epoll loop");
|
debug!("PAUSE_EVENT received, pausing virtio-rng epoll loop");
|
||||||
// We loop here to handle spurious park() returns.
|
// We loop here to handle spurious park() returns.
|
||||||
// Until we have not resumed, the paused boolean will
|
// Until we have not resumed, the paused boolean will
|
||||||
@ -176,6 +174,11 @@ impl RngEpollHandler {
|
|||||||
while paused.load(Ordering::SeqCst) {
|
while paused.load(Ordering::SeqCst) {
|
||||||
thread::park();
|
thread::park();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drain pause event after the device has been resumed.
|
||||||
|
// This ensures the pause event has been seen by each
|
||||||
|
// and every thread related to this virtio device.
|
||||||
|
let _ = self.pause_evt.read();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("Unknown event for virtio-block");
|
error!("Unknown event for virtio-block");
|
||||||
|
@ -163,8 +163,6 @@ impl<S: VhostUserMasterReqHandler> VhostUserEpollHandler<S> {
|
|||||||
break 'poll;
|
break 'poll;
|
||||||
}
|
}
|
||||||
x if pause_evt_index == x => {
|
x if pause_evt_index == x => {
|
||||||
// Drain pause event
|
|
||||||
let _ = self.vu_epoll_cfg.pause_evt.read();
|
|
||||||
debug!("PAUSE_EVENT received, pausing vhost-user epoll loop");
|
debug!("PAUSE_EVENT received, pausing vhost-user epoll loop");
|
||||||
// We loop here to handle spurious park() returns.
|
// We loop here to handle spurious park() returns.
|
||||||
// Until we have not resumed, the paused boolean will
|
// Until we have not resumed, the paused boolean will
|
||||||
@ -172,6 +170,11 @@ impl<S: VhostUserMasterReqHandler> VhostUserEpollHandler<S> {
|
|||||||
while paused.load(Ordering::SeqCst) {
|
while paused.load(Ordering::SeqCst) {
|
||||||
thread::park();
|
thread::park();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drain pause event after the device has been resumed.
|
||||||
|
// This ensures the pause event has been seen by each
|
||||||
|
// and every thread related to this virtio device.
|
||||||
|
let _ = self.vu_epoll_cfg.pause_evt.read();
|
||||||
}
|
}
|
||||||
x if (slave_evt_index.is_some() && slave_evt_index.unwrap() == x) => {
|
x if (slave_evt_index.is_some() && slave_evt_index.unwrap() == x) => {
|
||||||
if let Some(slave_req_handler) =
|
if let Some(slave_req_handler) =
|
||||||
|
@ -365,8 +365,6 @@ where
|
|||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
PAUSE_EVENT => {
|
PAUSE_EVENT => {
|
||||||
// Drain pause event
|
|
||||||
let _ = self.pause_evt.read();
|
|
||||||
debug!("PAUSE_EVENT received, pausing virtio-vsock epoll loop");
|
debug!("PAUSE_EVENT received, pausing virtio-vsock epoll loop");
|
||||||
// We loop here to handle spurious park() returns.
|
// We loop here to handle spurious park() returns.
|
||||||
// Until we have not resumed, the paused boolean will
|
// Until we have not resumed, the paused boolean will
|
||||||
@ -374,6 +372,11 @@ where
|
|||||||
while paused.load(Ordering::SeqCst) {
|
while paused.load(Ordering::SeqCst) {
|
||||||
thread::park();
|
thread::park();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drain pause event after the device has been resumed.
|
||||||
|
// This ensures the pause event has been seen by each
|
||||||
|
// and every thread related to this virtio device.
|
||||||
|
let _ = self.pause_evt.read();
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
error!("Unknown event for virtio-vsock");
|
error!("Unknown event for virtio-vsock");
|
||||||
|
Loading…
Reference in New Issue
Block a user