mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 21:55: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::convert::TryInto;
|
||||||
use std::fs::{File, Metadata};
|
use std::fs::{File, Metadata};
|
||||||
use std::io::{self, Read, Seek, SeekFrom, Write};
|
use std::io::{self, Read, Seek, SeekFrom, Write};
|
||||||
|
use std::num::Wrapping;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::os::linux::fs::MetadataExt;
|
use std::os::linux::fs::MetadataExt;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
@ -33,6 +34,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use virtio_bindings::bindings::virtio_blk::*;
|
use virtio_bindings::bindings::virtio_blk::*;
|
||||||
|
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
|
||||||
use vm_memory::{
|
use vm_memory::{
|
||||||
ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||||
GuestMemoryError, GuestMemoryMmap,
|
GuestMemoryError, GuestMemoryMmap,
|
||||||
@ -604,6 +606,8 @@ struct BlockEpollHandler<T: DiskFile> {
|
|||||||
disk_image_id: Vec<u8>,
|
disk_image_id: Vec<u8>,
|
||||||
kill_evt: EventFd,
|
kill_evt: EventFd,
|
||||||
pause_evt: EventFd,
|
pause_evt: EventFd,
|
||||||
|
event_idx: bool,
|
||||||
|
signalled_used: Option<Wrapping<u16>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: DiskFile> BlockEpollHandler<T> {
|
impl<T: DiskFile> BlockEpollHandler<T> {
|
||||||
@ -678,6 +682,25 @@ impl<T: DiskFile> BlockEpollHandler<T> {
|
|||||||
Ok(())
|
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(
|
fn run(
|
||||||
&mut self,
|
&mut self,
|
||||||
queue_evt: EventFd,
|
queue_evt: EventFd,
|
||||||
@ -738,6 +761,28 @@ impl<T: DiskFile> BlockEpollHandler<T> {
|
|||||||
if let Err(e) = queue_evt.read() {
|
if let Err(e) = queue_evt.read() {
|
||||||
error!("Failed to get queue event: {:?}", e);
|
error!("Failed to get queue event: {:?}", e);
|
||||||
break 'epoll;
|
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() {
|
} else if self.process_queue() {
|
||||||
if let Err(e) = self.signal_used_queue() {
|
if let Err(e) = self.signal_used_queue() {
|
||||||
error!("Failed to signal used queue: {:?}", e);
|
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 {
|
if iommu {
|
||||||
avail_features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM;
|
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);
|
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();
|
let mut epoll_threads = Vec::new();
|
||||||
for _ in 0..self.queue_size.len() {
|
for _ in 0..self.queue_size.len() {
|
||||||
let mut handler = BlockEpollHandler {
|
let mut handler = BlockEpollHandler {
|
||||||
@ -1123,6 +1173,8 @@ impl<T: 'static + DiskFile + Send> VirtioDevice for Block<T> {
|
|||||||
disk_image_id: disk_image_id.clone(),
|
disk_image_id: disk_image_id.clone(),
|
||||||
kill_evt: kill_evt.try_clone().unwrap(),
|
kill_evt: kill_evt.try_clone().unwrap(),
|
||||||
pause_evt: pause_evt.try_clone().unwrap(),
|
pause_evt: pause_evt.try_clone().unwrap(),
|
||||||
|
event_idx,
|
||||||
|
signalled_used: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let queue_evt = queue_evts.remove(0);
|
let queue_evt = queue_evts.remove(0);
|
||||||
|
Loading…
Reference in New Issue
Block a user