vm-virtio: Extend Queue helpers

First, this modifies the existing helpers on how to get indexes for
available and used rings from memory. Instead of updating the queue
through each helper, they are now used as simple getters.

Based on these new getters, we could create a new helper to determine if
the queue has some available descriptors already queued from the driver
side. This helper is going to be particularly helpful when trying to
determine from a virtio thread if a queue is already loaded with some
available buffers that can be used to send information to the guest.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2020-04-21 17:32:26 +02:00
parent c22fd39170
commit cf707da1a8
2 changed files with 40 additions and 37 deletions

View File

@ -17,7 +17,8 @@ use std::sync::Arc;
use crate::device::VirtioIommuRemapping;
use vm_memory::{
Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap, GuestUsize,
Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryMmap,
GuestUsize,
};
pub(super) const VIRTQ_DESC_F_NEXT: u16 = 0x1;
@ -29,6 +30,8 @@ pub enum Error {
GuestMemoryError,
InvalidIndirectDescriptor,
InvalidChain,
InvalidOffset(u64),
InvalidRingIndexFromMemory(GuestMemoryError),
}
impl Display for Error {
@ -39,6 +42,8 @@ impl Display for Error {
GuestMemoryError => write!(f, "error accessing guest memory"),
InvalidChain => write!(f, "invalid descriptor chain"),
InvalidIndirectDescriptor => write!(f, "invalid indirect descriptor"),
InvalidOffset(o) => write!(f, "invalid offset {}", o),
InvalidRingIndexFromMemory(e) => write!(f, "invalid ring index from memory: {}", e),
}
}
}
@ -649,44 +654,27 @@ impl Queue {
self.next_avail -= Wrapping(1);
}
/// Get latest index from available ring.
pub fn update_avail_index_from_memory(&mut self, mem: &GuestMemoryMmap) {
let index_addr = match mem.checked_offset(self.avail_ring, 2) {
Some(ret) => ret,
None => {
error!("Invalid offset 0x{:x}", self.avail_ring.raw_value() + 2);
return;
/// Get ring's index from memory.
fn index_from_memory(&self, ring: GuestAddress, mem: &GuestMemoryMmap) -> Result<u16, Error> {
mem.read_obj::<u16>(
mem.checked_offset(ring, 2)
.ok_or_else(|| Error::InvalidOffset(ring.raw_value() + 2))?,
)
.map_err(Error::InvalidRingIndexFromMemory)
}
};
let next_avail: u16 = match mem.read_obj::<u16>(index_addr) {
Ok(ret) => ret,
Err(e) => {
error!("Couldn't read `idx` field from memory: {}", e);
return;
}
};
self.next_avail = Wrapping(next_avail);
/// Get latest index from available ring.
pub fn avail_index_from_memory(&self, mem: &GuestMemoryMmap) -> Result<u16, Error> {
self.index_from_memory(self.avail_ring, mem)
}
/// Get latest index from used ring.
pub fn update_used_index_from_memory(&mut self, mem: &GuestMemoryMmap) {
let index_addr = match mem.checked_offset(self.used_ring, 2) {
Some(ret) => ret,
None => {
error!("Invalid offset 0x{:x}", self.used_ring.raw_value() + 2);
return;
pub fn used_index_from_memory(&self, mem: &GuestMemoryMmap) -> Result<u16, Error> {
self.index_from_memory(self.used_ring, mem)
}
};
let next_used: u16 = match mem.read_obj::<u16>(index_addr) {
Ok(ret) => ret,
Err(e) => {
error!("Couldn't read `idx` field from memory: {}", e);
return;
}
};
self.next_used = Wrapping(next_used);
pub fn available_descriptors(&self, mem: &GuestMemoryMmap) -> Result<bool, Error> {
Ok(self.used_index_from_memory(mem)? < self.avail_index_from_memory(mem)?)
}
}

View File

@ -12,6 +12,7 @@ use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian};
use devices::BusDevice;
use libc::EFD_NONBLOCK;
use std::num::Wrapping;
use std::result;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
@ -28,6 +29,12 @@ const VENDOR_ID: u32 = 0;
const MMIO_MAGIC_VALUE: u32 = 0x7472_6976;
const MMIO_VERSION: u32 = 2;
#[derive(Debug)]
enum Error {
/// Failed to retrieve queue ring's index.
QueueRingIndex(crate::queue::Error),
}
pub struct VirtioInterruptIntx {
interrupt_status: Arc<AtomicUsize>,
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
@ -152,7 +159,7 @@ impl MmioDevice {
}
}
fn set_state(&mut self, state: &VirtioMmioDeviceState) -> Result<()> {
fn set_state(&mut self, state: &VirtioMmioDeviceState) -> std::result::Result<(), Error> {
self.device_activated = state.device_activated;
self.features_select = state.features_select;
self.acked_features_select = state.acked_features_select;
@ -166,8 +173,16 @@ impl MmioDevice {
if let Some(mem) = self.mem.as_ref() {
let mem = mem.memory();
for queue in self.queues.iter_mut() {
queue.update_avail_index_from_memory(&mem);
queue.update_used_index_from_memory(&mem);
queue.next_avail = Wrapping(
queue
.avail_index_from_memory(&mem)
.map_err(Error::QueueRingIndex)?,
);
queue.next_used = Wrapping(
queue
.used_index_from_memory(&mem)
.map_err(Error::QueueRingIndex)?,
);
}
}