diff --git a/Cargo.toml b/Cargo.toml index b920917..f7d857a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,4 @@ virtio-bindings = "0.1.0" vm-memory = {version = ">=0.2.0", features = ["backend-mmap", "backend-atomic"]} virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio" } vmm-sys-util = ">=0.3.1" +nix = "0.21.0" diff --git a/src/lib.rs b/src/lib.rs index 3564b06..f9e634a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ #[macro_use] extern crate log; -use std::error; use std::fs::File; use std::io; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; @@ -15,8 +14,10 @@ use std::os::unix::prelude::IntoRawFd; use std::result; use std::sync::{Arc, Mutex, RwLock}; use std::thread; +use std::{error, mem}; use vhost::vhost_user::message::{ - VhostUserConfigFlags, VhostUserMemoryRegion, VhostUserProtocolFeatures, + DescStatePacked, DescStateSplit, QueueRegionPacked, QueueRegionSplit, VhostUserConfigFlags, + VhostUserInflight, VhostUserMemoryRegion, VhostUserProtocolFeatures, VhostUserSingleMemoryRegion, VhostUserVirtioFeatures, VhostUserVringAddrFlags, VhostUserVringState, }; @@ -24,13 +25,14 @@ use vhost::vhost_user::{ Error as VhostUserError, Listener, Result as VhostUserResult, SlaveFsCacheReq, SlaveListener, VhostUserSlaveReqHandlerMut, }; +use virtio_bindings::bindings::virtio_net::VIRTIO_F_RING_PACKED; use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX; +use virtio_queue::Queue; use vm_memory::guest_memory::FileOffset; use vm_memory::{ GuestAddress, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap, GuestRegionMmap, MmapRegion, }; -use virtio_queue::Queue; use vmm_sys_util::eventfd::EventFd; const MAX_MEM_SLOTS: u64 = 32; @@ -453,6 +455,7 @@ struct VhostUserHandler { atomic_mem: GuestMemoryAtomic, vrings: Vec>>, worker_threads: Vec>>, + inflight_file: Option, } impl VhostUserHandler { @@ -536,6 +539,7 @@ impl VhostUserHandler { atomic_mem, vrings, worker_threads, + inflight_file: None, }) } @@ -948,16 +952,54 @@ impl VhostUserSlaveReqHandlerMut for VhostUserHandler { fn get_inflight_fd( &mut self, - _inflight: &vhost::vhost_user::message::VhostUserInflight, - ) -> VhostUserResult<(vhost::vhost_user::message::VhostUserInflight, File)> { - // Assume the backend hasn't negotiated the inflight feature; it - // wouldn't be correct for the backend to do so, as we don't (yet) - // provide a way for it to handle such requests. - Err(VhostUserError::InvalidOperation) + inflight: &VhostUserInflight, + ) -> VhostUserResult<(VhostUserInflight, File)> { + let inflight_queue_region = nix::sys::memfd::memfd_create( + &std::ffi::CString::new("inflight-region").unwrap(), + nix::sys::memfd::MemFdCreateFlag::MFD_CLOEXEC, + ) + .unwrap(); + + self.inflight_file = Some(unsafe { File::from_raw_fd(inflight_queue_region) }); + + let virtio_features = self.get_features().unwrap(); + let total_mmap_size; + let queue_region_size; + let descr_state_size; + if virtio_features & (1 << VIRTIO_F_RING_PACKED) == 0 { + // Use descriptor and queue states for split virtqueues + queue_region_size = mem::size_of::(); + descr_state_size = mem::size_of::(); + } else { + // Use descriptor and queue states for packed virtqueues + queue_region_size = mem::size_of::(); + descr_state_size = mem::size_of::(); + } + + total_mmap_size = (queue_region_size + descr_state_size * inflight.queue_size as usize) + * inflight.num_queues as usize; + + nix::unistd::ftruncate(inflight_queue_region, total_mmap_size as i64).unwrap(); + + Ok(( + VhostUserInflight { + mmap_size: total_mmap_size as u64, + mmap_offset: 0, + num_queues: inflight.num_queues, + queue_size: inflight.queue_size, + }, + unsafe { File::from_raw_fd(inflight_queue_region) }, + )) } - fn set_inflight_fd(&mut self, _inflight: &vhost::vhost_user::message::VhostUserInflight, _file: File) -> VhostUserResult<()> { - Err(VhostUserError::InvalidOperation) + fn set_inflight_fd( + &mut self, + _inflight: &VhostUserInflight, + file: File, + ) -> VhostUserResult<()> { + self.inflight_file = Some(file); + + Ok(()) } }