mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-27 23:23:09 +00:00
virtio-devices: Support driver programming fewer queues
It is permissable for the driver to program fewer queues than offered by the device. Filter the queues so that only the ready ones are included and check that they have valid addresses configured. Fixes: #2136 Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
c366efc19e
commit
a105089702
@ -250,10 +250,10 @@ impl VirtioCommon {
|
|||||||
queue_evts: &[EventFd],
|
queue_evts: &[EventFd],
|
||||||
interrupt_cb: &Arc<dyn VirtioInterrupt>,
|
interrupt_cb: &Arc<dyn VirtioInterrupt>,
|
||||||
) -> ActivateResult {
|
) -> ActivateResult {
|
||||||
if queues.len() != self.queue_sizes.len() || queue_evts.len() != self.queue_sizes.len() {
|
if queues.len() != queue_evts.len() {
|
||||||
error!(
|
error!(
|
||||||
"Cannot perform activate. Expected {} queue(s), got {}",
|
"Cannot activate: length mismatch: queue_evts={} queues={}",
|
||||||
self.queue_sizes.len(),
|
queue_evts.len(),
|
||||||
queues.len()
|
queues.len()
|
||||||
);
|
);
|
||||||
return Err(ActivateError::BadActivate);
|
return Err(ActivateError::BadActivate);
|
||||||
|
@ -14,7 +14,7 @@ extern crate vmm_sys_util;
|
|||||||
use super::VirtioPciCommonConfig;
|
use super::VirtioPciCommonConfig;
|
||||||
use crate::transport::VirtioTransport;
|
use crate::transport::VirtioTransport;
|
||||||
use crate::{
|
use crate::{
|
||||||
Queue, VirtioDevice, VirtioDeviceType, VirtioInterrupt, VirtioInterruptType,
|
ActivateResult, Queue, VirtioDevice, VirtioDeviceType, VirtioInterrupt, VirtioInterruptType,
|
||||||
DEVICE_ACKNOWLEDGE, DEVICE_DRIVER, DEVICE_DRIVER_OK, DEVICE_FAILED, DEVICE_FEATURES_OK,
|
DEVICE_ACKNOWLEDGE, DEVICE_DRIVER, DEVICE_DRIVER_OK, DEVICE_FAILED, DEVICE_FEATURES_OK,
|
||||||
DEVICE_INIT, VIRTIO_MSI_NO_VECTOR,
|
DEVICE_INIT, VIRTIO_MSI_NO_VECTOR,
|
||||||
};
|
};
|
||||||
@ -515,14 +515,6 @@ impl VirtioPciDevice {
|
|||||||
self.common_config.driver_status == DEVICE_INIT as u8
|
self.common_config.driver_status == DEVICE_INIT as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
fn are_queues_valid(&self) -> bool {
|
|
||||||
if let Some(mem) = self.memory.as_ref() {
|
|
||||||
self.queues.iter().all(|q| q.is_valid(&mem.memory()))
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function is used by the caller to provide the expected base address
|
// This function is used by the caller to provide the expected base address
|
||||||
// for the virtio-pci configuration BAR.
|
// for the virtio-pci configuration BAR.
|
||||||
pub fn set_config_bar_addr(&mut self, bar_addr: u64) {
|
pub fn set_config_bar_addr(&mut self, bar_addr: u64) {
|
||||||
@ -653,35 +645,40 @@ impl VirtioPciDevice {
|
|||||||
self.device.clone()
|
self.device.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maybe_activate(&mut self) {
|
fn activate(&mut self) -> ActivateResult {
|
||||||
if self.needs_activation() {
|
|
||||||
if let Some(virtio_interrupt) = self.virtio_interrupt.take() {
|
if let Some(virtio_interrupt) = self.virtio_interrupt.take() {
|
||||||
if self.memory.is_some() {
|
if self.memory.is_some() {
|
||||||
let mem = self.memory.as_ref().unwrap().clone();
|
let mem = self.memory.as_ref().unwrap().clone();
|
||||||
let mut device = self.device.lock().unwrap();
|
let mut device = self.device.lock().unwrap();
|
||||||
let mut queue_evts = Vec::new();
|
let mut queue_evts = Vec::new();
|
||||||
let queues = self.queues.clone();
|
let mut queues = self.queues.clone();
|
||||||
for i in 0..queues.len() {
|
queues.retain(|q| q.ready);
|
||||||
|
for (i, queue) in queues.iter().enumerate() {
|
||||||
queue_evts.push(self.queue_evts[i].try_clone().unwrap());
|
queue_evts.push(self.queue_evts[i].try_clone().unwrap());
|
||||||
|
if !queue.is_valid(&mem.memory()) {
|
||||||
|
error!("Queue {} is not valid", i);
|
||||||
}
|
}
|
||||||
device
|
}
|
||||||
.activate(mem, virtio_interrupt, queues, queue_evts)
|
return device.activate(mem, virtio_interrupt, queues, queue_evts);
|
||||||
.expect("Failed to activate device");
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn maybe_activate(&mut self) {
|
||||||
|
if self.needs_activation() {
|
||||||
|
self.activate().expect("Failed to activate device");
|
||||||
self.device_activated.store(true, Ordering::SeqCst);
|
self.device_activated.store(true, Ordering::SeqCst);
|
||||||
info!("{}: Waiting for barrier", self.id);
|
info!("{}: Waiting for barrier", self.id);
|
||||||
self.activate_barrier.wait();
|
self.activate_barrier.wait();
|
||||||
info!("{}: Barrier released", self.id);
|
info!("{}: Barrier released", self.id);
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
info!("{}: Device does not need activation", self.id)
|
info!("{}: Device does not need activation", self.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn needs_activation(&self) -> bool {
|
fn needs_activation(&self) -> bool {
|
||||||
!self.device_activated.load(Ordering::SeqCst)
|
!self.device_activated.load(Ordering::SeqCst) && self.is_driver_ready()
|
||||||
&& self.is_driver_ready()
|
|
||||||
&& self.are_queues_valid()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1152,30 +1149,11 @@ impl Snapshottable for VirtioPciDevice {
|
|||||||
// Then we can activate the device, as we know at this point that
|
// Then we can activate the device, as we know at this point that
|
||||||
// the virtqueues are in the right state and the device is ready
|
// the virtqueues are in the right state and the device is ready
|
||||||
// to be activated, which will spawn each virtio worker thread.
|
// to be activated, which will spawn each virtio worker thread.
|
||||||
if self.device_activated.load(Ordering::SeqCst)
|
if self.device_activated.load(Ordering::SeqCst) && self.is_driver_ready() {
|
||||||
&& self.is_driver_ready()
|
self.activate().map_err(|e| {
|
||||||
&& self.are_queues_valid()
|
MigratableError::Restore(anyhow!("Failed activating the device: {:?}", e))
|
||||||
{
|
|
||||||
if let Some(virtio_interrupt) = self.virtio_interrupt.take() {
|
|
||||||
if self.memory.is_some() {
|
|
||||||
let mem = self.memory.as_ref().unwrap().clone();
|
|
||||||
let mut device = self.device.lock().unwrap();
|
|
||||||
let mut queue_evts = Vec::new();
|
|
||||||
let queues = self.queues.clone();
|
|
||||||
for i in 0..queues.len() {
|
|
||||||
queue_evts.push(self.queue_evts[i].try_clone().unwrap());
|
|
||||||
}
|
|
||||||
device
|
|
||||||
.activate(mem, virtio_interrupt, queues, queue_evts)
|
|
||||||
.map_err(|e| {
|
|
||||||
MigratableError::Restore(anyhow!(
|
|
||||||
"Failed activating the device: {:?}",
|
|
||||||
e
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user