diff --git a/Cargo.lock b/Cargo.lock index e31494390..6dd426c46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,6 +161,7 @@ dependencies = [ "credibility 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "epoll 4.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -282,6 +283,89 @@ name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "futures" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-channel" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-executor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-io" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-sink" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-task" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-util" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "getrandom" version = "0.1.14" @@ -445,6 +529,15 @@ dependencies = [ "vmm-sys-util 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num_cpus" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "openssl-sys" version = "0.9.54" @@ -492,6 +585,11 @@ dependencies = [ "vm-memory 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pkg-config" version = "0.3.17" @@ -583,6 +681,21 @@ name = "ppv-lite86" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "proc-macro-hack" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-nested" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "proc-macro2" version = "1.0.9" @@ -806,6 +919,11 @@ dependencies = [ "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "smallvec" version = "1.2.0" @@ -1273,6 +1391,15 @@ dependencies = [ "checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" "checksum failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" +"checksum futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" +"checksum futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" +"checksum futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" +"checksum futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" +"checksum futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" +"checksum futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" +"checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" +"checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" @@ -1291,9 +1418,11 @@ dependencies = [ "checksum log 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "1b9ad466a945c9c40f6f9a449c55675547e59bc75a2722d4689042ab3ae80c9c" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum micro_http 0.1.0 (git+https://github.com/firecracker-microvm/micro-http)" = "" +"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum openssl-sys 0.9.54 (registry+https://github.com/rust-lang/crates.io-index)" = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986" "checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" "checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" +"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum pnet 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c08c2c6c26481fcbe49dc4405baedf47151f859c5a45d3f254c2ff74ce51cf0" "checksum pnet_base 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4df28acf2fcc77436dd2b91a9a0c2bb617f9ca5f2acefee1a4135058b9f9801f" @@ -1304,6 +1433,8 @@ dependencies = [ "checksum pnet_sys 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82f881a6d75ac98c5541db6144682d1773bb14c6fc50c6ebac7086c8f7f23c29" "checksum pnet_transport 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b75ccaee7b5daba9f9a7d47bceeb73cc32edde9952dc5409460d6621ec667b6" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" +"checksum proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "369a6ed065f249a159e06c45752c780bda2fb53c995718f9e484d08daa9eb42e" "checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" "checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" @@ -1330,6 +1461,7 @@ dependencies = [ "checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" "checksum signal-hook 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "10b9f3a1686a29f53cfd91ee5e3db3c12313ec02d33765f02c1a9645a1811e2c" "checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" +"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" "checksum ssh2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eb1a0bdfb47e1fa1eb80f67c7909cfddab49d4262025aa9e4f6e9c39ad77b482" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" diff --git a/Cargo.toml b/Cargo.toml index a97aa90ab..c371f13fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ build = "build.rs" arc-swap = ">=0.4.4" clap = { version = "2.33.0", features=["wrap_help"] } epoll = ">=4.0.1" +futures = { version = "0.3.4", features = ["thread-pool"] } lazy_static = "1.4.0" libc = "0.2.67" log = { version = "0.4.10", features = ["std"] } diff --git a/src/bin/vhost_user_fs.rs b/src/bin/vhost_user_fs.rs index 5b666805f..15f7b8987 100644 --- a/src/bin/vhost_user_fs.rs +++ b/src/bin/vhost_user_fs.rs @@ -11,6 +11,7 @@ extern crate vm_virtio; use clap::{App, Arg}; use epoll; +use futures::executor::{ThreadPool, ThreadPoolBuilder}; use libc::EFD_NONBLOCK; use log::*; use std::num::Wrapping; @@ -30,11 +31,13 @@ use virtio_bindings::bindings::virtio_net::*; use virtio_bindings::bindings::virtio_ring::{ VIRTIO_RING_F_EVENT_IDX, VIRTIO_RING_F_INDIRECT_DESC, }; -use vm_memory::GuestMemoryMmap; +use vm_memory::{GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap}; +use vm_virtio::queue::DescriptorChain; use vmm_sys_util::eventfd::EventFd; const QUEUE_SIZE: usize = 1024; const NUM_QUEUES: usize = 2; +const THREAD_POOL_SIZE: usize = 64; // The guest queued an available buffer for the high priority queue. const HIPRIO_QUEUE_EVENT: u16 = 0; @@ -50,6 +53,8 @@ type VhostUserBackendResult = std::result::Result; enum Error { /// Failed to create kill eventfd. CreateKillEventFd(io::Error), + /// Failed to create thread pool. + CreateThreadPool(io::Error), /// Failed to handle event other than input event. HandleEventNotEpollIn, /// Failed to handle unknown event. @@ -62,8 +67,6 @@ enum Error { QueueReader(VufDescriptorError), /// Creating a queue writer failed. QueueWriter(VufDescriptorError), - /// Signaling queue failed. - SignalQueue(io::Error), } impl fmt::Display for Error { @@ -81,12 +84,13 @@ impl convert::From for io::Error { } struct VhostUserFsBackend { - mem: Option, + mem: Option>, kill_evt: EventFd, server: Arc>, // handle request from slave to master vu_req: Option, event_idx: bool, + pool: ThreadPool, } impl Clone for VhostUserFsBackend { @@ -97,46 +101,75 @@ impl Clone for VhostUserFsBackend { server: self.server.clone(), vu_req: self.vu_req.clone(), event_idx: self.event_idx, + pool: self.pool.clone(), } } } impl VhostUserFsBackend { - fn new(fs: F) -> Result { + fn new(fs: F, thread_pool_size: usize) -> Result { Ok(VhostUserFsBackend { mem: None, kill_evt: EventFd::new(EFD_NONBLOCK).map_err(Error::CreateKillEventFd)?, server: Arc::new(Server::new(fs)), vu_req: None, event_idx: false, + pool: ThreadPoolBuilder::new() + .pool_size(thread_pool_size) + .create() + .map_err(Error::CreateThreadPool)?, }) } - fn process_queue(&mut self, vring: &mut Vring) -> Result { + fn process_queue(&mut self, vring_lock: Arc>) -> Result { let mut used_any = false; - let mem = self.mem.as_ref().ok_or(Error::NoMemoryConfigured)?; + let (atomic_mem, mem) = match &self.mem { + Some(m) => (m, m.memory()), + None => return Err(Error::NoMemoryConfigured), + }; + let mut vring = vring_lock.write().unwrap(); while let Some(avail_desc) = vring.mut_queue().iter(&mem).next() { - let head_index = avail_desc.index; - let reader = Reader::new(mem, avail_desc.clone()).map_err(Error::QueueReader)?; - let writer = Writer::new(mem, avail_desc.clone()).map_err(Error::QueueWriter)?; + used_any = true; - self.server - .handle_message(reader, writer, self.vu_req.as_mut()) - .map_err(Error::ProcessQueue)?; - if self.event_idx { - if let Some(used_idx) = vring.mut_queue().add_used(mem, head_index, 0) { - if vring.needs_notification(&mem, Wrapping(used_idx)) { - vring.signal_used_queue().map_err(Error::SignalQueue)?; + // Prepare a set of objects that can be moved to the worker thread. + let desc_head = avail_desc.get_head(); + let atomic_mem = atomic_mem.clone(); + let server = self.server.clone(); + let mut vu_req = self.vu_req.clone(); + let event_idx = self.event_idx; + let vring_lock = vring_lock.clone(); + + self.pool.spawn_ok(async move { + let mem = atomic_mem.memory(); + let desc = DescriptorChain::new_from_head(&mem, desc_head).unwrap(); + let head_index = desc.index; + + let reader = Reader::new(&mem, desc.clone()) + .map_err(Error::QueueReader) + .unwrap(); + let writer = Writer::new(&mem, desc.clone()) + .map_err(Error::QueueWriter) + .unwrap(); + + server + .handle_message(reader, writer, vu_req.as_mut()) + .map_err(Error::ProcessQueue) + .unwrap(); + + let mut vring = vring_lock.write().unwrap(); + + if event_idx { + if let Some(used_idx) = vring.mut_queue().add_used(&mem, head_index, 0) { + if vring.needs_notification(&mem, Wrapping(used_idx)) { + vring.signal_used_queue().unwrap(); + } } - used_any = true; + } else { + vring.mut_queue().add_used(&mem, head_index, 0); + vring.signal_used_queue().unwrap(); } - } else { - vring.mut_queue().add_used(mem, head_index, 0); - vring.signal_used_queue().map_err(Error::SignalQueue)?; - used_any = true; - } - vring.signal_used_queue().map_err(Error::SignalQueue)?; + }); } Ok(used_any) @@ -168,7 +201,7 @@ impl VhostUserBackend for VhostUserFsBack } fn update_memory(&mut self, mem: GuestMemoryMmap) -> VhostUserBackendResult<()> { - self.mem = Some(mem); + self.mem = Some(GuestMemoryAtomic::new(mem)); Ok(()) } @@ -182,14 +215,19 @@ impl VhostUserBackend for VhostUserFsBack return Err(Error::HandleEventNotEpollIn.into()); } - let mut vring = match device_event { + let mem = match &self.mem { + Some(m) => m.memory(), + None => return Err(Error::NoMemoryConfigured.into()), + }; + + let vring_lock = match device_event { HIPRIO_QUEUE_EVENT => { debug!("HIPRIO_QUEUE_EVENT"); - vrings[0].write().unwrap() + vrings[0].clone() } REQ_QUEUE_EVENT => { debug!("QUEUE_EVENT"); - vrings[1].write().unwrap() + vrings[1].clone() } _ => return Err(Error::HandleEventUnknownEvent.into()), }; @@ -200,16 +238,17 @@ impl VhostUserBackend for VhostUserFsBack // calling process_queue() until it stops finding new // requests on the queue. loop { - vring - .mut_queue() - .update_avail_event(self.mem.as_ref().ok_or(Error::NoMemoryConfigured)?); - if !self.process_queue(&mut vring)? { + { + let mut vring = vring_lock.write().unwrap(); + vring.mut_queue().update_avail_event(&mem); + } + if !self.process_queue(vring_lock.clone())? { break; } } } else { // Without EVENT_IDX, a single call is enough. - self.process_queue(&mut vring)?; + self.process_queue(vring_lock)?; } Ok(false) @@ -243,6 +282,13 @@ fn main() { .takes_value(true) .min_values(1), ) + .arg( + Arg::with_name("thread-pool-size") + .long("thread-pool-size") + .help("thread pool size (default 64)") + .takes_value(true) + .min_values(1), + ) .get_matches(); // Retrieve arguments @@ -252,6 +298,10 @@ fn main() { let sock = cmd_arguments .value_of("sock") .expect("Failed to retrieve vhost-user socket path"); + let thread_pool_size: usize = match cmd_arguments.value_of("thread-pool-size") { + Some(size) => size.parse().expect("Invalid argument for thread-pool-size"), + None => THREAD_POOL_SIZE, + }; // Convert into appropriate types let sock = String::from(sock); @@ -261,7 +311,9 @@ fn main() { ..Default::default() }; let fs = PassthroughFs::new(fs_cfg).unwrap(); - let fs_backend = Arc::new(RwLock::new(VhostUserFsBackend::new(fs).unwrap())); + let fs_backend = Arc::new(RwLock::new( + VhostUserFsBackend::new(fs, thread_pool_size).unwrap(), + )); let mut daemon = VhostUserDaemon::new( String::from("vhost-user-fs-backend"),