mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
vm-virtio: block: Add support for VIRTIO_RING_F_EVENT_IDX
Permit the guest to suppress interrupts from the host as an optimisation. Fixes: #786 Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
5a55fc0737
commit
4366dd92ac
@ -23,6 +23,7 @@ use std::cmp;
|
||||
use std::convert::TryInto;
|
||||
use std::fs::{File, Metadata};
|
||||
use std::io::{self, Read, Seek, SeekFrom, Write};
|
||||
use std::num::Wrapping;
|
||||
use std::ops::DerefMut;
|
||||
use std::os::linux::fs::MetadataExt;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
@ -33,6 +34,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use virtio_bindings::bindings::virtio_blk::*;
|
||||
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
|
||||
use vm_memory::{
|
||||
ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||
GuestMemoryError, GuestMemoryMmap,
|
||||
@ -604,6 +606,8 @@ struct BlockEpollHandler<T: DiskFile> {
|
||||
disk_image_id: Vec<u8>,
|
||||
kill_evt: EventFd,
|
||||
pause_evt: EventFd,
|
||||
event_idx: bool,
|
||||
signalled_used: Option<Wrapping<u16>>,
|
||||
}
|
||||
|
||||
impl<T: DiskFile> BlockEpollHandler<T> {
|
||||
@ -678,6 +682,25 @@ impl<T: DiskFile> BlockEpollHandler<T> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn needs_notification(&mut self, mem: &GuestMemoryMmap, used_idx: Wrapping<u16>) -> bool {
|
||||
if !self.event_idx {
|
||||
return true;
|
||||
}
|
||||
|
||||
let mut notify = true;
|
||||
|
||||
if let Some(old_idx) = self.signalled_used {
|
||||
if let Some(used_event) = self.queue.get_used_event(&mem) {
|
||||
if (used_idx - used_event - Wrapping(1u16)) >= (used_idx - old_idx) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.signalled_used = Some(used_idx);
|
||||
notify
|
||||
}
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
queue_evt: EventFd,
|
||||
@ -738,6 +761,28 @@ impl<T: DiskFile> BlockEpollHandler<T> {
|
||||
if let Err(e) = queue_evt.read() {
|
||||
error!("Failed to get queue event: {:?}", e);
|
||||
break 'epoll;
|
||||
} else if self.event_idx {
|
||||
// vm-virtio's Queue implementation only checks avail_index
|
||||
// once, so to properly support EVENT_IDX we need to keep
|
||||
// calling process_queue() until it stops finding new
|
||||
// requests on the queue.
|
||||
loop {
|
||||
if self.process_queue() {
|
||||
self.queue.update_avail_event(&self.mem.memory());
|
||||
|
||||
if self.needs_notification(
|
||||
&self.mem.memory(),
|
||||
self.queue.next_used,
|
||||
) {
|
||||
if let Err(e) = self.signal_used_queue() {
|
||||
error!("Failed to signal used queue: {:?}", e);
|
||||
break 'epoll;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if self.process_queue() {
|
||||
if let Err(e) = self.signal_used_queue() {
|
||||
error!("Failed to signal used queue: {:?}", e);
|
||||
@ -934,7 +979,9 @@ impl<T: DiskFile> Block<T> {
|
||||
);
|
||||
}
|
||||
|
||||
let mut avail_features = (1u64 << VIRTIO_F_VERSION_1) | (1u64 << VIRTIO_BLK_F_FLUSH);
|
||||
let mut avail_features = (1u64 << VIRTIO_F_VERSION_1)
|
||||
| (1u64 << VIRTIO_BLK_F_FLUSH)
|
||||
| (1u64 << VIRTIO_RING_F_EVENT_IDX);
|
||||
|
||||
if iommu {
|
||||
avail_features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM;
|
||||
@ -1112,6 +1159,9 @@ impl<T: 'static + DiskFile + Send> VirtioDevice for Block<T> {
|
||||
}
|
||||
self.queue_evts = Some(tmp_queue_evts);
|
||||
|
||||
let event_idx = self.acked_features & 1u64 << VIRTIO_RING_F_EVENT_IDX
|
||||
== 1u64 << VIRTIO_RING_F_EVENT_IDX;
|
||||
|
||||
let mut epoll_threads = Vec::new();
|
||||
for _ in 0..self.queue_size.len() {
|
||||
let mut handler = BlockEpollHandler {
|
||||
@ -1123,6 +1173,8 @@ impl<T: 'static + DiskFile + Send> VirtioDevice for Block<T> {
|
||||
disk_image_id: disk_image_id.clone(),
|
||||
kill_evt: kill_evt.try_clone().unwrap(),
|
||||
pause_evt: pause_evt.try_clone().unwrap(),
|
||||
event_idx,
|
||||
signalled_used: None,
|
||||
};
|
||||
|
||||
let queue_evt = queue_evts.remove(0);
|
||||
|
Loading…
Reference in New Issue
Block a user