mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Move Cloud Hypervisor to virtio-queue crate
Relying on the vm-virtio/virtio-queue crate from rust-vmm which has been copied inside the Cloud Hypervisor tree, the entire codebase is moved to the new definition of a Queue and other related structures. The reason for this move is to follow the upstream until we get some agreement for the patches that we need on top of that to make it properly work with Cloud Hypervisor. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
@@ -31,6 +31,7 @@ versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vhost = { version = "0.2.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern"] }
|
||||
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
||||
virtio-queue = { path = "../virtio-queue" }
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
// limitations under the License.
|
||||
|
||||
use super::{
|
||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue,
|
||||
VirtioCommon, VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1,
|
||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, VirtioCommon,
|
||||
VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1,
|
||||
};
|
||||
use crate::seccomp_filters::Thread;
|
||||
use crate::thread_helper::spawn_virtio_thread;
|
||||
@@ -31,11 +31,9 @@ use std::sync::mpsc;
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::GuestMemory;
|
||||
use vm_memory::{
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic,
|
||||
GuestMemoryError,
|
||||
};
|
||||
use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryError};
|
||||
use vm_migration::VersionMapped;
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@@ -81,6 +79,12 @@ pub enum Error {
|
||||
ProcessQueueWrongEvType(u16),
|
||||
// Fail tp signal
|
||||
FailedSignal(io::Error),
|
||||
/// Descriptor chain is too short
|
||||
DescriptorChainTooShort,
|
||||
/// Failed adding used index
|
||||
QueueAddUsed(virtio_queue::Error),
|
||||
/// Failed creating an iterator over the queue
|
||||
QueueIterator(virtio_queue::Error),
|
||||
}
|
||||
|
||||
// Got from include/uapi/linux/virtio_balloon.h
|
||||
@@ -152,8 +156,7 @@ impl VirtioBalloonResize {
|
||||
struct BalloonEpollHandler {
|
||||
config: Arc<Mutex<VirtioBalloonConfig>>,
|
||||
resize_receiver: VirtioBalloonResizeReceiver,
|
||||
queues: Vec<Queue>,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
inflate_queue_evt: EventFd,
|
||||
deflate_queue_evt: EventFd,
|
||||
@@ -165,7 +168,7 @@ impl BalloonEpollHandler {
|
||||
fn signal(
|
||||
&self,
|
||||
int_type: &VirtioInterruptType,
|
||||
queue: Option<&Queue>,
|
||||
queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
) -> result::Result<(), Error> {
|
||||
self.interrupt_cb.trigger(int_type, queue).map_err(|e| {
|
||||
error!("Failed to signal used queue: {:?}", e);
|
||||
@@ -182,38 +185,45 @@ impl BalloonEpollHandler {
|
||||
|
||||
let mut used_desc_heads = [0; QUEUE_SIZE as usize];
|
||||
let mut used_count = 0;
|
||||
let mem = self.mem.memory();
|
||||
for avail_desc in self.queues[queue_index].iter(&mem) {
|
||||
used_desc_heads[used_count] = avail_desc.index;
|
||||
for mut desc_chain in self.queues[queue_index]
|
||||
.iter()
|
||||
.map_err(Error::QueueIterator)?
|
||||
{
|
||||
let desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
|
||||
|
||||
used_desc_heads[used_count] = desc_chain.head_index();
|
||||
used_count += 1;
|
||||
|
||||
let data_chunk_size = size_of::<u32>();
|
||||
|
||||
// The head contains the request type which MUST be readable.
|
||||
if avail_desc.is_write_only() {
|
||||
if desc.is_write_only() {
|
||||
error!("The head contains the request type is not right");
|
||||
return Err(Error::UnexpectedWriteOnlyDescriptor);
|
||||
}
|
||||
if avail_desc.len as usize % data_chunk_size != 0 {
|
||||
error!("the request size {} is not right", avail_desc.len);
|
||||
if desc.len() as usize % data_chunk_size != 0 {
|
||||
error!("the request size {} is not right", desc.len());
|
||||
return Err(Error::InvalidRequest);
|
||||
}
|
||||
|
||||
let mut offset = 0u64;
|
||||
while offset < avail_desc.len as u64 {
|
||||
let addr = avail_desc.addr.checked_add(offset).unwrap();
|
||||
let pfn: u32 = mem.read_obj(addr).map_err(Error::GuestMemory)?;
|
||||
while offset < desc.len() as u64 {
|
||||
let addr = desc.addr().checked_add(offset).unwrap();
|
||||
let pfn: u32 = desc_chain
|
||||
.memory()
|
||||
.read_obj(addr)
|
||||
.map_err(Error::GuestMemory)?;
|
||||
offset += data_chunk_size as u64;
|
||||
|
||||
let gpa = (pfn as u64) << VIRTIO_BALLOON_PFN_SHIFT;
|
||||
if let Ok(hva) = mem.get_host_address(GuestAddress(gpa)) {
|
||||
if let Ok(hva) = desc_chain.memory().get_host_address(GuestAddress(gpa)) {
|
||||
let advice = match ev_type {
|
||||
INFLATE_QUEUE_EVENT => {
|
||||
let region =
|
||||
mem.find_region(GuestAddress(gpa))
|
||||
.ok_or(Error::GuestMemory(
|
||||
GuestMemoryError::InvalidGuestAddress(GuestAddress(gpa)),
|
||||
))?;
|
||||
let region = desc_chain.memory().find_region(GuestAddress(gpa)).ok_or(
|
||||
Error::GuestMemory(GuestMemoryError::InvalidGuestAddress(
|
||||
GuestAddress(gpa),
|
||||
)),
|
||||
)?;
|
||||
if let Some(f_off) = region.file_offset() {
|
||||
let offset = hva as usize - region.as_ptr() as usize;
|
||||
let res = unsafe {
|
||||
@@ -253,7 +263,9 @@ impl BalloonEpollHandler {
|
||||
}
|
||||
|
||||
for &desc_index in &used_desc_heads[..used_count] {
|
||||
self.queues[queue_index].add_used(&mem, desc_index, 0);
|
||||
self.queues[queue_index]
|
||||
.add_used(desc_index, 0)
|
||||
.map_err(Error::QueueAddUsed)?;
|
||||
}
|
||||
if used_count > 0 {
|
||||
self.signal(&VirtioInterruptType::Queue, Some(&self.queues[queue_index]))?;
|
||||
@@ -463,9 +475,9 @@ impl VirtioDevice for Balloon {
|
||||
|
||||
fn activate(
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
_mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
mut queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
@@ -478,7 +490,6 @@ impl VirtioDevice for Balloon {
|
||||
ActivateError::BadActivate
|
||||
})?,
|
||||
queues,
|
||||
mem,
|
||||
interrupt_cb,
|
||||
inflate_queue_evt: queue_evts.remove(0),
|
||||
deflate_queue_evt: queue_evts.remove(0),
|
||||
|
||||
+28
-16
@@ -10,7 +10,7 @@
|
||||
|
||||
use super::Error as DeviceError;
|
||||
use super::{
|
||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue,
|
||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler,
|
||||
RateLimiterConfig, VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType,
|
||||
EPOLL_HELPER_EVENT_LAST,
|
||||
};
|
||||
@@ -35,6 +35,7 @@ use std::{collections::HashMap, convert::TryInto};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_bindings::bindings::virtio_blk::*;
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::{ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic};
|
||||
use vm_migration::VersionMapped;
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
@@ -62,6 +63,10 @@ pub enum Error {
|
||||
AsyncRequestFailure,
|
||||
/// Failed synchronizing the file
|
||||
Fsync(AsyncIoError),
|
||||
/// Failed adding used index
|
||||
QueueAddUsed(virtio_queue::Error),
|
||||
/// Failed creating an iterator over the queue
|
||||
QueueIterator(virtio_queue::Error),
|
||||
}
|
||||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
@@ -75,7 +80,7 @@ pub struct BlockCounters {
|
||||
}
|
||||
|
||||
struct BlockEpollHandler {
|
||||
queue: Queue,
|
||||
queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
disk_image: Box<dyn AsyncIo>,
|
||||
disk_nsectors: u64,
|
||||
@@ -93,13 +98,13 @@ struct BlockEpollHandler {
|
||||
impl BlockEpollHandler {
|
||||
fn process_queue_submit(&mut self) -> Result<bool> {
|
||||
let queue = &mut self.queue;
|
||||
let mem = self.mem.memory();
|
||||
|
||||
let mut used_desc_heads = Vec::new();
|
||||
let mut used_count = 0;
|
||||
|
||||
for avail_desc in queue.iter(&mem) {
|
||||
let mut request = Request::parse(&avail_desc, &mem).map_err(Error::RequestParsing)?;
|
||||
let mut avail_iter = queue.iter().map_err(Error::QueueIterator)?;
|
||||
for mut desc_chain in &mut avail_iter {
|
||||
let mut request = Request::parse(&mut desc_chain).map_err(Error::RequestParsing)?;
|
||||
|
||||
if let Some(rate_limiter) = &mut self.rate_limiter {
|
||||
// If limiter.consume() fails it means there is no more TokenType::Ops
|
||||
@@ -107,7 +112,7 @@ impl BlockEpollHandler {
|
||||
if !rate_limiter.consume(1, TokenType::Ops) {
|
||||
// Stop processing the queue and return this descriptor chain to the
|
||||
// avail ring, for later processing.
|
||||
queue.go_to_previous_position();
|
||||
avail_iter.go_to_previous_position();
|
||||
break;
|
||||
}
|
||||
// Exercise the rate limiter only if this request is of data transfer type.
|
||||
@@ -126,7 +131,7 @@ impl BlockEpollHandler {
|
||||
rate_limiter.manual_replenish(1, TokenType::Ops);
|
||||
// Stop processing the queue and return this descriptor chain to the
|
||||
// avail ring, for later processing.
|
||||
queue.go_to_previous_position();
|
||||
avail_iter.go_to_previous_position();
|
||||
break;
|
||||
}
|
||||
};
|
||||
@@ -136,29 +141,34 @@ impl BlockEpollHandler {
|
||||
|
||||
if request
|
||||
.execute_async(
|
||||
&mem,
|
||||
desc_chain.memory(),
|
||||
self.disk_nsectors,
|
||||
self.disk_image.as_mut(),
|
||||
&self.disk_image_id,
|
||||
avail_desc.index as u64,
|
||||
desc_chain.head_index() as u64,
|
||||
)
|
||||
.map_err(Error::RequestExecuting)?
|
||||
{
|
||||
self.request_list.insert(avail_desc.index, request);
|
||||
self.request_list.insert(desc_chain.head_index(), request);
|
||||
} else {
|
||||
// We use unwrap because the request parsing process already
|
||||
// checked that the status_addr was valid.
|
||||
mem.write_obj(VIRTIO_BLK_S_OK, request.status_addr).unwrap();
|
||||
desc_chain
|
||||
.memory()
|
||||
.write_obj(VIRTIO_BLK_S_OK, request.status_addr)
|
||||
.unwrap();
|
||||
|
||||
// If no asynchronous operation has been submitted, we can
|
||||
// simply return the used descriptor.
|
||||
used_desc_heads.push((avail_desc.index, 0));
|
||||
used_desc_heads.push((desc_chain.head_index(), 0));
|
||||
used_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for &(desc_index, len) in used_desc_heads.iter() {
|
||||
queue.add_used(&mem, desc_index, len);
|
||||
queue
|
||||
.add_used(desc_index, len)
|
||||
.map_err(Error::QueueAddUsed)?;
|
||||
}
|
||||
|
||||
Ok(used_count > 0)
|
||||
@@ -221,7 +231,9 @@ impl BlockEpollHandler {
|
||||
}
|
||||
|
||||
for &(desc_index, len) in used_desc_heads.iter() {
|
||||
queue.add_used(&mem, desc_index, len);
|
||||
queue
|
||||
.add_used(desc_index, len)
|
||||
.map_err(Error::QueueAddUsed)?;
|
||||
}
|
||||
|
||||
self.counters
|
||||
@@ -545,7 +557,7 @@ impl VirtioDevice for Block {
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
mut queues: Vec<Queue>,
|
||||
mut queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
mut queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
@@ -557,7 +569,7 @@ impl VirtioDevice for Block {
|
||||
for i in 0..queues.len() {
|
||||
let queue_evt = queue_evts.remove(0);
|
||||
let queue = queues.remove(0);
|
||||
let queue_size = queue.size;
|
||||
let queue_size = queue.state.size;
|
||||
let (kill_evt, pause_evt) = self.common.dup_eventfds();
|
||||
|
||||
let rate_limiter: Option<RateLimiter> = self
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
use super::Error as DeviceError;
|
||||
use super::{
|
||||
ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue, VirtioCommon,
|
||||
VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST,
|
||||
VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1,
|
||||
ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, VirtioCommon, VirtioDevice,
|
||||
VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IOMMU_PLATFORM,
|
||||
VIRTIO_F_VERSION_1,
|
||||
};
|
||||
use crate::seccomp_filters::Thread;
|
||||
use crate::thread_helper::spawn_virtio_thread;
|
||||
@@ -24,7 +24,8 @@ use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use vm_memory::{ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic};
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::{ByteValued, Bytes, GuestMemoryAtomic};
|
||||
use vm_migration::VersionMapped;
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@@ -72,8 +73,7 @@ impl Default for VirtioConsoleConfig {
|
||||
unsafe impl ByteValued for VirtioConsoleConfig {}
|
||||
|
||||
struct ConsoleEpollHandler {
|
||||
queues: Vec<Queue>,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
in_buffer: Arc<Mutex<VecDeque<u8>>>,
|
||||
resizer: Arc<ConsoleResizer>,
|
||||
@@ -140,17 +140,21 @@ impl ConsoleEpollHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mem = self.mem.memory();
|
||||
for avail_desc in recv_queue.iter(&mem) {
|
||||
let len = cmp::min(avail_desc.len as u32, in_buffer.len() as u32);
|
||||
let mut avail_iter = recv_queue.iter().unwrap();
|
||||
for mut desc_chain in &mut avail_iter {
|
||||
let desc = desc_chain.next().unwrap();
|
||||
let len = cmp::min(desc.len() as u32, in_buffer.len() as u32);
|
||||
let source_slice = in_buffer.drain(..len as usize).collect::<Vec<u8>>();
|
||||
if let Err(e) = mem.write_slice(&source_slice[..], avail_desc.addr) {
|
||||
if let Err(e) = desc_chain
|
||||
.memory()
|
||||
.write_slice(&source_slice[..], desc.addr())
|
||||
{
|
||||
error!("Failed to write slice: {:?}", e);
|
||||
recv_queue.go_to_previous_position();
|
||||
avail_iter.go_to_previous_position();
|
||||
break;
|
||||
}
|
||||
|
||||
used_desc_heads[used_count] = (avail_desc.index, len);
|
||||
used_desc_heads[used_count] = (desc_chain.head_index(), len);
|
||||
used_count += 1;
|
||||
|
||||
if in_buffer.is_empty() {
|
||||
@@ -159,7 +163,7 @@ impl ConsoleEpollHandler {
|
||||
}
|
||||
|
||||
for &(desc_index, len) in &used_desc_heads[..used_count] {
|
||||
recv_queue.add_used(&mem, desc_index, len);
|
||||
recv_queue.add_used(desc_index, len).unwrap();
|
||||
}
|
||||
|
||||
used_count > 0
|
||||
@@ -177,20 +181,20 @@ impl ConsoleEpollHandler {
|
||||
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
|
||||
let mut used_count = 0;
|
||||
|
||||
let mem = self.mem.memory();
|
||||
for avail_desc in trans_queue.iter(&mem) {
|
||||
let len;
|
||||
for mut desc_chain in trans_queue.iter().unwrap() {
|
||||
let desc = desc_chain.next().unwrap();
|
||||
if let Some(ref mut out) = self.endpoint.out_file() {
|
||||
let _ = mem.write_to(avail_desc.addr, out, avail_desc.len as usize);
|
||||
let _ = desc_chain
|
||||
.memory()
|
||||
.write_to(desc.addr(), out, desc.len() as usize);
|
||||
let _ = out.flush();
|
||||
}
|
||||
len = avail_desc.len;
|
||||
used_desc_heads[used_count] = (avail_desc.index, len);
|
||||
used_desc_heads[used_count] = (desc_chain.head_index(), desc.len());
|
||||
used_count += 1;
|
||||
}
|
||||
|
||||
for &(desc_index, len) in &used_desc_heads[..used_count] {
|
||||
trans_queue.add_used(&mem, desc_index, len);
|
||||
trans_queue.add_used(desc_index, len).unwrap();
|
||||
}
|
||||
used_count > 0
|
||||
}
|
||||
@@ -477,9 +481,9 @@ impl VirtioDevice for Console {
|
||||
|
||||
fn activate(
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
_mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
mut queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
@@ -498,7 +502,6 @@ impl VirtioDevice for Console {
|
||||
|
||||
let mut handler = ConsoleEpollHandler {
|
||||
queues,
|
||||
mem,
|
||||
interrupt_cb,
|
||||
in_buffer: self.in_buffer.clone(),
|
||||
endpoint: self.endpoint.clone(),
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use crate::{ActivateError, ActivateResult, Error, Queue};
|
||||
use crate::{ActivateError, ActivateResult, Error};
|
||||
use crate::{GuestMemoryMmap, GuestRegionMmap};
|
||||
use libc::EFD_NONBLOCK;
|
||||
use std::collections::HashMap;
|
||||
@@ -17,6 +17,7 @@ use std::sync::{
|
||||
Arc, Barrier,
|
||||
};
|
||||
use std::thread;
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::{GuestAddress, GuestMemoryAtomic, GuestUsize};
|
||||
use vm_migration::{MigratableError, Pausable};
|
||||
use vm_virtio::VirtioDeviceType;
|
||||
@@ -31,9 +32,13 @@ pub trait VirtioInterrupt: Send + Sync {
|
||||
fn trigger(
|
||||
&self,
|
||||
int_type: &VirtioInterruptType,
|
||||
queue: Option<&Queue>,
|
||||
queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
) -> std::result::Result<(), std::io::Error>;
|
||||
fn notifier(&self, _int_type: &VirtioInterruptType, _queue: Option<&Queue>) -> Option<EventFd> {
|
||||
fn notifier(
|
||||
&self,
|
||||
_int_type: &VirtioInterruptType,
|
||||
_queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
) -> Option<EventFd> {
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -107,7 +112,7 @@ pub trait VirtioDevice: Send {
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_evt: Arc<dyn VirtioInterrupt>,
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult;
|
||||
|
||||
@@ -247,7 +252,7 @@ impl VirtioCommon {
|
||||
|
||||
pub fn activate(
|
||||
&mut self,
|
||||
queues: &[Queue],
|
||||
queues: &[Queue<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
queue_evts: &[EventFd],
|
||||
interrupt_cb: &Arc<dyn VirtioInterrupt>,
|
||||
) -> ActivateResult {
|
||||
|
||||
@@ -26,6 +26,7 @@ pub enum EpollHelperError {
|
||||
Ctl(std::io::Error),
|
||||
IoError(std::io::Error),
|
||||
Wait(std::io::Error),
|
||||
QueueRingIndex(virtio_queue::Error),
|
||||
}
|
||||
|
||||
pub const EPOLL_HELPER_EVENT_PAUSE: u16 = 0;
|
||||
|
||||
+68
-38
@@ -4,8 +4,8 @@
|
||||
|
||||
use super::Error as DeviceError;
|
||||
use super::{
|
||||
ActivateResult, DescriptorChain, EpollHelper, EpollHelperError, EpollHelperHandler, Queue,
|
||||
VirtioCommon, VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1,
|
||||
ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, VirtioCommon, VirtioDevice,
|
||||
VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1,
|
||||
};
|
||||
use crate::seccomp_filters::Thread;
|
||||
use crate::thread_helper::spawn_virtio_thread;
|
||||
@@ -23,11 +23,9 @@ use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Barrier, RwLock};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_queue::{AccessPlatform, DescriptorChain, Queue};
|
||||
use vm_device::dma_mapping::ExternalDmaMapping;
|
||||
use vm_memory::{
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic,
|
||||
GuestMemoryError,
|
||||
};
|
||||
use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryError};
|
||||
use vm_migration::VersionMapped;
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@@ -352,27 +350,36 @@ impl Request {
|
||||
// is created based on the information provided from the guest driver for
|
||||
// virtio-iommu (giving the link device_id <=> domain).
|
||||
fn parse(
|
||||
avail_desc: &DescriptorChain,
|
||||
mem: &GuestMemoryMmap,
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
mapping: &Arc<IommuMapping>,
|
||||
ext_mapping: &BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
||||
ext_domain_mapping: &mut BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
||||
msi_iova_space: (u64, u64),
|
||||
) -> result::Result<usize, Error> {
|
||||
// The head contains the request type which MUST be readable.
|
||||
if avail_desc.is_write_only() {
|
||||
let desc = desc_chain
|
||||
.next()
|
||||
.ok_or(Error::DescriptorChainTooShort)
|
||||
.map_err(|e| {
|
||||
error!("Missing head descriptor");
|
||||
e
|
||||
})?;
|
||||
|
||||
// The descriptor contains the request type which MUST be readable.
|
||||
if desc.is_write_only() {
|
||||
return Err(Error::UnexpectedWriteOnlyDescriptor);
|
||||
}
|
||||
|
||||
if (avail_desc.len as usize) < size_of::<VirtioIommuReqHead>() {
|
||||
if (desc.len() as usize) < size_of::<VirtioIommuReqHead>() {
|
||||
return Err(Error::InvalidRequest);
|
||||
}
|
||||
|
||||
let req_head: VirtioIommuReqHead =
|
||||
mem.read_obj(avail_desc.addr).map_err(Error::GuestMemory)?;
|
||||
let req_head: VirtioIommuReqHead = desc_chain
|
||||
.memory()
|
||||
.read_obj(desc.addr())
|
||||
.map_err(Error::GuestMemory)?;
|
||||
let req_offset = size_of::<VirtioIommuReqHead>();
|
||||
let desc_size_left = (avail_desc.len as usize) - req_offset;
|
||||
let req_addr = if let Some(addr) = avail_desc.addr.checked_add(req_offset as u64) {
|
||||
let desc_size_left = (desc.len() as usize) - req_offset;
|
||||
let req_addr = if let Some(addr) = desc.addr().checked_add(req_offset as u64) {
|
||||
addr
|
||||
} else {
|
||||
return Err(Error::InvalidRequest);
|
||||
@@ -389,7 +396,8 @@ impl Request {
|
||||
return Err(Error::InvalidAttachRequest);
|
||||
}
|
||||
|
||||
let req: VirtioIommuReqAttach = mem
|
||||
let req: VirtioIommuReqAttach = desc_chain
|
||||
.memory()
|
||||
.read_obj(req_addr as GuestAddress)
|
||||
.map_err(Error::GuestMemory)?;
|
||||
debug!("Attach request {:?}", req);
|
||||
@@ -419,7 +427,8 @@ impl Request {
|
||||
return Err(Error::InvalidDetachRequest);
|
||||
}
|
||||
|
||||
let req: VirtioIommuReqDetach = mem
|
||||
let req: VirtioIommuReqDetach = desc_chain
|
||||
.memory()
|
||||
.read_obj(req_addr as GuestAddress)
|
||||
.map_err(Error::GuestMemory)?;
|
||||
debug!("Detach request {:?}", req);
|
||||
@@ -445,7 +454,8 @@ impl Request {
|
||||
return Err(Error::InvalidMapRequest);
|
||||
}
|
||||
|
||||
let req: VirtioIommuReqMap = mem
|
||||
let req: VirtioIommuReqMap = desc_chain
|
||||
.memory()
|
||||
.read_obj(req_addr as GuestAddress)
|
||||
.map_err(Error::GuestMemory)?;
|
||||
debug!("Map request {:?}", req);
|
||||
@@ -481,7 +491,8 @@ impl Request {
|
||||
return Err(Error::InvalidUnmapRequest);
|
||||
}
|
||||
|
||||
let req: VirtioIommuReqUnmap = mem
|
||||
let req: VirtioIommuReqUnmap = desc_chain
|
||||
.memory()
|
||||
.read_obj(req_addr as GuestAddress)
|
||||
.map_err(Error::GuestMemory)?;
|
||||
debug!("Unmap request {:?}", req);
|
||||
@@ -510,7 +521,8 @@ impl Request {
|
||||
return Err(Error::InvalidProbeRequest);
|
||||
}
|
||||
|
||||
let req: VirtioIommuReqProbe = mem
|
||||
let req: VirtioIommuReqProbe = desc_chain
|
||||
.memory()
|
||||
.read_obj(req_addr as GuestAddress)
|
||||
.map_err(Error::GuestMemory)?;
|
||||
debug!("Probe request {:?}", req);
|
||||
@@ -534,16 +546,14 @@ impl Request {
|
||||
_ => return Err(Error::InvalidRequest),
|
||||
};
|
||||
|
||||
let status_desc = avail_desc
|
||||
.next_descriptor()
|
||||
.ok_or(Error::DescriptorChainTooShort)?;
|
||||
let status_desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
|
||||
|
||||
// The status MUST always be writable
|
||||
if !status_desc.is_write_only() {
|
||||
return Err(Error::UnexpectedReadOnlyDescriptor);
|
||||
}
|
||||
|
||||
if status_desc.len < hdr_len + size_of::<VirtioIommuReqTail>() as u32 {
|
||||
if status_desc.len() < hdr_len + size_of::<VirtioIommuReqTail>() as u32 {
|
||||
return Err(Error::BufferLengthTooSmall);
|
||||
}
|
||||
|
||||
@@ -553,7 +563,9 @@ impl Request {
|
||||
};
|
||||
reply.extend_from_slice(tail.as_slice());
|
||||
|
||||
mem.write_slice(reply.as_slice(), status_desc.addr)
|
||||
desc_chain
|
||||
.memory()
|
||||
.write_slice(reply.as_slice(), status_desc.addr())
|
||||
.map_err(Error::GuestMemory)?;
|
||||
|
||||
Ok((hdr_len as usize) + size_of::<VirtioIommuReqTail>())
|
||||
@@ -561,8 +573,7 @@ impl Request {
|
||||
}
|
||||
|
||||
struct IommuEpollHandler {
|
||||
queues: Vec<Queue>,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
kill_evt: EventFd,
|
||||
@@ -577,11 +588,9 @@ impl IommuEpollHandler {
|
||||
fn request_queue(&mut self) -> bool {
|
||||
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
|
||||
let mut used_count = 0;
|
||||
let mem = self.mem.memory();
|
||||
for avail_desc in self.queues[0].iter(&mem) {
|
||||
for mut desc_chain in self.queues[0].iter().unwrap() {
|
||||
let len = match Request::parse(
|
||||
&avail_desc,
|
||||
&mem,
|
||||
&mut desc_chain,
|
||||
&self.mapping,
|
||||
&self.ext_mapping,
|
||||
&mut self.ext_domain_mapping,
|
||||
@@ -594,12 +603,12 @@ impl IommuEpollHandler {
|
||||
}
|
||||
};
|
||||
|
||||
used_desc_heads[used_count] = (avail_desc.index, len);
|
||||
used_desc_heads[used_count] = (desc_chain.head_index(), len);
|
||||
used_count += 1;
|
||||
}
|
||||
|
||||
for &(desc_index, len) in &used_desc_heads[..used_count] {
|
||||
self.queues[0].add_used(&mem, desc_index, len);
|
||||
self.queues[0].add_used(desc_index, len).unwrap();
|
||||
}
|
||||
used_count > 0
|
||||
}
|
||||
@@ -608,7 +617,10 @@ impl IommuEpollHandler {
|
||||
false
|
||||
}
|
||||
|
||||
fn signal_used_queue(&self, queue: &Queue) -> result::Result<(), DeviceError> {
|
||||
fn signal_used_queue(
|
||||
&self,
|
||||
queue: &Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
) -> result::Result<(), DeviceError> {
|
||||
self.interrupt_cb
|
||||
.trigger(&VirtioInterruptType::Queue, Some(queue))
|
||||
.map_err(|e| {
|
||||
@@ -666,12 +678,13 @@ impl EpollHelperHandler for IommuEpollHandler {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Versionize)]
|
||||
#[derive(Clone, Copy, Debug, Versionize)]
|
||||
struct Mapping {
|
||||
gpa: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IommuMapping {
|
||||
// Domain related to an endpoint.
|
||||
endpoints: Arc<RwLock<BTreeMap<u32, u32>>>,
|
||||
@@ -704,6 +717,24 @@ impl DmaRemapping for IommuMapping {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AccessPlatformMapping {
|
||||
id: u32,
|
||||
mapping: Arc<IommuMapping>,
|
||||
}
|
||||
|
||||
impl AccessPlatformMapping {
|
||||
pub fn new(id: u32, mapping: Arc<IommuMapping>) -> Self {
|
||||
AccessPlatformMapping { id, mapping }
|
||||
}
|
||||
}
|
||||
|
||||
impl AccessPlatform for AccessPlatformMapping {
|
||||
fn translate(&self, base: u64, _size: u64) -> std::result::Result<u64, std::io::Error> {
|
||||
self.mapping.translate(self.id, base)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iommu {
|
||||
common: VirtioCommon,
|
||||
id: String,
|
||||
@@ -839,16 +870,15 @@ impl VirtioDevice for Iommu {
|
||||
|
||||
fn activate(
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
_mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
let (kill_evt, pause_evt) = self.common.dup_eventfds();
|
||||
let mut handler = IommuEpollHandler {
|
||||
queues,
|
||||
mem,
|
||||
interrupt_cb,
|
||||
queue_evts,
|
||||
kill_evt,
|
||||
|
||||
@@ -51,7 +51,7 @@ pub use self::rng::*;
|
||||
pub use self::vsock::*;
|
||||
pub use self::watchdog::*;
|
||||
use vm_memory::{bitmap::AtomicBitmap, GuestAddress, GuestMemory};
|
||||
use vm_virtio::{queue::*, VirtioDeviceType};
|
||||
use vm_virtio::VirtioDeviceType;
|
||||
|
||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
||||
type GuestRegionMmap = vm_memory::GuestRegionMmap<AtomicBitmap>;
|
||||
@@ -115,6 +115,8 @@ pub enum Error {
|
||||
SetShmRegionsNotSupported,
|
||||
NetQueuePair(::net_util::NetQueuePairError),
|
||||
ApplySeccompFilter(seccompiler::Error),
|
||||
QueueAddUsed(virtio_queue::Error),
|
||||
QueueIterator(virtio_queue::Error),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq)]
|
||||
|
||||
+33
-31
@@ -14,9 +14,8 @@
|
||||
|
||||
use super::Error as DeviceError;
|
||||
use super::{
|
||||
ActivateError, ActivateResult, DescriptorChain, EpollHelper, EpollHelperError,
|
||||
EpollHelperHandler, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType,
|
||||
EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1,
|
||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, VirtioCommon,
|
||||
VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1,
|
||||
};
|
||||
use crate::seccomp_filters::Thread;
|
||||
use crate::thread_helper::spawn_virtio_thread;
|
||||
@@ -35,10 +34,11 @@ use std::sync::mpsc;
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_queue::{DescriptorChain, Queue};
|
||||
use vm_device::dma_mapping::ExternalDmaMapping;
|
||||
use vm_memory::{
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic,
|
||||
GuestMemoryError, GuestMemoryRegion,
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryError,
|
||||
GuestMemoryRegion,
|
||||
};
|
||||
use vm_migration::protocol::MemoryRangeTable;
|
||||
use vm_migration::{
|
||||
@@ -277,34 +277,35 @@ struct Request {
|
||||
|
||||
impl Request {
|
||||
fn parse(
|
||||
avail_desc: &DescriptorChain,
|
||||
mem: &GuestMemoryMmap,
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
) -> result::Result<Request, Error> {
|
||||
// The head contains the request type which MUST be readable.
|
||||
if avail_desc.is_write_only() {
|
||||
let desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
|
||||
// The descriptor contains the request type which MUST be readable.
|
||||
if desc.is_write_only() {
|
||||
return Err(Error::UnexpectedWriteOnlyDescriptor);
|
||||
}
|
||||
if avail_desc.len as usize != size_of::<VirtioMemReq>() {
|
||||
if desc.len() as usize != size_of::<VirtioMemReq>() {
|
||||
return Err(Error::InvalidRequest);
|
||||
}
|
||||
let req: VirtioMemReq = mem.read_obj(avail_desc.addr).map_err(Error::GuestMemory)?;
|
||||
let req: VirtioMemReq = desc_chain
|
||||
.memory()
|
||||
.read_obj(desc.addr())
|
||||
.map_err(Error::GuestMemory)?;
|
||||
|
||||
let status_desc = avail_desc
|
||||
.next_descriptor()
|
||||
.ok_or(Error::DescriptorChainTooShort)?;
|
||||
let status_desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
|
||||
|
||||
// The status MUST always be writable
|
||||
if !status_desc.is_write_only() {
|
||||
return Err(Error::UnexpectedReadOnlyDescriptor);
|
||||
}
|
||||
|
||||
if (status_desc.len as usize) < size_of::<VirtioMemResp>() {
|
||||
if (status_desc.len() as usize) < size_of::<VirtioMemResp>() {
|
||||
return Err(Error::BufferLengthTooSmall);
|
||||
}
|
||||
|
||||
Ok(Request {
|
||||
req,
|
||||
status_addr: status_desc.addr,
|
||||
status_addr: status_desc.addr(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -455,8 +456,7 @@ struct MemEpollHandler {
|
||||
blocks_state: Arc<Mutex<BlocksState>>,
|
||||
config: Arc<Mutex<VirtioMemConfig>>,
|
||||
resize: ResizeSender,
|
||||
queue: Queue,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queue_evt: EventFd,
|
||||
kill_evt: EventFd,
|
||||
@@ -656,12 +656,16 @@ impl MemEpollHandler {
|
||||
fn process_queue(&mut self) -> bool {
|
||||
let mut request_list = Vec::new();
|
||||
let mut used_count = 0;
|
||||
let mem = self.mem.memory();
|
||||
for avail_desc in self.queue.iter(&mem) {
|
||||
request_list.push((avail_desc.index, Request::parse(&avail_desc, &mem)));
|
||||
|
||||
for mut desc_chain in self.queue.iter().unwrap() {
|
||||
request_list.push((
|
||||
desc_chain.head_index(),
|
||||
Request::parse(&mut desc_chain),
|
||||
desc_chain.memory().clone(),
|
||||
));
|
||||
}
|
||||
|
||||
for (desc_index, request) in request_list.iter() {
|
||||
for (head_index, request, memory) in request_list {
|
||||
let len = match request {
|
||||
Err(e) => {
|
||||
error!("failed parse VirtioMemReq: {:?}", e);
|
||||
@@ -671,21 +675,21 @@ impl MemEpollHandler {
|
||||
VIRTIO_MEM_REQ_PLUG => {
|
||||
let resp_type =
|
||||
self.state_change_request(r.req.addr, r.req.nb_blocks, true);
|
||||
r.send_response(&mem, resp_type, 0u16)
|
||||
r.send_response(&memory, resp_type, 0u16)
|
||||
}
|
||||
VIRTIO_MEM_REQ_UNPLUG => {
|
||||
let resp_type =
|
||||
self.state_change_request(r.req.addr, r.req.nb_blocks, false);
|
||||
r.send_response(&mem, resp_type, 0u16)
|
||||
r.send_response(&memory, resp_type, 0u16)
|
||||
}
|
||||
VIRTIO_MEM_REQ_UNPLUG_ALL => {
|
||||
let resp_type = self.unplug_all();
|
||||
r.send_response(&mem, resp_type, 0u16)
|
||||
r.send_response(&memory, resp_type, 0u16)
|
||||
}
|
||||
VIRTIO_MEM_REQ_STATE => {
|
||||
let (resp_type, resp_state) =
|
||||
self.state_request(r.req.addr, r.req.nb_blocks);
|
||||
r.send_response(&mem, resp_type, resp_state)
|
||||
r.send_response(&memory, resp_type, resp_state)
|
||||
}
|
||||
_ => {
|
||||
error!("VirtioMemReq unknown request type {:?}", r.req.req_type);
|
||||
@@ -694,8 +698,7 @@ impl MemEpollHandler {
|
||||
},
|
||||
};
|
||||
|
||||
self.queue.add_used(&mem, *desc_index, len);
|
||||
|
||||
self.queue.add_used(head_index, len).unwrap();
|
||||
used_count += 1;
|
||||
}
|
||||
|
||||
@@ -990,9 +993,9 @@ impl VirtioDevice for Mem {
|
||||
|
||||
fn activate(
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
_mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
mut queues: Vec<Queue>,
|
||||
mut queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
mut queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
@@ -1004,7 +1007,6 @@ impl VirtioDevice for Mem {
|
||||
config: self.config.clone(),
|
||||
resize: self.resize.clone(),
|
||||
queue: queues.remove(0),
|
||||
mem,
|
||||
interrupt_cb,
|
||||
queue_evt: queue_evts.remove(0),
|
||||
kill_evt,
|
||||
|
||||
+17
-14
@@ -7,7 +7,7 @@
|
||||
|
||||
use super::Error as DeviceError;
|
||||
use super::{
|
||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue,
|
||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler,
|
||||
RateLimiterConfig, VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType,
|
||||
EPOLL_HELPER_EVENT_LAST,
|
||||
};
|
||||
@@ -35,7 +35,8 @@ use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_bindings::bindings::virtio_net::*;
|
||||
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
|
||||
use vm_memory::{ByteValued, GuestAddressSpace, GuestMemoryAtomic};
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::{ByteValued, GuestMemoryAtomic};
|
||||
use vm_migration::VersionMapped;
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@@ -45,12 +46,11 @@ use vmm_sys_util::eventfd::EventFd;
|
||||
const CTRL_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1;
|
||||
|
||||
pub struct NetCtrlEpollHandler {
|
||||
pub mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
pub kill_evt: EventFd,
|
||||
pub pause_evt: EventFd,
|
||||
pub ctrl_q: CtrlQueue,
|
||||
pub queue_evt: EventFd,
|
||||
pub queue: Queue,
|
||||
pub queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
}
|
||||
|
||||
impl NetCtrlEpollHandler {
|
||||
@@ -72,12 +72,11 @@ impl EpollHelperHandler for NetCtrlEpollHandler {
|
||||
let ev_type = event.data as u16;
|
||||
match ev_type {
|
||||
CTRL_QUEUE_EVENT => {
|
||||
let mem = self.mem.memory();
|
||||
if let Err(e) = self.queue_evt.read() {
|
||||
error!("failed to get ctl queue event: {:?}", e);
|
||||
return true;
|
||||
}
|
||||
if let Err(e) = self.ctrl_q.process(&mem, &mut self.queue) {
|
||||
if let Err(e) = self.ctrl_q.process(&mut self.queue) {
|
||||
error!("failed to process ctrl queue: {:?}", e);
|
||||
return true;
|
||||
}
|
||||
@@ -125,7 +124,7 @@ struct NetEpollHandler {
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
kill_evt: EventFd,
|
||||
pause_evt: EventFd,
|
||||
queue_pair: Vec<Queue>,
|
||||
queue_pair: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
queue_evt_pair: Vec<EventFd>,
|
||||
// Always generate interrupts until the driver has signalled to the device.
|
||||
// This mitigates a problem with interrupts from tap events being "lost" upon
|
||||
@@ -135,7 +134,10 @@ struct NetEpollHandler {
|
||||
}
|
||||
|
||||
impl NetEpollHandler {
|
||||
fn signal_used_queue(&self, queue: &Queue) -> result::Result<(), DeviceError> {
|
||||
fn signal_used_queue(
|
||||
&self,
|
||||
queue: &Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
) -> result::Result<(), DeviceError> {
|
||||
self.interrupt_cb
|
||||
.trigger(&VirtioInterruptType::Queue, Some(queue))
|
||||
.map_err(|e| {
|
||||
@@ -235,8 +237,11 @@ impl NetEpollHandler {
|
||||
// If there are some already available descriptors on the RX queue,
|
||||
// then we can start the thread while listening onto the TAP.
|
||||
if self.queue_pair[0]
|
||||
.available_descriptors(&self.net.mem.as_ref().unwrap().memory())
|
||||
.unwrap()
|
||||
.used_idx(Ordering::Acquire)
|
||||
.map_err(EpollHelperError::QueueRingIndex)?
|
||||
< self.queue_pair[0]
|
||||
.avail_idx(Ordering::Acquire)
|
||||
.map_err(EpollHelperError::QueueRingIndex)?
|
||||
{
|
||||
helper.add_event(self.net.tap.as_raw_fd(), RX_TAP_EVENT)?;
|
||||
self.net.rx_tap_listening = true;
|
||||
@@ -549,9 +554,9 @@ impl VirtioDevice for Net {
|
||||
|
||||
fn activate(
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
_mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
mut queues: Vec<Queue>,
|
||||
mut queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
mut queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
@@ -563,7 +568,6 @@ impl VirtioDevice for Net {
|
||||
|
||||
let (kill_evt, pause_evt) = self.common.dup_eventfds();
|
||||
let mut ctrl_handler = NetCtrlEpollHandler {
|
||||
mem: mem.clone(),
|
||||
kill_evt,
|
||||
pause_evt,
|
||||
ctrl_q: CtrlQueue::new(self.taps.clone()),
|
||||
@@ -632,7 +636,6 @@ impl VirtioDevice for Net {
|
||||
|
||||
let mut handler = NetEpollHandler {
|
||||
net: NetQueuePair {
|
||||
mem: Some(mem.clone()),
|
||||
tap_for_write_epoll: tap.clone(),
|
||||
tap,
|
||||
rx,
|
||||
|
||||
+25
-29
@@ -8,9 +8,9 @@
|
||||
|
||||
use super::Error as DeviceError;
|
||||
use super::{
|
||||
ActivateError, ActivateResult, DescriptorChain, EpollHelper, EpollHelperError,
|
||||
EpollHelperHandler, Queue, UserspaceMapping, VirtioCommon, VirtioDevice, VirtioDeviceType,
|
||||
EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1,
|
||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler,
|
||||
UserspaceMapping, VirtioCommon, VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST,
|
||||
VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1,
|
||||
};
|
||||
use crate::seccomp_filters::Thread;
|
||||
use crate::thread_helper::spawn_virtio_thread;
|
||||
@@ -27,10 +27,8 @@ use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Barrier};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use vm_memory::{
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic,
|
||||
GuestMemoryError,
|
||||
};
|
||||
use virtio_queue::{DescriptorChain, Queue};
|
||||
use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryError};
|
||||
use vm_migration::VersionMapped;
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@@ -116,48 +114,48 @@ struct Request {
|
||||
|
||||
impl Request {
|
||||
fn parse(
|
||||
avail_desc: &DescriptorChain,
|
||||
mem: &GuestMemoryMmap,
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
) -> result::Result<Request, Error> {
|
||||
// The head contains the request type which MUST be readable.
|
||||
if avail_desc.is_write_only() {
|
||||
let desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
|
||||
// The descriptor contains the request type which MUST be readable.
|
||||
if desc.is_write_only() {
|
||||
return Err(Error::UnexpectedWriteOnlyDescriptor);
|
||||
}
|
||||
|
||||
if avail_desc.len as usize != size_of::<VirtioPmemReq>() {
|
||||
if desc.len() as usize != size_of::<VirtioPmemReq>() {
|
||||
return Err(Error::InvalidRequest);
|
||||
}
|
||||
|
||||
let request: VirtioPmemReq = mem.read_obj(avail_desc.addr).map_err(Error::GuestMemory)?;
|
||||
let request: VirtioPmemReq = desc_chain
|
||||
.memory()
|
||||
.read_obj(desc.addr())
|
||||
.map_err(Error::GuestMemory)?;
|
||||
|
||||
let request_type = match request.type_ {
|
||||
VIRTIO_PMEM_REQ_TYPE_FLUSH => RequestType::Flush,
|
||||
_ => return Err(Error::InvalidRequest),
|
||||
};
|
||||
|
||||
let status_desc = avail_desc
|
||||
.next_descriptor()
|
||||
.ok_or(Error::DescriptorChainTooShort)?;
|
||||
let status_desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
|
||||
|
||||
// The status MUST always be writable
|
||||
if !status_desc.is_write_only() {
|
||||
return Err(Error::UnexpectedReadOnlyDescriptor);
|
||||
}
|
||||
|
||||
if (status_desc.len as usize) < size_of::<VirtioPmemResp>() {
|
||||
if (status_desc.len() as usize) < size_of::<VirtioPmemResp>() {
|
||||
return Err(Error::BufferLengthTooSmall);
|
||||
}
|
||||
|
||||
Ok(Request {
|
||||
type_: request_type,
|
||||
status_addr: status_desc.addr,
|
||||
status_addr: status_desc.addr(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct PmemEpollHandler {
|
||||
queue: Queue,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
disk: File,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queue_evt: EventFd,
|
||||
@@ -169,9 +167,8 @@ impl PmemEpollHandler {
|
||||
fn process_queue(&mut self) -> bool {
|
||||
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
|
||||
let mut used_count = 0;
|
||||
let mem = self.mem.memory();
|
||||
for avail_desc in self.queue.iter(&mem) {
|
||||
let len = match Request::parse(&avail_desc, &mem) {
|
||||
for mut desc_chain in self.queue.iter().unwrap() {
|
||||
let len = match Request::parse(&mut desc_chain) {
|
||||
Ok(ref req) if (req.type_ == RequestType::Flush) => {
|
||||
let status_code = match self.disk.sync_all() {
|
||||
Ok(()) => VIRTIO_PMEM_RESP_TYPE_OK,
|
||||
@@ -182,7 +179,7 @@ impl PmemEpollHandler {
|
||||
};
|
||||
|
||||
let resp = VirtioPmemResp { ret: status_code };
|
||||
match mem.write_obj(resp, req.status_addr) {
|
||||
match desc_chain.memory().write_obj(resp, req.status_addr) {
|
||||
Ok(_) => size_of::<VirtioPmemResp>() as u32,
|
||||
Err(e) => {
|
||||
error!("bad guest memory address: {}", e);
|
||||
@@ -201,12 +198,12 @@ impl PmemEpollHandler {
|
||||
}
|
||||
};
|
||||
|
||||
used_desc_heads[used_count] = (avail_desc.index, len);
|
||||
used_desc_heads[used_count] = (desc_chain.head_index(), len);
|
||||
used_count += 1;
|
||||
}
|
||||
|
||||
for &(desc_index, len) in &used_desc_heads[..used_count] {
|
||||
self.queue.add_used(&mem, desc_index, len);
|
||||
self.queue.add_used(desc_index, len).unwrap();
|
||||
}
|
||||
used_count > 0
|
||||
}
|
||||
@@ -369,9 +366,9 @@ impl VirtioDevice for Pmem {
|
||||
|
||||
fn activate(
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
_mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
mut queues: Vec<Queue>,
|
||||
mut queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
mut queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
@@ -383,7 +380,6 @@ impl VirtioDevice for Pmem {
|
||||
})?;
|
||||
let mut handler = PmemEpollHandler {
|
||||
queue: queues.remove(0),
|
||||
mem,
|
||||
disk,
|
||||
interrupt_cb,
|
||||
queue_evt: queue_evts.remove(0),
|
||||
|
||||
+16
-20
@@ -4,8 +4,8 @@
|
||||
|
||||
use super::Error as DeviceError;
|
||||
use super::{
|
||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue,
|
||||
VirtioCommon, VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IOMMU_PLATFORM,
|
||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, VirtioCommon,
|
||||
VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IOMMU_PLATFORM,
|
||||
VIRTIO_F_VERSION_1,
|
||||
};
|
||||
use crate::seccomp_filters::Thread;
|
||||
@@ -21,7 +21,8 @@ use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Barrier};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use vm_memory::{Bytes, GuestAddressSpace, GuestMemoryAtomic};
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::{Bytes, GuestMemoryAtomic};
|
||||
use vm_migration::VersionMapped;
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@@ -33,8 +34,7 @@ const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];
|
||||
const QUEUE_AVAIL_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1;
|
||||
|
||||
struct RngEpollHandler {
|
||||
queues: Vec<Queue>,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
random_file: File,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queue_evt: EventFd,
|
||||
@@ -48,31 +48,28 @@ impl RngEpollHandler {
|
||||
|
||||
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
|
||||
let mut used_count = 0;
|
||||
let mem = self.mem.memory();
|
||||
for avail_desc in queue.iter(&mem) {
|
||||
for mut desc_chain in queue.iter().unwrap() {
|
||||
let desc = desc_chain.next().unwrap();
|
||||
let mut len = 0;
|
||||
|
||||
// Drivers can only read from the random device.
|
||||
if avail_desc.is_write_only() {
|
||||
if desc.is_write_only() {
|
||||
// Fill the read with data from the random device on the host.
|
||||
if mem
|
||||
.read_from(
|
||||
avail_desc.addr,
|
||||
&mut self.random_file,
|
||||
avail_desc.len as usize,
|
||||
)
|
||||
if desc_chain
|
||||
.memory()
|
||||
.read_from(desc.addr(), &mut self.random_file, desc.len() as usize)
|
||||
.is_ok()
|
||||
{
|
||||
len = avail_desc.len;
|
||||
len = desc.len();
|
||||
}
|
||||
}
|
||||
|
||||
used_desc_heads[used_count] = (avail_desc.index, len);
|
||||
used_desc_heads[used_count] = (desc_chain.head_index(), len);
|
||||
used_count += 1;
|
||||
}
|
||||
|
||||
for &(desc_index, len) in &used_desc_heads[..used_count] {
|
||||
queue.add_used(&mem, desc_index, len);
|
||||
queue.add_used(desc_index, len).unwrap();
|
||||
}
|
||||
used_count > 0
|
||||
}
|
||||
@@ -213,9 +210,9 @@ impl VirtioDevice for Rng {
|
||||
|
||||
fn activate(
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
_mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
mut queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
@@ -228,7 +225,6 @@ impl VirtioDevice for Rng {
|
||||
})?;
|
||||
let mut handler = RngEpollHandler {
|
||||
queues,
|
||||
mem,
|
||||
random_file,
|
||||
interrupt_cb,
|
||||
queue_evt: queue_evts.remove(0),
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use crate::{Queue, VirtioDevice};
|
||||
use crate::{GuestMemoryMmap, VirtioDevice};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use std::sync::atomic::{AtomicU16, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use vm_memory::GuestAddress;
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::{GuestAddress, GuestMemoryAtomic};
|
||||
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
|
||||
|
||||
#[derive(Clone, Versionize)]
|
||||
@@ -83,7 +84,7 @@ impl VirtioPciCommonConfig {
|
||||
&mut self,
|
||||
offset: u64,
|
||||
data: &mut [u8],
|
||||
queues: &mut Vec<Queue>,
|
||||
queues: &mut Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
) {
|
||||
assert!(data.len() <= 8);
|
||||
@@ -113,7 +114,7 @@ impl VirtioPciCommonConfig {
|
||||
&mut self,
|
||||
offset: u64,
|
||||
data: &[u8],
|
||||
queues: &mut Vec<Queue>,
|
||||
queues: &mut Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
) {
|
||||
assert!(data.len() <= 8);
|
||||
@@ -152,16 +153,20 @@ impl VirtioPciCommonConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_common_config_word(&self, offset: u64, queues: &[Queue]) -> u16 {
|
||||
fn read_common_config_word(
|
||||
&self,
|
||||
offset: u64,
|
||||
queues: &[Queue<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
) -> u16 {
|
||||
debug!("read_common_config_word: offset 0x{:x}", offset);
|
||||
match offset {
|
||||
0x10 => self.msix_config.load(Ordering::Acquire),
|
||||
0x12 => queues.len() as u16, // num_queues
|
||||
0x16 => self.queue_select,
|
||||
0x18 => self.with_queue(queues, |q| q.size).unwrap_or(0),
|
||||
0x1a => self.with_queue(queues, |q| q.vector).unwrap_or(0),
|
||||
0x18 => self.with_queue(queues, |q| q.state.size).unwrap_or(0),
|
||||
0x1a => self.with_queue(queues, |q| q.state.vector).unwrap_or(0),
|
||||
0x1c => {
|
||||
if self.with_queue(queues, |q| q.ready).unwrap_or(false) {
|
||||
if self.with_queue(queues, |q| q.state.ready).unwrap_or(false) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
@@ -175,13 +180,18 @@ impl VirtioPciCommonConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_common_config_word(&mut self, offset: u64, value: u16, queues: &mut Vec<Queue>) {
|
||||
fn write_common_config_word(
|
||||
&mut self,
|
||||
offset: u64,
|
||||
value: u16,
|
||||
queues: &mut Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
) {
|
||||
debug!("write_common_config_word: offset 0x{:x}", offset);
|
||||
match offset {
|
||||
0x10 => self.msix_config.store(value, Ordering::Release),
|
||||
0x16 => self.queue_select = value,
|
||||
0x18 => self.with_queue_mut(queues, |q| q.size = value),
|
||||
0x1a => self.with_queue_mut(queues, |q| q.vector = value),
|
||||
0x18 => self.with_queue_mut(queues, |q| q.state.size = value),
|
||||
0x1a => self.with_queue_mut(queues, |q| q.state.vector = value),
|
||||
0x1c => self.with_queue_mut(queues, |q| q.enable(value == 1)),
|
||||
_ => {
|
||||
warn!("invalid virtio register word write: 0x{:x}", offset);
|
||||
@@ -215,7 +225,7 @@ impl VirtioPciCommonConfig {
|
||||
&mut self,
|
||||
offset: u64,
|
||||
value: u32,
|
||||
queues: &mut Vec<Queue>,
|
||||
queues: &mut Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
) {
|
||||
debug!("write_common_config_dword: offset 0x{:x}", offset);
|
||||
@@ -242,12 +252,12 @@ impl VirtioPciCommonConfig {
|
||||
);
|
||||
}
|
||||
}
|
||||
0x20 => self.with_queue_mut(queues, |q| lo(&mut q.desc_table, value)),
|
||||
0x24 => self.with_queue_mut(queues, |q| hi(&mut q.desc_table, value)),
|
||||
0x28 => self.with_queue_mut(queues, |q| lo(&mut q.avail_ring, value)),
|
||||
0x2c => self.with_queue_mut(queues, |q| hi(&mut q.avail_ring, value)),
|
||||
0x30 => self.with_queue_mut(queues, |q| lo(&mut q.used_ring, value)),
|
||||
0x34 => self.with_queue_mut(queues, |q| hi(&mut q.used_ring, value)),
|
||||
0x20 => self.with_queue_mut(queues, |q| lo(&mut q.state.desc_table, value)),
|
||||
0x24 => self.with_queue_mut(queues, |q| hi(&mut q.state.desc_table, value)),
|
||||
0x28 => self.with_queue_mut(queues, |q| lo(&mut q.state.avail_ring, value)),
|
||||
0x2c => self.with_queue_mut(queues, |q| hi(&mut q.state.avail_ring, value)),
|
||||
0x30 => self.with_queue_mut(queues, |q| lo(&mut q.state.used_ring, value)),
|
||||
0x34 => self.with_queue_mut(queues, |q| hi(&mut q.state.used_ring, value)),
|
||||
_ => {
|
||||
warn!("invalid virtio register dword write: 0x{:x}", offset);
|
||||
}
|
||||
@@ -259,26 +269,39 @@ impl VirtioPciCommonConfig {
|
||||
0 // Assume the guest has no reason to read write-only registers.
|
||||
}
|
||||
|
||||
fn write_common_config_qword(&mut self, offset: u64, value: u64, queues: &mut Vec<Queue>) {
|
||||
fn write_common_config_qword(
|
||||
&mut self,
|
||||
offset: u64,
|
||||
value: u64,
|
||||
queues: &mut Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
) {
|
||||
debug!("write_common_config_qword: offset 0x{:x}", offset);
|
||||
match offset {
|
||||
0x20 => self.with_queue_mut(queues, |q| q.desc_table = GuestAddress(value)),
|
||||
0x28 => self.with_queue_mut(queues, |q| q.avail_ring = GuestAddress(value)),
|
||||
0x30 => self.with_queue_mut(queues, |q| q.used_ring = GuestAddress(value)),
|
||||
0x20 => self.with_queue_mut(queues, |q| q.state.desc_table = GuestAddress(value)),
|
||||
0x28 => self.with_queue_mut(queues, |q| q.state.avail_ring = GuestAddress(value)),
|
||||
0x30 => self.with_queue_mut(queues, |q| q.state.used_ring = GuestAddress(value)),
|
||||
_ => {
|
||||
warn!("invalid virtio register qword write: 0x{:x}", offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn with_queue<U, F>(&self, queues: &[Queue], f: F) -> Option<U>
|
||||
fn with_queue<U, F>(
|
||||
&self,
|
||||
queues: &[Queue<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
f: F,
|
||||
) -> Option<U>
|
||||
where
|
||||
F: FnOnce(&Queue) -> U,
|
||||
F: FnOnce(&Queue<GuestMemoryAtomic<GuestMemoryMmap>>) -> U,
|
||||
{
|
||||
queues.get(self.queue_select as usize).map(f)
|
||||
}
|
||||
|
||||
fn with_queue_mut<F: FnOnce(&mut Queue)>(&self, queues: &mut Vec<Queue>, f: F) {
|
||||
fn with_queue_mut<F: FnOnce(&mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>)>(
|
||||
&self,
|
||||
queues: &mut Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
f: F,
|
||||
) {
|
||||
if let Some(queue) = queues.get_mut(self.queue_select as usize) {
|
||||
f(queue);
|
||||
}
|
||||
@@ -308,6 +331,7 @@ mod tests {
|
||||
use crate::GuestMemoryMmap;
|
||||
use crate::{ActivateResult, VirtioInterrupt};
|
||||
use std::sync::Arc;
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::GuestMemoryAtomic;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
@@ -326,7 +350,7 @@ mod tests {
|
||||
&mut self,
|
||||
_mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
_interrupt_evt: Arc<dyn VirtioInterrupt>,
|
||||
_queues: Vec<Queue>,
|
||||
_queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
_queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
Ok(())
|
||||
|
||||
@@ -10,7 +10,7 @@ use super::VirtioPciCommonConfig;
|
||||
use crate::transport::VirtioTransport;
|
||||
use crate::GuestMemoryMmap;
|
||||
use crate::{
|
||||
ActivateResult, Queue, VirtioDevice, VirtioDeviceType, VirtioInterrupt, VirtioInterruptType,
|
||||
ActivateResult, VirtioDevice, VirtioDeviceType, VirtioInterrupt, VirtioInterruptType,
|
||||
DEVICE_ACKNOWLEDGE, DEVICE_DRIVER, DEVICE_DRIVER_OK, DEVICE_FAILED, DEVICE_FEATURES_OK,
|
||||
DEVICE_INIT,
|
||||
};
|
||||
@@ -24,30 +24,28 @@ use pci::{
|
||||
use std::any::Any;
|
||||
use std::cmp;
|
||||
use std::io::Write;
|
||||
use std::num::Wrapping;
|
||||
use std::result;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU16, AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_queue::AccessPlatform;
|
||||
use virtio_queue::{defs::VIRTQ_MSI_NO_VECTOR, Error as QueueError, Queue};
|
||||
use vm_allocator::SystemAllocator;
|
||||
use vm_device::interrupt::{
|
||||
InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig,
|
||||
};
|
||||
use vm_device::BusDevice;
|
||||
use vm_memory::{
|
||||
Address, ByteValued, GuestAddress, GuestAddressSpace, GuestMemoryAtomic, GuestUsize, Le32,
|
||||
};
|
||||
use vm_memory::{Address, ByteValued, GuestAddress, GuestMemoryAtomic, GuestUsize, Le32};
|
||||
use vm_migration::{
|
||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
||||
};
|
||||
use vm_virtio::{queue, VirtioIommuRemapping, VIRTIO_MSI_NO_VECTOR};
|
||||
use vmm_sys_util::{errno::Result, eventfd::EventFd};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Error {
|
||||
/// Failed to retrieve queue ring's index.
|
||||
QueueRingIndex(queue::Error),
|
||||
QueueRingIndex(QueueError),
|
||||
}
|
||||
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
@@ -309,7 +307,7 @@ pub struct VirtioPciDevice {
|
||||
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||
|
||||
// virtio queues
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
|
||||
// Guest memory
|
||||
@@ -348,7 +346,7 @@ impl VirtioPciDevice {
|
||||
memory: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
msix_num: u16,
|
||||
iommu_mapping_cb: Option<Arc<VirtioIommuRemapping>>,
|
||||
access_platform: Option<Arc<dyn AccessPlatform>>,
|
||||
interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||
pci_device_bdf: u32,
|
||||
activate_evt: EventFd,
|
||||
@@ -363,8 +361,11 @@ impl VirtioPciDevice {
|
||||
.queue_max_sizes()
|
||||
.iter()
|
||||
.map(|&s| {
|
||||
let mut queue = Queue::new(s);
|
||||
queue.iommu_mapping_cb = iommu_mapping_cb.clone();
|
||||
let mut queue = Queue::<
|
||||
GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
virtio_queue::QueueState<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
>::new(memory.clone(), s);
|
||||
queue.state.access_platform = access_platform.clone();
|
||||
queue
|
||||
})
|
||||
.collect();
|
||||
@@ -432,7 +433,7 @@ impl VirtioPciDevice {
|
||||
device_feature_select: 0,
|
||||
driver_feature_select: 0,
|
||||
queue_select: 0,
|
||||
msix_config: Arc::new(AtomicU16::new(VIRTIO_MSI_NO_VECTOR)),
|
||||
msix_config: Arc::new(AtomicU16::new(VIRTQ_MSI_NO_VECTOR)),
|
||||
},
|
||||
msix_config,
|
||||
msix_num,
|
||||
@@ -472,13 +473,13 @@ impl VirtioPciDevice {
|
||||
.queues
|
||||
.iter()
|
||||
.map(|q| QueueState {
|
||||
max_size: q.max_size,
|
||||
size: q.size,
|
||||
ready: q.ready,
|
||||
vector: q.vector,
|
||||
desc_table: q.desc_table.0,
|
||||
avail_ring: q.avail_ring.0,
|
||||
used_ring: q.used_ring.0,
|
||||
max_size: q.max_size(),
|
||||
size: q.state.size,
|
||||
ready: q.state.ready,
|
||||
vector: q.state.vector,
|
||||
desc_table: q.state.desc_table.0,
|
||||
avail_ring: q.state.avail_ring.0,
|
||||
used_ring: q.state.used_ring.0,
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
@@ -491,27 +492,25 @@ impl VirtioPciDevice {
|
||||
.store(state.interrupt_status, Ordering::Release);
|
||||
|
||||
// Update virtqueues indexes for both available and used rings.
|
||||
if let Some(mem) = self.memory.as_ref() {
|
||||
let mem = mem.memory();
|
||||
for (i, queue) in self.queues.iter_mut().enumerate() {
|
||||
queue.max_size = state.queues[i].max_size;
|
||||
queue.size = state.queues[i].size;
|
||||
queue.ready = state.queues[i].ready;
|
||||
queue.vector = state.queues[i].vector;
|
||||
queue.desc_table = GuestAddress(state.queues[i].desc_table);
|
||||
queue.avail_ring = GuestAddress(state.queues[i].avail_ring);
|
||||
queue.used_ring = GuestAddress(state.queues[i].used_ring);
|
||||
queue.next_avail = Wrapping(
|
||||
queue
|
||||
.used_index_from_memory(&mem)
|
||||
.map_err(Error::QueueRingIndex)?,
|
||||
);
|
||||
queue.next_used = Wrapping(
|
||||
queue
|
||||
.used_index_from_memory(&mem)
|
||||
.map_err(Error::QueueRingIndex)?,
|
||||
);
|
||||
}
|
||||
for (i, queue) in self.queues.iter_mut().enumerate() {
|
||||
queue.state.size = state.queues[i].size;
|
||||
queue.state.ready = state.queues[i].ready;
|
||||
queue.state.vector = state.queues[i].vector;
|
||||
queue.state.desc_table = GuestAddress(state.queues[i].desc_table);
|
||||
queue.state.avail_ring = GuestAddress(state.queues[i].avail_ring);
|
||||
queue.state.used_ring = GuestAddress(state.queues[i].used_ring);
|
||||
queue.set_next_avail(
|
||||
queue
|
||||
.used_idx(Ordering::Acquire)
|
||||
.map_err(Error::QueueRingIndex)?
|
||||
.0,
|
||||
);
|
||||
queue.set_next_used(
|
||||
queue
|
||||
.used_idx(Ordering::Acquire)
|
||||
.map_err(Error::QueueRingIndex)?
|
||||
.0,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -673,10 +672,10 @@ impl VirtioPciDevice {
|
||||
let mut device = self.device.lock().unwrap();
|
||||
let mut queue_evts = Vec::new();
|
||||
let mut queues = self.queues.clone();
|
||||
queues.retain(|q| q.ready);
|
||||
queues.retain(|q| q.state.ready);
|
||||
for (i, queue) in queues.iter().enumerate() {
|
||||
queue_evts.push(self.queue_evts[i].try_clone().unwrap());
|
||||
if !queue.is_valid(&mem.memory()) {
|
||||
if !queue.is_valid() {
|
||||
error!("Queue {} is not valid", i);
|
||||
}
|
||||
}
|
||||
@@ -743,20 +742,20 @@ impl VirtioInterrupt for VirtioInterruptMsix {
|
||||
fn trigger(
|
||||
&self,
|
||||
int_type: &VirtioInterruptType,
|
||||
queue: Option<&Queue>,
|
||||
queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
) -> std::result::Result<(), std::io::Error> {
|
||||
let vector = match int_type {
|
||||
VirtioInterruptType::Config => self.config_vector.load(Ordering::Acquire),
|
||||
VirtioInterruptType::Queue => {
|
||||
if let Some(q) = queue {
|
||||
q.vector
|
||||
q.state.vector
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if vector == VIRTIO_MSI_NO_VECTOR {
|
||||
if vector == VIRTQ_MSI_NO_VECTOR {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -776,12 +775,16 @@ impl VirtioInterrupt for VirtioInterruptMsix {
|
||||
.trigger(vector as InterruptIndex)
|
||||
}
|
||||
|
||||
fn notifier(&self, int_type: &VirtioInterruptType, queue: Option<&Queue>) -> Option<EventFd> {
|
||||
fn notifier(
|
||||
&self,
|
||||
int_type: &VirtioInterruptType,
|
||||
queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
) -> Option<EventFd> {
|
||||
let vector = match int_type {
|
||||
VirtioInterruptType::Config => self.config_vector.load(Ordering::Acquire),
|
||||
VirtioInterruptType::Queue => {
|
||||
if let Some(q) = queue {
|
||||
q.vector
|
||||
q.state.vector
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::super::{ActivateResult, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType};
|
||||
use super::super::{ActivateResult, VirtioCommon, VirtioDevice, VirtioDeviceType};
|
||||
use super::vu_common_ctrl::{VhostUserConfig, VhostUserHandle};
|
||||
use super::{Error, Result, DEFAULT_VIRTIO_FEATURES};
|
||||
use crate::seccomp_filters::Thread;
|
||||
@@ -28,6 +28,7 @@ use virtio_bindings::bindings::virtio_blk::{
|
||||
VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_SEG_MAX,
|
||||
VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_WRITE_ZEROES,
|
||||
};
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::{ByteValued, GuestMemoryAtomic};
|
||||
use vm_migration::{
|
||||
protocol::MemoryRangeTable, Migratable, MigratableError, Pausable, Snapshot, Snapshottable,
|
||||
@@ -279,7 +280,7 @@ impl VirtioDevice for Blk {
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
|
||||
@@ -7,8 +7,8 @@ use crate::seccomp_filters::Thread;
|
||||
use crate::thread_helper::spawn_virtio_thread;
|
||||
use crate::vhost_user::VhostUserCommon;
|
||||
use crate::{
|
||||
ActivateError, ActivateResult, Queue, UserspaceMapping, VirtioCommon, VirtioDevice,
|
||||
VirtioDeviceType, VirtioInterrupt, VirtioSharedMemoryList,
|
||||
ActivateError, ActivateResult, UserspaceMapping, VirtioCommon, VirtioDevice, VirtioDeviceType,
|
||||
VirtioInterrupt, VirtioSharedMemoryList,
|
||||
};
|
||||
use crate::{GuestMemoryMmap, GuestRegionMmap, MmapRegion};
|
||||
use libc::{self, c_void, off64_t, pread64, pwrite64};
|
||||
@@ -27,6 +27,7 @@ use vhost::vhost_user::message::{
|
||||
use vhost::vhost_user::{
|
||||
HandlerResult, MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler,
|
||||
};
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::{
|
||||
Address, ByteValued, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||
};
|
||||
@@ -501,7 +502,7 @@ impl VirtioDevice for Fs {
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::{
|
||||
ActivateError, EpollHelper, EpollHelperError, EpollHelperHandler, GuestMemoryMmap,
|
||||
GuestRegionMmap, Queue, VirtioInterrupt, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IN_ORDER,
|
||||
GuestRegionMmap, VirtioInterrupt, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IN_ORDER,
|
||||
VIRTIO_F_NOTIFICATION_DATA, VIRTIO_F_ORDER_PLATFORM, VIRTIO_F_RING_EVENT_IDX,
|
||||
VIRTIO_F_RING_INDIRECT_DESC, VIRTIO_F_VERSION_1,
|
||||
};
|
||||
@@ -18,12 +18,13 @@ use vhost::vhost_user::message::{
|
||||
};
|
||||
use vhost::vhost_user::{MasterReqHandler, VhostUserMasterReqHandler};
|
||||
use vhost::Error as VhostError;
|
||||
use virtio_queue::Error as QueueError;
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::{
|
||||
mmap::MmapRegionError, Address, Error as MmapError, GuestAddressSpace, GuestMemory,
|
||||
GuestMemoryAtomic,
|
||||
};
|
||||
use vm_migration::{protocol::MemoryRangeTable, MigratableError, Snapshot, VersionMapped};
|
||||
use vm_virtio::Error as VirtioError;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vu_common_ctrl::VhostUserHandle;
|
||||
|
||||
@@ -128,7 +129,7 @@ pub enum Error {
|
||||
/// Missing IrqFd
|
||||
MissingIrqFd,
|
||||
/// Failed getting the available index.
|
||||
GetAvailableIndex(VirtioError),
|
||||
GetAvailableIndex(QueueError),
|
||||
/// Migration is not supported by this vhost-user device.
|
||||
MigrationNotSupported,
|
||||
/// Failed creating memfd.
|
||||
@@ -166,7 +167,7 @@ pub struct VhostUserEpollHandler<S: VhostUserMasterReqHandler> {
|
||||
pub mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
pub kill_evt: EventFd,
|
||||
pub pause_evt: EventFd,
|
||||
pub queues: Vec<Queue>,
|
||||
pub queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
pub queue_evts: Vec<EventFd>,
|
||||
pub virtio_interrupt: Arc<dyn VirtioInterrupt>,
|
||||
pub acked_features: u64,
|
||||
@@ -298,7 +299,7 @@ impl VhostUserCommon {
|
||||
pub fn activate<T: VhostUserMasterReqHandler>(
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
acked_features: u64,
|
||||
|
||||
@@ -6,9 +6,9 @@ use crate::thread_helper::spawn_virtio_thread;
|
||||
use crate::vhost_user::vu_common_ctrl::{VhostUserConfig, VhostUserHandle};
|
||||
use crate::vhost_user::{Error, Result, VhostUserCommon};
|
||||
use crate::{
|
||||
ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue, VirtioCommon,
|
||||
VirtioDevice, VirtioDeviceType, VirtioInterrupt, EPOLL_HELPER_EVENT_LAST,
|
||||
VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_VERSION_1,
|
||||
ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, VirtioCommon, VirtioDevice,
|
||||
VirtioDeviceType, VirtioInterrupt, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_RING_EVENT_IDX,
|
||||
VIRTIO_F_VERSION_1,
|
||||
};
|
||||
use crate::{GuestMemoryMmap, GuestRegionMmap};
|
||||
use net_util::{build_net_config_space, CtrlQueue, MacAddr, VirtioNetConfig};
|
||||
@@ -29,7 +29,8 @@ use virtio_bindings::bindings::virtio_net::{
|
||||
VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_UFO,
|
||||
VIRTIO_NET_F_MAC, VIRTIO_NET_F_MRG_RXBUF,
|
||||
};
|
||||
use vm_memory::{ByteValued, GuestAddressSpace, GuestMemoryAtomic};
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::{ByteValued, GuestMemoryAtomic};
|
||||
use vm_migration::{
|
||||
protocol::MemoryRangeTable, Migratable, MigratableError, Pausable, Snapshot, Snapshottable,
|
||||
Transportable, VersionMapped,
|
||||
@@ -62,7 +63,7 @@ pub struct NetCtrlEpollHandler {
|
||||
pub pause_evt: EventFd,
|
||||
pub ctrl_q: CtrlQueue,
|
||||
pub queue_evt: EventFd,
|
||||
pub queue: Queue,
|
||||
pub queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
}
|
||||
|
||||
impl NetCtrlEpollHandler {
|
||||
@@ -84,12 +85,11 @@ impl EpollHelperHandler for NetCtrlEpollHandler {
|
||||
let ev_type = event.data as u16;
|
||||
match ev_type {
|
||||
CTRL_QUEUE_EVENT => {
|
||||
let mem = self.mem.memory();
|
||||
if let Err(e) = self.queue_evt.read() {
|
||||
error!("failed to get ctl queue event: {:?}", e);
|
||||
return true;
|
||||
}
|
||||
if let Err(e) = self.ctrl_q.process(&mem, &mut self.queue) {
|
||||
if let Err(e) = self.ctrl_q.process(&mut self.queue) {
|
||||
error!("failed to process ctrl queue: {:?}", e);
|
||||
return true;
|
||||
}
|
||||
@@ -308,7 +308,7 @@ impl VirtioDevice for Net {
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
mut queues: Vec<Queue>,
|
||||
mut queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
mut queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::super::{Descriptor, Queue};
|
||||
use super::{Error, Result};
|
||||
use crate::vhost_user::Inflight;
|
||||
use crate::{
|
||||
@@ -13,6 +12,7 @@ use std::ffi;
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::os::unix::net::UnixListener;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::thread::sleep;
|
||||
use std::time::{Duration, Instant};
|
||||
@@ -23,7 +23,10 @@ use vhost::vhost_user::message::{
|
||||
};
|
||||
use vhost::vhost_user::{Master, MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler};
|
||||
use vhost::{VhostBackend, VhostUserDirtyLogRegion, VhostUserMemoryRegionInfo, VringConfigData};
|
||||
use vm_memory::{Address, Error as MmapError, FileOffset, GuestMemory, GuestMemoryRegion};
|
||||
use virtio_queue::{Descriptor, Queue};
|
||||
use vm_memory::{
|
||||
Address, Error as MmapError, FileOffset, GuestMemory, GuestMemoryAtomic, GuestMemoryRegion,
|
||||
};
|
||||
use vm_migration::protocol::MemoryRangeTable;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
@@ -148,7 +151,7 @@ impl VhostUserHandle {
|
||||
pub fn setup_vhost_user<S: VhostUserMasterReqHandler>(
|
||||
&mut self,
|
||||
mem: &GuestMemoryMmap,
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
virtio_interrupt: &Arc<dyn VirtioInterrupt>,
|
||||
acked_features: u64,
|
||||
@@ -203,29 +206,37 @@ impl VhostUserHandle {
|
||||
let actual_size: usize = queue.actual_size().try_into().unwrap();
|
||||
|
||||
let config_data = VringConfigData {
|
||||
queue_max_size: queue.get_max_size(),
|
||||
queue_max_size: queue.max_size(),
|
||||
queue_size: queue.actual_size(),
|
||||
flags: 0u32,
|
||||
desc_table_addr: get_host_address_range(
|
||||
mem,
|
||||
queue.desc_table,
|
||||
queue.state.desc_table,
|
||||
actual_size * std::mem::size_of::<Descriptor>(),
|
||||
)
|
||||
.ok_or(Error::DescriptorTableAddress)? as u64,
|
||||
// The used ring is {flags: u16; idx: u16; virtq_used_elem [{id: u16, len: u16}; actual_size]},
|
||||
// i.e. 4 + (4 + 4) * actual_size.
|
||||
used_ring_addr: get_host_address_range(mem, queue.used_ring, 4 + actual_size * 8)
|
||||
.ok_or(Error::UsedAddress)? as u64,
|
||||
used_ring_addr: get_host_address_range(
|
||||
mem,
|
||||
queue.state.used_ring,
|
||||
4 + actual_size * 8,
|
||||
)
|
||||
.ok_or(Error::UsedAddress)? as u64,
|
||||
// The used ring is {flags: u16; idx: u16; elem [u16; actual_size]},
|
||||
// i.e. 4 + (2) * actual_size.
|
||||
avail_ring_addr: get_host_address_range(mem, queue.avail_ring, 4 + actual_size * 2)
|
||||
.ok_or(Error::AvailAddress)? as u64,
|
||||
avail_ring_addr: get_host_address_range(
|
||||
mem,
|
||||
queue.state.avail_ring,
|
||||
4 + actual_size * 2,
|
||||
)
|
||||
.ok_or(Error::AvailAddress)? as u64,
|
||||
log_addr: None,
|
||||
};
|
||||
|
||||
vrings_info.push(VringInfo {
|
||||
config_data,
|
||||
used_guest_addr: queue.used_ring.raw_value(),
|
||||
used_guest_addr: queue.state.used_ring.raw_value(),
|
||||
});
|
||||
|
||||
self.vu
|
||||
@@ -235,8 +246,9 @@ impl VhostUserHandle {
|
||||
.set_vring_base(
|
||||
queue_index,
|
||||
queue
|
||||
.used_index_from_memory(mem)
|
||||
.map_err(Error::GetAvailableIndex)?,
|
||||
.avail_idx(Ordering::Acquire)
|
||||
.map_err(Error::GetAvailableIndex)?
|
||||
.0,
|
||||
)
|
||||
.map_err(Error::VhostUserSetVringBase)?;
|
||||
|
||||
@@ -317,7 +329,7 @@ impl VhostUserHandle {
|
||||
pub fn reinitialize_vhost_user<S: VhostUserMasterReqHandler>(
|
||||
&mut self,
|
||||
mem: &GuestMemoryMmap,
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
virtio_interrupt: &Arc<dyn VirtioInterrupt>,
|
||||
acked_features: u64,
|
||||
|
||||
@@ -818,8 +818,9 @@ mod tests {
|
||||
let mut handler_ctx = vsock_test_ctx.create_epoll_handler_context();
|
||||
let stream = TestStream::new();
|
||||
let mut pkt = VsockPacket::from_rx_virtq_head(
|
||||
&handler_ctx.handler.queues[0]
|
||||
.iter(&vsock_test_ctx.mem)
|
||||
&mut handler_ctx.handler.queues[0]
|
||||
.iter()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap(),
|
||||
)
|
||||
|
||||
@@ -34,7 +34,7 @@ use crate::GuestMemoryMmap;
|
||||
use crate::VirtioInterrupt;
|
||||
use crate::{
|
||||
thread_helper::spawn_virtio_thread, ActivateResult, EpollHelper, EpollHelperError,
|
||||
EpollHelperHandler, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType,
|
||||
EpollHelperHandler, VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType,
|
||||
EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IN_ORDER, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1,
|
||||
};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
@@ -47,7 +47,8 @@ use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Barrier, RwLock};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use vm_memory::{GuestAddressSpace, GuestMemoryAtomic};
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::GuestMemoryAtomic;
|
||||
use vm_migration::{
|
||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
||||
};
|
||||
@@ -86,7 +87,7 @@ pub const BACKEND_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 4;
|
||||
///
|
||||
pub struct VsockEpollHandler<B: VsockBackend> {
|
||||
pub mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
pub queues: Vec<Queue>,
|
||||
pub queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
pub queue_evts: Vec<EventFd>,
|
||||
pub kill_evt: EventFd,
|
||||
pub pause_evt: EventFd,
|
||||
@@ -101,7 +102,10 @@ where
|
||||
/// Signal the guest driver that we've used some virtio buffers that it had previously made
|
||||
/// available.
|
||||
///
|
||||
fn signal_used_queue(&self, queue: &Queue) -> result::Result<(), DeviceError> {
|
||||
fn signal_used_queue(
|
||||
&self,
|
||||
queue: &Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
) -> result::Result<(), DeviceError> {
|
||||
debug!("vsock: raising IRQ");
|
||||
|
||||
self.interrupt_cb
|
||||
@@ -120,16 +124,17 @@ where
|
||||
|
||||
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
|
||||
let mut used_count = 0;
|
||||
let mem = self.mem.memory();
|
||||
for avail_desc in self.queues[0].iter(&mem) {
|
||||
let used_len = match VsockPacket::from_rx_virtq_head(&avail_desc) {
|
||||
|
||||
let mut avail_iter = self.queues[0].iter().map_err(DeviceError::QueueIterator)?;
|
||||
for mut desc_chain in &mut avail_iter {
|
||||
let used_len = match VsockPacket::from_rx_virtq_head(&mut desc_chain) {
|
||||
Ok(mut pkt) => {
|
||||
if self.backend.write().unwrap().recv_pkt(&mut pkt).is_ok() {
|
||||
pkt.hdr().len() as u32 + pkt.len()
|
||||
} else {
|
||||
// We are using a consuming iterator over the virtio buffers, so, if we can't
|
||||
// fill in this buffer, we'll need to undo the last iterator step.
|
||||
self.queues[0].go_to_previous_position();
|
||||
avail_iter.go_to_previous_position();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -139,12 +144,14 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
used_desc_heads[used_count] = (avail_desc.index, used_len);
|
||||
used_desc_heads[used_count] = (desc_chain.head_index(), used_len);
|
||||
used_count += 1;
|
||||
}
|
||||
|
||||
for &(desc_index, len) in &used_desc_heads[..used_count] {
|
||||
self.queues[0].add_used(&mem, desc_index, len);
|
||||
self.queues[0]
|
||||
.add_used(desc_index, len)
|
||||
.map_err(DeviceError::QueueAddUsed)?;
|
||||
}
|
||||
|
||||
if used_count > 0 {
|
||||
@@ -162,29 +169,32 @@ where
|
||||
|
||||
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
|
||||
let mut used_count = 0;
|
||||
let mem = self.mem.memory();
|
||||
for avail_desc in self.queues[1].iter(&mem) {
|
||||
let pkt = match VsockPacket::from_tx_virtq_head(&avail_desc) {
|
||||
|
||||
let mut avail_iter = self.queues[1].iter().map_err(DeviceError::QueueIterator)?;
|
||||
for mut desc_chain in &mut avail_iter {
|
||||
let pkt = match VsockPacket::from_tx_virtq_head(&mut desc_chain) {
|
||||
Ok(pkt) => pkt,
|
||||
Err(e) => {
|
||||
error!("vsock: error reading TX packet: {:?}", e);
|
||||
used_desc_heads[used_count] = (avail_desc.index, 0);
|
||||
used_desc_heads[used_count] = (desc_chain.head_index(), 0);
|
||||
used_count += 1;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if self.backend.write().unwrap().send_pkt(&pkt).is_err() {
|
||||
self.queues[1].go_to_previous_position();
|
||||
avail_iter.go_to_previous_position();
|
||||
break;
|
||||
}
|
||||
|
||||
used_desc_heads[used_count] = (avail_desc.index, 0);
|
||||
used_desc_heads[used_count] = (desc_chain.head_index(), 0);
|
||||
used_count += 1;
|
||||
}
|
||||
|
||||
for &(desc_index, len) in &used_desc_heads[..used_count] {
|
||||
self.queues[1].add_used(&mem, desc_index, len);
|
||||
self.queues[1]
|
||||
.add_used(desc_index, len)
|
||||
.map_err(DeviceError::QueueAddUsed)?;
|
||||
}
|
||||
|
||||
if used_count > 0 {
|
||||
@@ -417,7 +427,7 @@ where
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
@@ -578,12 +588,18 @@ mod tests {
|
||||
other => panic!("{:?}", other),
|
||||
}
|
||||
|
||||
let memory = GuestMemoryAtomic::new(ctx.mem.clone());
|
||||
|
||||
// Test a correct activation.
|
||||
ctx.device
|
||||
.activate(
|
||||
GuestMemoryAtomic::new(ctx.mem.clone()),
|
||||
memory.clone(),
|
||||
Arc::new(NoopVirtioInterrupt {}),
|
||||
vec![Queue::new(256), Queue::new(256), Queue::new(256)],
|
||||
vec![
|
||||
Queue::new(memory.clone(), 256),
|
||||
Queue::new(memory.clone(), 256),
|
||||
Queue::new(memory, 256),
|
||||
],
|
||||
vec![
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
@@ -599,8 +615,9 @@ mod tests {
|
||||
{
|
||||
let test_ctx = TestContext::new();
|
||||
let ctx = test_ctx.create_epoll_handler_context();
|
||||
let memory = GuestMemoryAtomic::new(test_ctx.mem.clone());
|
||||
|
||||
let queue = Queue::new(256);
|
||||
let queue = Queue::new(memory, 256);
|
||||
assert!(ctx.handler.signal_used_queue(&queue).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,8 @@ pub enum VsockError {
|
||||
GuestMemoryBounds,
|
||||
/// The vsock header descriptor length is too small.
|
||||
HdrDescTooSmall(u32),
|
||||
/// The vsock header descriptor is expected, but missing.
|
||||
HdrDescMissing,
|
||||
/// The vsock header `len` field holds an invalid value.
|
||||
InvalidPktLen(u32),
|
||||
/// A data fetch was attempted when no data was available.
|
||||
@@ -168,10 +170,9 @@ mod tests {
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use virtio_queue::{defs::VIRTQ_DESC_F_NEXT, defs::VIRTQ_DESC_F_WRITE, Queue};
|
||||
use vm_memory::{GuestAddress, GuestMemoryAtomic};
|
||||
use vm_virtio::queue::testing::VirtQueue as GuestQ;
|
||||
use vm_virtio::queue::Queue;
|
||||
use vm_virtio::queue::{VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
pub struct NoopVirtioInterrupt {}
|
||||
@@ -180,7 +181,7 @@ mod tests {
|
||||
fn trigger(
|
||||
&self,
|
||||
_int_type: &VirtioInterruptType,
|
||||
_queue: Option<&Queue>,
|
||||
_queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
) -> std::result::Result<(), std::io::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -19,7 +19,9 @@ use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
use super::defs;
|
||||
use super::{Result, VsockError};
|
||||
use crate::{get_host_address_range, DescriptorChain};
|
||||
use crate::{get_host_address_range, GuestMemoryMmap};
|
||||
use virtio_queue::DescriptorChain;
|
||||
use vm_memory::GuestMemoryAtomic;
|
||||
|
||||
// The vsock packet header is defined by the C struct:
|
||||
//
|
||||
@@ -103,7 +105,11 @@ impl VsockPacket {
|
||||
/// descriptor can optionally end the chain. Bounds and pointer checks are performed when
|
||||
/// creating the wrapper.
|
||||
///
|
||||
pub fn from_tx_virtq_head(head: &DescriptorChain) -> Result<Self> {
|
||||
pub fn from_tx_virtq_head(
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
) -> Result<Self> {
|
||||
let head = desc_chain.next().ok_or(VsockError::HdrDescMissing)?;
|
||||
|
||||
// All buffers in the TX queue must be readable.
|
||||
//
|
||||
if head.is_write_only() {
|
||||
@@ -111,12 +117,12 @@ impl VsockPacket {
|
||||
}
|
||||
|
||||
// The packet header should fit inside the head descriptor.
|
||||
if head.len < VSOCK_PKT_HDR_SIZE as u32 {
|
||||
return Err(VsockError::HdrDescTooSmall(head.len));
|
||||
if head.len() < VSOCK_PKT_HDR_SIZE as u32 {
|
||||
return Err(VsockError::HdrDescTooSmall(head.len()));
|
||||
}
|
||||
|
||||
let mut pkt = Self {
|
||||
hdr: get_host_address_range(head.mem, head.addr, VSOCK_PKT_HDR_SIZE)
|
||||
hdr: get_host_address_range(desc_chain.memory(), head.addr(), VSOCK_PKT_HDR_SIZE)
|
||||
.ok_or(VsockError::GuestMemory)? as *mut u8,
|
||||
buf: None,
|
||||
buf_size: 0,
|
||||
@@ -134,7 +140,7 @@ impl VsockPacket {
|
||||
}
|
||||
|
||||
// If the packet header showed a non-zero length, there should be a data descriptor here.
|
||||
let buf_desc = head.next_descriptor().ok_or(VsockError::BufDescMissing)?;
|
||||
let buf_desc = desc_chain.next().ok_or(VsockError::BufDescMissing)?;
|
||||
|
||||
// TX data should be read-only.
|
||||
if buf_desc.is_write_only() {
|
||||
@@ -143,13 +149,13 @@ impl VsockPacket {
|
||||
|
||||
// The data buffer should be large enough to fit the size of the data, as described by
|
||||
// the header descriptor.
|
||||
if buf_desc.len < pkt.len() {
|
||||
if buf_desc.len() < pkt.len() {
|
||||
return Err(VsockError::BufDescTooSmall);
|
||||
}
|
||||
|
||||
pkt.buf_size = buf_desc.len as usize;
|
||||
pkt.buf_size = buf_desc.len() as usize;
|
||||
pkt.buf = Some(
|
||||
get_host_address_range(buf_desc.mem, buf_desc.addr, pkt.buf_size)
|
||||
get_host_address_range(desc_chain.memory(), buf_desc.addr(), pkt.buf_size)
|
||||
.ok_or(VsockError::GuestMemory)? as *mut u8,
|
||||
);
|
||||
|
||||
@@ -161,7 +167,11 @@ impl VsockPacket {
|
||||
/// There must be two descriptors in the chain, both writable: a header descriptor and a data
|
||||
/// descriptor. Bounds and pointer checks are performed when creating the wrapper.
|
||||
///
|
||||
pub fn from_rx_virtq_head(head: &DescriptorChain) -> Result<Self> {
|
||||
pub fn from_rx_virtq_head(
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
) -> Result<Self> {
|
||||
let head = desc_chain.next().ok_or(VsockError::HdrDescMissing)?;
|
||||
|
||||
// All RX buffers must be writable.
|
||||
//
|
||||
if !head.is_write_only() {
|
||||
@@ -169,22 +179,22 @@ impl VsockPacket {
|
||||
}
|
||||
|
||||
// The packet header should fit inside the head descriptor.
|
||||
if head.len < VSOCK_PKT_HDR_SIZE as u32 {
|
||||
return Err(VsockError::HdrDescTooSmall(head.len));
|
||||
if head.len() < VSOCK_PKT_HDR_SIZE as u32 {
|
||||
return Err(VsockError::HdrDescTooSmall(head.len()));
|
||||
}
|
||||
|
||||
// All RX descriptor chains should have a header and a data descriptor.
|
||||
if !head.has_next() {
|
||||
return Err(VsockError::BufDescMissing);
|
||||
}
|
||||
let buf_desc = head.next_descriptor().ok_or(VsockError::BufDescMissing)?;
|
||||
let buf_size = buf_desc.len as usize;
|
||||
let buf_desc = desc_chain.next().ok_or(VsockError::BufDescMissing)?;
|
||||
let buf_size = buf_desc.len() as usize;
|
||||
|
||||
Ok(Self {
|
||||
hdr: get_host_address_range(head.mem, head.addr, VSOCK_PKT_HDR_SIZE)
|
||||
hdr: get_host_address_range(desc_chain.memory(), head.addr(), VSOCK_PKT_HDR_SIZE)
|
||||
.ok_or(VsockError::GuestMemory)? as *mut u8,
|
||||
buf: Some(
|
||||
get_host_address_range(buf_desc.mem, buf_desc.addr, buf_size)
|
||||
get_host_address_range(desc_chain.memory(), buf_desc.addr(), buf_size)
|
||||
.ok_or(VsockError::GuestMemory)? as *mut u8,
|
||||
),
|
||||
buf_size,
|
||||
@@ -343,9 +353,9 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::vsock::defs::MAX_PKT_BUF_SIZE;
|
||||
use crate::GuestMemoryMmap;
|
||||
use virtio_queue::defs::VIRTQ_DESC_F_WRITE;
|
||||
use vm_memory::GuestAddress;
|
||||
use vm_virtio::queue::testing::VirtqDesc as GuestQDesc;
|
||||
use vm_virtio::queue::VIRTQ_DESC_F_WRITE;
|
||||
|
||||
macro_rules! create_context {
|
||||
($test_ctx:ident, $handler_ctx:ident) => {
|
||||
@@ -365,8 +375,9 @@ mod tests {
|
||||
};
|
||||
($test_ctx:expr, $handler_ctx:expr, $err:pat, $ctor:ident, $vq:expr) => {
|
||||
match VsockPacket::$ctor(
|
||||
&$handler_ctx.handler.queues[$vq]
|
||||
.iter(&$test_ctx.mem)
|
||||
&mut $handler_ctx.handler.queues[$vq]
|
||||
.iter()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap(),
|
||||
) {
|
||||
@@ -394,8 +405,9 @@ mod tests {
|
||||
create_context!(test_ctx, handler_ctx);
|
||||
|
||||
let pkt = VsockPacket::from_tx_virtq_head(
|
||||
&handler_ctx.handler.queues[1]
|
||||
.iter(&test_ctx.mem)
|
||||
&mut handler_ctx.handler.queues[1]
|
||||
.iter()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -430,8 +442,9 @@ mod tests {
|
||||
create_context!(test_ctx, handler_ctx);
|
||||
set_pkt_len(0, &handler_ctx.guest_txvq.dtable[0], &test_ctx.mem);
|
||||
let mut pkt = VsockPacket::from_tx_virtq_head(
|
||||
&handler_ctx.handler.queues[1]
|
||||
.iter(&test_ctx.mem)
|
||||
&mut handler_ctx.handler.queues[1]
|
||||
.iter()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -486,8 +499,9 @@ mod tests {
|
||||
{
|
||||
create_context!(test_ctx, handler_ctx);
|
||||
let pkt = VsockPacket::from_rx_virtq_head(
|
||||
&handler_ctx.handler.queues[0]
|
||||
.iter(&test_ctx.mem)
|
||||
&mut handler_ctx.handler.queues[0]
|
||||
.iter()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -541,8 +555,9 @@ mod tests {
|
||||
|
||||
create_context!(test_ctx, handler_ctx);
|
||||
let mut pkt = VsockPacket::from_rx_virtq_head(
|
||||
&handler_ctx.handler.queues[0]
|
||||
.iter(&test_ctx.mem)
|
||||
&mut handler_ctx.handler.queues[0]
|
||||
.iter()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -630,8 +645,9 @@ mod tests {
|
||||
fn test_packet_buf() {
|
||||
create_context!(test_ctx, handler_ctx);
|
||||
let mut pkt = VsockPacket::from_rx_virtq_head(
|
||||
&handler_ctx.handler.queues[0]
|
||||
.iter(&test_ctx.mem)
|
||||
&mut handler_ctx.handler.queues[0]
|
||||
.iter()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap(),
|
||||
)
|
||||
|
||||
@@ -840,8 +840,9 @@ mod tests {
|
||||
let vsock_test_ctx = VsockTestContext::new();
|
||||
let mut handler_ctx = vsock_test_ctx.create_epoll_handler_context();
|
||||
let pkt = VsockPacket::from_rx_virtq_head(
|
||||
&handler_ctx.handler.queues[0]
|
||||
.iter(&vsock_test_ctx.mem)
|
||||
&mut handler_ctx.handler.queues[0]
|
||||
.iter()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap(),
|
||||
)
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
use super::Error as DeviceError;
|
||||
use super::{
|
||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue,
|
||||
VirtioCommon, VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1,
|
||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, VirtioCommon,
|
||||
VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1,
|
||||
};
|
||||
use crate::seccomp_filters::Thread;
|
||||
use crate::thread_helper::spawn_virtio_thread;
|
||||
@@ -25,7 +25,8 @@ use std::sync::{Arc, Barrier, Mutex};
|
||||
use std::time::Instant;
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use vm_memory::{Bytes, GuestAddressSpace, GuestMemoryAtomic};
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::{Bytes, GuestMemoryAtomic};
|
||||
use vm_migration::VersionMapped;
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@@ -46,8 +47,7 @@ const WATCHDOG_TIMER_INTERVAL: i64 = 15;
|
||||
const WATCHDOG_TIMEOUT: u64 = WATCHDOG_TIMER_INTERVAL as u64 + 5;
|
||||
|
||||
struct WatchdogEpollHandler {
|
||||
queues: Vec<Queue>,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queue_evt: EventFd,
|
||||
kill_evt: EventFd,
|
||||
@@ -64,12 +64,13 @@ impl WatchdogEpollHandler {
|
||||
let queue = &mut self.queues[0];
|
||||
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
|
||||
let mut used_count = 0;
|
||||
let mem = self.mem.memory();
|
||||
for avail_desc in queue.iter(&mem) {
|
||||
for mut desc_chain in queue.iter().unwrap() {
|
||||
let desc = desc_chain.next().unwrap();
|
||||
|
||||
let mut len = 0;
|
||||
|
||||
if avail_desc.is_write_only() && mem.write_obj(1u8, avail_desc.addr).is_ok() {
|
||||
len = avail_desc.len;
|
||||
if desc.is_write_only() && desc_chain.memory().write_obj(1u8, desc.addr()).is_ok() {
|
||||
len = desc.len();
|
||||
// If this is the first "ping" then setup the timer
|
||||
if self.last_ping_time.lock().unwrap().is_none() {
|
||||
info!(
|
||||
@@ -83,12 +84,12 @@ impl WatchdogEpollHandler {
|
||||
self.last_ping_time.lock().unwrap().replace(Instant::now());
|
||||
}
|
||||
|
||||
used_desc_heads[used_count] = (avail_desc.index, len);
|
||||
used_desc_heads[used_count] = (desc_chain.head_index(), len);
|
||||
used_count += 1;
|
||||
}
|
||||
|
||||
for &(desc_index, len) in &used_desc_heads[..used_count] {
|
||||
queue.add_used(&mem, desc_index, len);
|
||||
queue.add_used(desc_index, len).unwrap();
|
||||
}
|
||||
used_count > 0
|
||||
}
|
||||
@@ -288,9 +289,9 @@ impl VirtioDevice for Watchdog {
|
||||
|
||||
fn activate(
|
||||
&mut self,
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
_mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
queues: Vec<Queue>,
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
mut queue_evts: Vec<EventFd>,
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
@@ -308,7 +309,6 @@ impl VirtioDevice for Watchdog {
|
||||
|
||||
let mut handler = WatchdogEpollHandler {
|
||||
queues,
|
||||
mem,
|
||||
interrupt_cb,
|
||||
queue_evt: queue_evts.remove(0),
|
||||
kill_evt,
|
||||
|
||||
Reference in New Issue
Block a user