mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices: fix barrier handling in virtio-net
When configuring multiple queues for a virtio device, the guest can activate between 1 and the configured amout of queues. The firmware, for example, may activate only one queue, while a Linux guest would likely activate all available queues. The constructor of virtio-net initializes the `paused_sync` barrier using the configured queue count (plus one for the main thread). This can be wrong if the guest enables a different number of queues at activation time, which can make pause hang. Thus, we now recompute the barrier size from the queues that are actually activated. On-behalf-of: SAP sebastian.eydam@sap.com Signed-off-by: Sebastian Eydam <sebastian.eydam@cyberus-technology.de>
This commit is contained in:
committed by
Rob Bradford
parent
92109136f1
commit
882f82f04b
@@ -752,7 +752,15 @@ impl VirtioDevice for Net {
|
||||
|
||||
let num_queues = queues.len();
|
||||
let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into());
|
||||
if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && !num_queues.is_multiple_of(2) {
|
||||
|
||||
// Recompute the barrier size from the queues that are actually activated.
|
||||
let has_ctrl_queue =
|
||||
self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && !num_queues.is_multiple_of(2);
|
||||
let ctrl_threads = if has_ctrl_queue { 1 } else { 0 };
|
||||
let qp_threads = (num_queues - ctrl_threads) / 2;
|
||||
self.common.paused_sync = Some(Arc::new(Barrier::new(1 + qp_threads + ctrl_threads)));
|
||||
|
||||
if has_ctrl_queue {
|
||||
let ctrl_queue_index = num_queues - 1;
|
||||
let (_, mut ctrl_queue, ctrl_queue_evt) = queues.remove(ctrl_queue_index);
|
||||
|
||||
@@ -772,10 +780,6 @@ impl VirtioDevice for Net {
|
||||
};
|
||||
|
||||
let paused = self.common.paused.clone();
|
||||
// Let's update the barrier as we need 1 for each RX/TX pair +
|
||||
// 1 for the control queue + 1 for the main thread signalling
|
||||
// the pause.
|
||||
self.common.paused_sync = Some(Arc::new(Barrier::new(self.taps.len() + 2)));
|
||||
let paused_sync = self.common.paused_sync.clone();
|
||||
|
||||
let mut epoll_threads = Vec::new();
|
||||
|
||||
Reference in New Issue
Block a user