vm-virtio: Implement support for EVENT_IDX

VIRTIO_RING_F_EVENT_IDX is a virtio feature that allows to avoid
device <-> driver notifications under some circunstances, most
notably when actively polling the queue.

This commit implements support for in in the vm-virtio
crate. Consumers of this crate will also need to add support for it by
exposing the feature and calling using update_avail_event() and
get_used_event() accordingly.

Signed-off-by: Sergio Lopez <slp@redhat.com>
This commit is contained in:
Sergio Lopez 2020-02-14 06:14:27 -05:00 committed by Rob Bradford
parent 793d4e7b8d
commit d17fa784bc
2 changed files with 51 additions and 2 deletions

View File

@ -447,14 +447,59 @@ impl Queue {
}
}
/// Update avail_event on the used ring with the last index in the avail ring.
pub fn update_avail_event(&mut self, mem: &GuestMemoryMmap) {
let index_addr = match mem.checked_offset(self.avail_ring, 2) {
Some(ret) => ret,
None => {
// TODO log address
warn!("Invalid offset");
return;
}
};
// Note that last_index has no invalid values
let last_index: u16 = match mem.read_obj::<u16>(index_addr) {
Ok(ret) => ret,
Err(_) => return,
};
match mem.checked_offset(self.used_ring, (4 + self.actual_size() * 8) as usize) {
Some(a) => {
mem.write_obj(last_index, a).unwrap();
}
None => warn!("Can't update avail_event"),
}
// This fence ensures all descriptor writes are visible before the index update is.
fence(Ordering::Release);
}
/// Return the value present in the used_event field of the avail ring.
pub fn get_used_event(&self, mem: &GuestMemoryMmap) -> Option<Wrapping<u16>> {
let avail_ring = self.avail_ring;
let used_event_addr =
match mem.checked_offset(avail_ring, (4 + self.actual_size() * 2) as usize) {
Some(a) => a,
None => {
warn!("Invalid offset looking for used_event");
return None;
}
};
match mem.read_obj::<u16>(used_event_addr) {
Ok(ret) => Some(Wrapping(ret)),
Err(_) => None,
}
}
/// Puts an available descriptor head into the used ring for use by the guest.
pub fn add_used(&mut self, mem: &GuestMemoryMmap, desc_index: u16, len: u32) {
pub fn add_used(&mut self, mem: &GuestMemoryMmap, desc_index: u16, len: u32) -> Option<u16> {
if desc_index >= self.actual_size() {
error!(
"attempted to add out of bounds descriptor to used ring: {}",
desc_index
);
return;
return None;
}
let used_ring = self.used_ring;
@ -473,6 +518,8 @@ impl Queue {
mem.write_obj(self.next_used.0 as u16, used_ring.unchecked_add(2))
.unwrap();
Some(self.next_used.0)
}
/// Goes back one position in the available descriptor chain offered by the driver.

View File

@ -24,6 +24,7 @@ use vhost_rs::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFe
use vhost_rs::vhost_user::{Master, VhostUserMaster, VhostUserMasterReqHandler};
use vhost_rs::VhostBackend;
use virtio_bindings::bindings::virtio_blk::*;
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
use vm_device::{Migratable, MigratableError, Pausable, Snapshotable};
use vm_memory::{ByteValued, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap};
use vmm_sys_util::eventfd::EventFd;
@ -57,6 +58,7 @@ impl Blk {
| 1 << VIRTIO_BLK_F_BLK_SIZE
| 1 << VIRTIO_BLK_F_FLUSH
| 1 << VIRTIO_BLK_F_TOPOLOGY
| 1 << VIRTIO_RING_F_EVENT_IDX
| 1 << VIRTIO_F_VERSION_1
| VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();