From c2137e33a028c9fd29199d4136b91a40a8f42211 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Wed, 19 May 2021 16:53:53 +0200 Subject: [PATCH] vhost_user_backend: Don't discard events when queue is not enabled The vhost crate does not support the need_reply flag yet, meaning we can't be sure the backend is properly setup before the guest goes on. One can run in a race condition where the VMM enables the vring, but never gets any acknowledgement, meaning it assumes everything went well and finalize the virtio device activation. Once the device is seen as ready by the guest, it keeps going by sending some messages through the virtqueues. Problem is, if it took some time for the backend to enable the queue, one of the backend thread might receive a kick from the guest while the corresponding queue is not enabled. This leads to the loss of the event as it is discarded because the queue is not enabled. Until vhost crate allows for requests with ACK, the way to mitigate this issue is by ignoring an event coming up on a queue that has not been enabled. Signed-off-by: Sebastien Boeuf --- vhost_user_backend/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vhost_user_backend/src/lib.rs b/vhost_user_backend/src/lib.rs index e6bdfa0c8..134703a35 100644 --- a/vhost_user_backend/src/lib.rs +++ b/vhost_user_backend/src/lib.rs @@ -295,16 +295,16 @@ impl VringEpollHandler { let num_queues = self.vrings.len(); if (device_event as usize) < num_queues { + // If the vring is not enabled, it should not be processed. + // But let's not read it (hence lose it) in case it is later enabled. + if !self.vrings[device_event as usize].read().unwrap().enabled { + return Ok(false); + } + if let Some(kick) = &self.vrings[device_event as usize].read().unwrap().kick { kick.read() .map_err(VringEpollHandlerError::HandleEventReadKick)?; } - - // If the vring is not enabled, it should not be processed. - // The event is only read to be discarded. - if !self.vrings[device_event as usize].read().unwrap().enabled { - return Ok(false); - } } self.backend