diff options
author | Zach Reizner <zachr@google.com> | 2018-10-03 10:22:32 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-10-09 21:14:05 -0700 |
commit | 55a9e504beef368bd97e51ffd5a7fa6c034eb8ad (patch) | |
tree | 894d8685e2fdfa105ea35d1cb6cfceee06502c7a /src/plugin | |
parent | 046df60760f3b0691f23c27a7f24a96c9afe8c05 (diff) | |
download | crosvm-55a9e504beef368bd97e51ffd5a7fa6c034eb8ad.tar crosvm-55a9e504beef368bd97e51ffd5a7fa6c034eb8ad.tar.gz crosvm-55a9e504beef368bd97e51ffd5a7fa6c034eb8ad.tar.bz2 crosvm-55a9e504beef368bd97e51ffd5a7fa6c034eb8ad.tar.lz crosvm-55a9e504beef368bd97e51ffd5a7fa6c034eb8ad.tar.xz crosvm-55a9e504beef368bd97e51ffd5a7fa6c034eb8ad.tar.zst crosvm-55a9e504beef368bd97e51ffd5a7fa6c034eb8ad.zip |
cargo fmt all source code
Now that cargo fmt has landed, run it over everything at once to bring rust source to the standard formatting. TEST=cargo test BUG=None Change-Id: Ic95a48725e5a40dcbd33ba6d5aef2bd01e91865b Reviewed-on: https://chromium-review.googlesource.com/1259287 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'src/plugin')
-rw-r--r-- | src/plugin/mod.rs | 295 | ||||
-rw-r--r-- | src/plugin/process.rs | 335 | ||||
-rw-r--r-- | src/plugin/vcpu.rs | 129 |
3 files changed, 384 insertions, 375 deletions
diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index ef55afe..ddff643 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -8,7 +8,7 @@ mod vcpu; use std::fmt; use std::fs::File; use std::io; -use std::os::unix::io::{IntoRawFd, FromRawFd}; +use std::os::unix::io::{FromRawFd, IntoRawFd}; use std::os::unix::net::UnixDatagram; use std::path::Path; use std::result; @@ -17,17 +17,21 @@ use std::sync::{Arc, Barrier}; use std::thread; use std::time::{Duration, Instant}; -use libc::{socketpair, ioctl, c_ulong, AF_UNIX, SOCK_SEQPACKET, FIOCLEX, EAGAIN, EINTR, EINVAL, - ENOENT, EPERM, EDEADLK, EEXIST, EBADF, EOVERFLOW, SIGCHLD, MS_NOSUID, MS_NODEV}; +use libc::{ + c_ulong, ioctl, socketpair, AF_UNIX, EAGAIN, EBADF, EDEADLK, EEXIST, EINTR, EINVAL, ENOENT, + EOVERFLOW, EPERM, FIOCLEX, MS_NODEV, MS_NOSUID, SIGCHLD, SOCK_SEQPACKET, +}; use protobuf::ProtobufError; use io_jail::{self, Minijail}; -use kvm::{Kvm, Vm, Vcpu, VcpuExit, IoeventAddress, NoDatamatch}; +use kvm::{IoeventAddress, Kvm, NoDatamatch, Vcpu, VcpuExit, Vm}; use net_util::{Error as TapError, Tap, TapT}; -use sys_util::{EventFd, MmapError, Killable, SignalFd, SignalFdError, PollContext, PollToken, - GuestMemory, Result as SysResult, Error as SysError, block_signal, clear_signal, - SIGRTMIN, register_signal_handler, geteuid, getegid}; +use sys_util::{ + block_signal, clear_signal, getegid, geteuid, register_signal_handler, Error as SysError, + EventFd, GuestMemory, Killable, MmapError, PollContext, PollToken, Result as SysResult, + SignalFd, SignalFdError, SIGRTMIN, +}; use Config; @@ -123,7 +127,9 @@ impl fmt::Display for Error { Error::MountPlugin(ref e) => write!(f, "failed to mount: {}", e), Error::MountPluginLib(ref e) => write!(f, "failed to mount: {}", e), Error::MountRoot(ref e) => write!(f, "failed to mount: {}", e), - Error::NoRootDir => write!(f, "no root directory for jailed process to pivot root into"), + Error::NoRootDir => { + write!(f, "no root directory for jailed process to pivot root into") + } Error::ParsePivotRoot(ref e) => write!(f, "failed to set jail pivot root: {}", e), Error::ParseSeccomp(ref e) => write!(f, "failed to parse jail seccomp filter: {}", e), Error::PluginFailed(ref e) => write!(f, "plugin exited with error: {}", e), @@ -154,14 +160,11 @@ impl fmt::Display for Error { signo, status, code, - } => { - write!(f, - "process {} died with signal {}, status {}, and code {}", - pid, - signo, - status, - code) - } + } => write!( + f, + "process {} died with signal {}, status {}, and code {}", + pid, signo, status, code + ), Error::SignalFd(ref e) => write!(f, "failed to read signal fd: {:?}", e), Error::SpawnVcpu(ref e) => write!(f, "error spawning vcpu thread: {}", e), Error::TapOpen(ref e) => write!(f, "error opening tap device: {:?}", e), @@ -185,7 +188,10 @@ fn new_seqpacket_pair() -> SysResult<(UnixDatagram, UnixDatagram)> { let ret = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds.as_mut_ptr()); if ret == 0 { ioctl(fds[0], FIOCLEX); - Ok((UnixDatagram::from_raw_fd(fds[0]), UnixDatagram::from_raw_fd(fds[1]))) + Ok(( + UnixDatagram::from_raw_fd(fds[0]), + UnixDatagram::from_raw_fd(fds[1]), + )) } else { Err(SysError::last()) } @@ -242,12 +248,13 @@ fn create_plugin_jail(root: &Path, seccomp_policy: &Path) -> Result<Minijail> { // Create a tmpfs in the plugin's root directory so that we can bind mount it's executable // file into it. The size=67108864 is size=64*1024*1024 or size=64MB. - j.mount_with_data(Path::new("none"), - Path::new("/"), - "tmpfs", - (MS_NOSUID | MS_NODEV) as usize, - "size=67108864") - .map_err(Error::MountRoot)?; + j.mount_with_data( + Path::new("none"), + Path::new("/"), + "tmpfs", + (MS_NOSUID | MS_NODEV) as usize, + "size=67108864", + ).map_err(Error::MountRoot)?; Ok(j) } @@ -277,8 +284,14 @@ enum PluginObject { length: u32, datamatch: u64, }, - Memory { slot: u32, length: usize }, - IrqEvent { irq_id: u32, evt: EventFd }, + Memory { + slot: u32, + length: usize, + }, + IrqEvent { + irq_id: u32, + evt: EventFd, + }, } impl PluginObject { @@ -289,119 +302,114 @@ impl PluginObject { addr, length, datamatch, - } => { - match length { - 0 => vm.unregister_ioevent(&evt, addr, NoDatamatch), - 1 => vm.unregister_ioevent(&evt, addr, datamatch as u8), - 2 => vm.unregister_ioevent(&evt, addr, datamatch as u16), - 4 => vm.unregister_ioevent(&evt, addr, datamatch as u32), - 8 => vm.unregister_ioevent(&evt, addr, datamatch as u64), - _ => Err(SysError::new(EINVAL)), - } - } + } => match length { + 0 => vm.unregister_ioevent(&evt, addr, NoDatamatch), + 1 => vm.unregister_ioevent(&evt, addr, datamatch as u8), + 2 => vm.unregister_ioevent(&evt, addr, datamatch as u16), + 4 => vm.unregister_ioevent(&evt, addr, datamatch as u32), + 8 => vm.unregister_ioevent(&evt, addr, datamatch as u64), + _ => Err(SysError::new(EINVAL)), + }, PluginObject::Memory { slot, .. } => vm.remove_device_memory(slot).and(Ok(())), PluginObject::IrqEvent { irq_id, evt } => vm.unregister_irqfd(&evt, irq_id), } } } -pub fn run_vcpus(kvm: &Kvm, - vm: &Vm, - plugin: &Process, - vcpu_count: u32, - kill_signaled: &Arc<AtomicBool>, - exit_evt: &EventFd, - vcpu_handles: &mut Vec<thread::JoinHandle<()>>) - -> Result<()> { +pub fn run_vcpus( + kvm: &Kvm, + vm: &Vm, + plugin: &Process, + vcpu_count: u32, + kill_signaled: &Arc<AtomicBool>, + exit_evt: &EventFd, + vcpu_handles: &mut Vec<thread::JoinHandle<()>>, +) -> Result<()> { let vcpu_thread_barrier = Arc::new(Barrier::new((vcpu_count) as usize)); for cpu_id in 0..vcpu_count { let kill_signaled = kill_signaled.clone(); let vcpu_thread_barrier = vcpu_thread_barrier.clone(); let vcpu_exit_evt = exit_evt.try_clone().map_err(Error::CloneEventFd)?; let vcpu_plugin = plugin.create_vcpu(cpu_id)?; - let vcpu = Vcpu::new(cpu_id as c_ulong, kvm, vm) - .map_err(Error::CreateVcpu)?; - - vcpu_handles.push(thread::Builder::new() - .name(format!("crosvm_vcpu{}", cpu_id)) - .spawn(move || { - unsafe { - extern "C" fn handle_signal() {} - // Our signal handler does nothing and is trivially async signal safe. - // We need to install this signal handler even though we do block - // the signal below, to ensure that this signal will interrupt - // execution of KVM_RUN (this is implementation issue). - register_signal_handler(SIGRTMIN() + 0, handle_signal) - .expect("failed to register vcpu signal handler"); - } - - // We do not really want the signal handler to run... - block_signal(SIGRTMIN() + 0).expect("failed to block signal"); - // Tell KVM to not block anything when entering kvm run - // because we will be using first RT signal to kick the VCPU. - vcpu.set_signal_mask(&[]) - .expect("failed to set up KVM VCPU signal mask"); + let vcpu = Vcpu::new(cpu_id as c_ulong, kvm, vm).map_err(Error::CreateVcpu)?; + + vcpu_handles.push( + thread::Builder::new() + .name(format!("crosvm_vcpu{}", cpu_id)) + .spawn(move || { + unsafe { + extern "C" fn handle_signal() {} + // Our signal handler does nothing and is trivially async signal safe. + // We need to install this signal handler even though we do block + // the signal below, to ensure that this signal will interrupt + // execution of KVM_RUN (this is implementation issue). + register_signal_handler(SIGRTMIN() + 0, handle_signal) + .expect("failed to register vcpu signal handler"); + } - let res = vcpu_plugin.init(&vcpu); - vcpu_thread_barrier.wait(); - if let Err(e) = res { - error!("failed to initialize vcpu {}: {:?}", cpu_id, e); - } else { - loop { - let run_res = vcpu.run(); - match run_res { - Ok(run) => { - match run { - VcpuExit::IoIn(addr, data) => { - vcpu_plugin.io_read(addr as u64, data, &vcpu); - } - VcpuExit::IoOut(addr, data) => { - vcpu_plugin.io_write(addr as u64, data, &vcpu); - } - VcpuExit::MmioRead(addr, data) => { - vcpu_plugin.mmio_read(addr as u64, data, &vcpu); - } - VcpuExit::MmioWrite(addr, data) => { - vcpu_plugin.mmio_write(addr as u64, data, &vcpu); - } - VcpuExit::Hlt => break, - VcpuExit::Shutdown => break, - VcpuExit::InternalError => { - error!("vcpu {} has internal error", cpu_id); - break; - } - r => warn!("unexpected vcpu exit: {:?}", r), + // We do not really want the signal handler to run... + block_signal(SIGRTMIN() + 0).expect("failed to block signal"); + // Tell KVM to not block anything when entering kvm run + // because we will be using first RT signal to kick the VCPU. + vcpu.set_signal_mask(&[]) + .expect("failed to set up KVM VCPU signal mask"); + + let res = vcpu_plugin.init(&vcpu); + vcpu_thread_barrier.wait(); + if let Err(e) = res { + error!("failed to initialize vcpu {}: {:?}", cpu_id, e); + } else { + loop { + let run_res = vcpu.run(); + match run_res { + Ok(run) => match run { + VcpuExit::IoIn(addr, data) => { + vcpu_plugin.io_read(addr as u64, data, &vcpu); + } + VcpuExit::IoOut(addr, data) => { + vcpu_plugin.io_write(addr as u64, data, &vcpu); + } + VcpuExit::MmioRead(addr, data) => { + vcpu_plugin.mmio_read(addr as u64, data, &vcpu); + } + VcpuExit::MmioWrite(addr, data) => { + vcpu_plugin.mmio_write(addr as u64, data, &vcpu); + } + VcpuExit::Hlt => break, + VcpuExit::Shutdown => break, + VcpuExit::InternalError => { + error!("vcpu {} has internal error", cpu_id); + break; + } + r => warn!("unexpected vcpu exit: {:?}", r), + }, + Err(e) => match e.errno() { + EAGAIN | EINTR => {} + _ => { + error!("vcpu hit unknown error: {:?}", e); + break; + } + }, } - } - Err(e) => { - match e.errno() { - EAGAIN | EINTR => {} - _ => { - error!("vcpu hit unknown error: {:?}", e); - break; - } + if kill_signaled.load(Ordering::SeqCst) { + break; } - } - } - if kill_signaled.load(Ordering::SeqCst) { - break; - } - // Try to clear the signal that we use to kick VCPU if it is - // pending before attempting to handle pause requests. - clear_signal(SIGRTMIN() + 0).expect("failed to clear pending signal"); + // Try to clear the signal that we use to kick VCPU if it is + // pending before attempting to handle pause requests. + clear_signal(SIGRTMIN() + 0).expect("failed to clear pending signal"); - if let Err(e) = vcpu_plugin.pre_run(&vcpu) { - error!("failed to process pause on vcpu {}: {:?}", cpu_id, e); - break; + if let Err(e) = vcpu_plugin.pre_run(&vcpu) { + error!("failed to process pause on vcpu {}: {:?}", cpu_id, e); + break; + } + } } - } - } - vcpu_exit_evt - .write(1) - .expect("failed to signal vcpu exit eventfd"); - }) - .map_err(Error::SpawnVcpu)?); + vcpu_exit_evt + .write(1) + .expect("failed to signal vcpu exit eventfd"); + }).map_err(Error::SpawnVcpu)?, + ); } Ok(()) } @@ -504,8 +512,9 @@ pub fn run_config(cfg: Config) -> Result<()> { 'poll: loop { // After we have waited long enough, it's time to give up and exit. if dying_instant - .map(|i| i.elapsed() >= duration_to_die) - .unwrap_or(false) { + .map(|i| i.elapsed() >= duration_to_die) + .unwrap_or(false) + { break; } @@ -559,11 +568,11 @@ pub fn run_config(cfg: Config) -> Result<()> { // plugin process, report it as an error. if res.is_ok() { res = Err(Error::SigChild { - pid: siginfo.ssi_pid, - signo: siginfo.ssi_signo, - status: siginfo.ssi_status, - code: siginfo.ssi_code, - }) + pid: siginfo.ssi_pid, + signo: siginfo.ssi_signo, + status: siginfo.ssi_status, + code: siginfo.ssi_code, + }) } } Ok(None) => break, // No more signals to read. @@ -586,11 +595,13 @@ pub fn run_config(cfg: Config) -> Result<()> { } } Token::Plugin { index } => { - match plugin.handle_socket(index, - &kvm, - &mut vm, - &vcpu_handles, - tap_opt.as_ref()) { + match plugin.handle_socket( + index, + &kvm, + &mut vm, + &vcpu_handles, + tap_opt.as_ref(), + ) { Ok(_) => {} // A HUP is an expected event for a socket, so don't bother warning about // it. @@ -608,21 +619,23 @@ pub fn run_config(cfg: Config) -> Result<()> { } if vcpu_handles.is_empty() && dying_instant.is_none() && plugin.is_started() { - let res = run_vcpus(&kvm, - &vm, - &plugin, - vcpu_count, - &kill_signaled, - &exit_evt, - &mut vcpu_handles); + let res = run_vcpus( + &kvm, + &vm, + &plugin, + vcpu_count, + &kill_signaled, + &exit_evt, + &mut vcpu_handles, + ); if let Err(e) = res { dying_instant.get_or_insert(Instant::now()); error!("failed to start vcpus: {}", e); } } - redo_poll_ctx_sockets = !sockets_to_drop.is_empty() || - plugin.sockets().len() != plugin_socket_count; + redo_poll_ctx_sockets = + !sockets_to_drop.is_empty() || plugin.sockets().len() != plugin_socket_count; // Cleanup all of the sockets that we have determined were disconnected or suffered some // other error. diff --git a/src/plugin/process.rs b/src/plugin/process.rs index 71c16c0..c99e3b6 100644 --- a/src/plugin/process.rs +++ b/src/plugin/process.rs @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -use std::collections::hash_map::{HashMap, Entry, VacantEntry}; +use std::collections::hash_map::{Entry, HashMap, VacantEntry}; use std::env::set_var; use std::fs::File; use std::mem::transmute; @@ -17,17 +17,19 @@ use std::thread::JoinHandle; use net_util; use net_util::Error as NetError; -use libc::{waitpid, pid_t, EINVAL, ENODATA, ENOTTY, WNOHANG, WIFEXITED, WEXITSTATUS, WTERMSIG}; +use libc::{pid_t, waitpid, EINVAL, ENODATA, ENOTTY, WEXITSTATUS, WIFEXITED, WNOHANG, WTERMSIG}; use protobuf; use protobuf::Message; use io_jail::Minijail; -use kvm::{Vm, IoeventAddress, NoDatamatch, IrqSource, IrqRoute, PicId, dirty_log_bitmap_size}; -use kvm_sys::{kvm_pic_state, kvm_ioapic_state, kvm_pit_state2}; -use sys_util::{EventFd, MemoryMapping, Killable, ScmSocket, SharedMemory, GuestAddress, - Result as SysResult, Error as SysError, SIGRTMIN}; +use kvm::{dirty_log_bitmap_size, IoeventAddress, IrqRoute, IrqSource, NoDatamatch, PicId, Vm}; +use kvm_sys::{kvm_ioapic_state, kvm_pic_state, kvm_pit_state2}; use plugin_proto::*; +use sys_util::{ + Error as SysError, EventFd, GuestAddress, Killable, MemoryMapping, Result as SysResult, + ScmSocket, SharedMemory, SIGRTMIN, +}; use super::*; @@ -45,47 +47,41 @@ unsafe impl DataInit for VmPitState {} fn get_vm_state(vm: &Vm, state_set: MainRequest_StateSet) -> SysResult<Vec<u8>> { Ok(match state_set { - MainRequest_StateSet::PIC0 => { - VmPicState(vm.get_pic_state(PicId::Primary)?) - .as_slice() - .to_vec() - } - MainRequest_StateSet::PIC1 => { - VmPicState(vm.get_pic_state(PicId::Secondary)?) - .as_slice() - .to_vec() - } - MainRequest_StateSet::IOAPIC => { - VmIoapicState(vm.get_ioapic_state()?).as_slice().to_vec() - } - MainRequest_StateSet::PIT => VmPitState(vm.get_pit_state()?).as_slice().to_vec(), - }) + MainRequest_StateSet::PIC0 => VmPicState(vm.get_pic_state(PicId::Primary)?) + .as_slice() + .to_vec(), + MainRequest_StateSet::PIC1 => VmPicState(vm.get_pic_state(PicId::Secondary)?) + .as_slice() + .to_vec(), + MainRequest_StateSet::IOAPIC => VmIoapicState(vm.get_ioapic_state()?).as_slice().to_vec(), + MainRequest_StateSet::PIT => VmPitState(vm.get_pit_state()?).as_slice().to_vec(), + }) } fn set_vm_state(vm: &Vm, state_set: MainRequest_StateSet, state: &[u8]) -> SysResult<()> { match state_set { - MainRequest_StateSet::PIC0 => { - vm.set_pic_state(PicId::Primary, - &VmPicState::from_slice(state) - .ok_or(SysError::new(EINVAL))? - .0) - } - MainRequest_StateSet::PIC1 => { - vm.set_pic_state(PicId::Secondary, - &VmPicState::from_slice(state) - .ok_or(SysError::new(EINVAL))? - .0) - } - MainRequest_StateSet::IOAPIC => { - vm.set_ioapic_state(&VmIoapicState::from_slice(state) - .ok_or(SysError::new(EINVAL))? - .0) - } - MainRequest_StateSet::PIT => { - vm.set_pit_state(&VmPitState::from_slice(state) - .ok_or(SysError::new(EINVAL))? - .0) - } + MainRequest_StateSet::PIC0 => vm.set_pic_state( + PicId::Primary, + &VmPicState::from_slice(state) + .ok_or(SysError::new(EINVAL))? + .0, + ), + MainRequest_StateSet::PIC1 => vm.set_pic_state( + PicId::Secondary, + &VmPicState::from_slice(state) + .ok_or(SysError::new(EINVAL))? + .0, + ), + MainRequest_StateSet::IOAPIC => vm.set_ioapic_state( + &VmIoapicState::from_slice(state) + .ok_or(SysError::new(EINVAL))? + .0, + ), + MainRequest_StateSet::PIT => vm.set_pit_state( + &VmPitState::from_slice(state) + .ok_or(SysError::new(EINVAL))? + .0, + ), } } @@ -132,20 +128,22 @@ impl Process { /// Set the `jail` argument to spawn the plugin process within the preconfigured jail. /// Due to an API limitation in libminijail necessitating that this function set an environment /// variable, this function is not thread-safe. - pub fn new(cpu_count: u32, - cmd: &Path, - args: &[&str], - jail: Option<Minijail>) - -> Result<Process> { - let (request_socket, child_socket) = new_seqpacket_pair().map_err(Error::CreateMainSocket)?; - - let mut vcpu_sockets: Vec<(UnixDatagram, UnixDatagram)> = Vec::with_capacity(cpu_count as - usize); + pub fn new( + cpu_count: u32, + cmd: &Path, + args: &[&str], + jail: Option<Minijail>, + ) -> Result<Process> { + let (request_socket, child_socket) = + new_seqpacket_pair().map_err(Error::CreateMainSocket)?; + + let mut vcpu_sockets: Vec<(UnixDatagram, UnixDatagram)> = + Vec::with_capacity(cpu_count as usize); for _ in 0..cpu_count { vcpu_sockets.push(new_seqpacket_pair().map_err(Error::CreateVcpuSocket)?); } - let mut per_vcpu_states: Vec<Arc<Mutex<PerVcpuState>>> = Vec::with_capacity(cpu_count as - usize); + let mut per_vcpu_states: Vec<Arc<Mutex<PerVcpuState>>> = + Vec::with_capacity(cpu_count as usize); // TODO(zachr): replace with `resize_default` when that stabilizes. Using a plain `resize` // is incorrect because each element in the `Vec` will contain a shared reference to the // same `PerVcpuState` instance. This happens because `resize` fills new slots using clones @@ -160,28 +158,26 @@ impl Process { jail.run(cmd, &[0, 1, 2, child_socket.as_raw_fd()], args) .map_err(Error::PluginRunJail)? } - None => { - Command::new(cmd) - .args(args) - .env("CROSVM_SOCKET", child_socket.as_raw_fd().to_string()) - .spawn() - .map_err(Error::PluginSpawn)? - .id() as pid_t - } + None => Command::new(cmd) + .args(args) + .env("CROSVM_SOCKET", child_socket.as_raw_fd().to_string()) + .spawn() + .map_err(Error::PluginSpawn)? + .id() as pid_t, }; Ok(Process { - started: false, - plugin_pid, - request_sockets: vec![request_socket], - objects: Default::default(), - shared_vcpu_state: Default::default(), - per_vcpu_states, - kill_evt: EventFd::new().map_err(Error::CreateEventFd)?, - vcpu_sockets, - request_buffer: vec![0; MAX_DATAGRAM_SIZE], - response_buffer: Vec::new(), - }) + started: false, + plugin_pid, + request_sockets: vec![request_socket], + objects: Default::default(), + shared_vcpu_state: Default::default(), + per_vcpu_states, + kill_evt: EventFd::new().map_err(Error::CreateEventFd)?, + vcpu_sockets, + request_buffer: vec![0; MAX_DATAGRAM_SIZE], + response_buffer: Vec::new(), + }) } /// Creates a VCPU plugin connection object, used by a VCPU run loop to communicate with the @@ -195,9 +191,11 @@ impl Process { .0 .try_clone() .map_err(Error::CloneVcpuSocket)?; - Ok(PluginVcpu::new(self.shared_vcpu_state.clone(), - self.per_vcpu_states[cpu_id as usize].clone(), - vcpu_socket)) + Ok(PluginVcpu::new( + self.shared_vcpu_state.clone(), + self.per_vcpu_states[cpu_id as usize].clone(), + vcpu_socket, + )) } /// Returns if the plugin process indicated the VM was ready to start. @@ -267,7 +265,8 @@ impl Process { _ => { // Trivially safe if unsafe { WIFEXITED(status) } { - match unsafe { WEXITSTATUS(status) } { // Trivially safe + match unsafe { WEXITSTATUS(status) } { + // Trivially safe 0 => Ok(ProcessStatus::Success), code => Ok(ProcessStatus::Fail(code)), } @@ -279,10 +278,11 @@ impl Process { } } - fn handle_io_event(entry: VacantEntry<u32, PluginObject>, - vm: &mut Vm, - io_event: &MainRequest_Create_IoEvent) - -> SysResult<RawFd> { + fn handle_io_event( + entry: VacantEntry<u32, PluginObject>, + vm: &mut Vm, + io_event: &MainRequest_Create_IoEvent, + ) -> SysResult<RawFd> { let evt = EventFd::new()?; let addr = match io_event.space { AddressSpace::IOPORT => IoeventAddress::Pio(io_event.address), @@ -299,24 +299,24 @@ impl Process { let fd = evt.as_raw_fd(); entry.insert(PluginObject::IoEvent { - evt, - addr, - length: io_event.length, - datamatch: io_event.datamatch, - }); + evt, + addr, + length: io_event.length, + datamatch: io_event.datamatch, + }); Ok(fd) } - - fn handle_memory(entry: VacantEntry<u32, PluginObject>, - vm: &mut Vm, - memfd: File, - offset: u64, - start: u64, - length: u64, - read_only: bool, - dirty_log: bool) - -> SysResult<()> { + fn handle_memory( + entry: VacantEntry<u32, PluginObject>, + vm: &mut Vm, + memfd: File, + offset: u64, + start: u64, + length: u64, + read_only: bool, + dirty_log: bool, + ) -> SysResult<()> { let shm = SharedMemory::from_raw_fd(memfd)?; // Checking the seals ensures the plugin process won't shrink the mmapped file, causing us // to SIGBUS in the future. @@ -334,9 +334,9 @@ impl Process { .map_err(mmap_to_sys_err)?; let slot = vm.add_device_memory(GuestAddress(start), mem, read_only, dirty_log)?; entry.insert(PluginObject::Memory { - slot, - length: length as usize, - }); + slot, + length: length as usize, + }); Ok(()) } @@ -356,42 +356,43 @@ impl Process { } } - fn handle_set_irq_routing(vm: &mut Vm, - irq_routing: &MainRequest_SetIrqRouting) - -> SysResult<()> { + fn handle_set_irq_routing( + vm: &mut Vm, + irq_routing: &MainRequest_SetIrqRouting, + ) -> SysResult<()> { let mut routes = Vec::with_capacity(irq_routing.routes.len()); for route in irq_routing.routes.iter() { routes.push(IrqRoute { - gsi: route.irq_id, - source: if route.has_irqchip() { - let irqchip = route.get_irqchip(); - IrqSource::Irqchip { - chip: irqchip.irqchip, - pin: irqchip.pin, - } - } else if route.has_msi() { - let msi = route.get_msi(); - IrqSource::Msi { - address: msi.address, - data: msi.data, - } - } else { - // Because route is a oneof field in the proto definition, this should - // only happen if a new variant gets added without updating this chained - // if block. - return Err(SysError::new(EINVAL)); - }, - }); + gsi: route.irq_id, + source: if route.has_irqchip() { + let irqchip = route.get_irqchip(); + IrqSource::Irqchip { + chip: irqchip.irqchip, + pin: irqchip.pin, + } + } else if route.has_msi() { + let msi = route.get_msi(); + IrqSource::Msi { + address: msi.address, + data: msi.data, + } + } else { + // Because route is a oneof field in the proto definition, this should + // only happen if a new variant gets added without updating this chained + // if block. + return Err(SysError::new(EINVAL)); + }, + }); } vm.set_gsi_routing(&routes[..]) } fn handle_pause_vcpus(&self, vcpu_handles: &[JoinHandle<()>], cpu_mask: u64, user_data: u64) { - for (cpu_id, (handle, per_cpu_state)) in - vcpu_handles - .iter() - .zip(self.per_vcpu_states.iter()) - .enumerate() { + for (cpu_id, (handle, per_cpu_state)) in vcpu_handles + .iter() + .zip(self.per_vcpu_states.iter()) + .enumerate() + { if cpu_mask & (1 << cpu_id) != 0 { per_cpu_state.lock().unwrap().request_pause(user_data); if let Err(e) = handle.kill(SIGRTMIN() + 0) { @@ -401,9 +402,10 @@ impl Process { } } - fn handle_get_net_config(tap: &net_util::Tap, - config: &mut MainResponse_GetNetConfig) - -> SysResult<()> { + fn handle_get_net_config( + tap: &net_util::Tap, + config: &mut MainResponse_GetNetConfig, + ) -> SysResult<()> { // Log any NetError so that the cause can be found later, but extract and return the // underlying errno for the client as well. fn map_net_error(s: &str, e: NetError) -> SysError { @@ -411,15 +413,15 @@ impl Process { e.sys_error() } - let ip_addr = tap.ip_addr() - .map_err(|e| map_net_error("IP address", e))?; + let ip_addr = tap.ip_addr().map_err(|e| map_net_error("IP address", e))?; config.set_host_ipv4_address(u32::from(ip_addr)); let netmask = tap.netmask().map_err(|e| map_net_error("netmask", e))?; config.set_netmask(u32::from(netmask)); let result_mac_addr = config.mut_host_mac_address(); - let mac_addr_octets = tap.mac_address() + let mac_addr_octets = tap + .mac_address() .map_err(|e| map_net_error("mac address", e))? .octets(); result_mac_addr.resize(mac_addr_octets.len(), 0); @@ -433,13 +435,14 @@ impl Process { /// /// The `vm` is used to service request that affect the VM. The `vcpu_handles` slice is used to /// interrupt a VCPU thread currently running in the VM if the socket request it. - pub fn handle_socket(&mut self, - index: usize, - kvm: &Kvm, - vm: &mut Vm, - vcpu_handles: &[JoinHandle<()>], - tap: Option<&Tap>) - -> Result<()> { + pub fn handle_socket( + &mut self, + index: usize, + kvm: &Kvm, + vm: &mut Vm, + vcpu_handles: &[JoinHandle<()>], + tap: Option<&Tap>, + ) -> Result<()> { let (msg_size, request_file) = self.request_sockets[index] .recv_with_fd(&mut self.request_buffer) .map_err(Error::PluginSocketRecv)?; @@ -470,38 +473,38 @@ impl Process { } else if create.has_memory() { let memory = create.get_memory(); match request_file { - Some(memfd) => { - Self::handle_memory(entry, - vm, - memfd, - memory.offset, - memory.start, - memory.length, - memory.read_only, - memory.dirty_log) - } + Some(memfd) => Self::handle_memory( + entry, + vm, + memfd, + memory.offset, + memory.start, + memory.length, + memory.read_only, + memory.dirty_log, + ), None => Err(SysError::new(EBADF)), } } else if create.has_irq_event() { let irq_event = create.get_irq_event(); match (EventFd::new(), EventFd::new()) { - (Ok(evt), Ok(resample_evt)) => { - match vm.register_irqfd_resample(&evt, - &resample_evt, - irq_event.irq_id) { - Ok(()) => { - response_fds.push(evt.as_raw_fd()); - response_fds.push(resample_evt.as_raw_fd()); - response_files.push(downcast_file(resample_evt)); - entry.insert(PluginObject::IrqEvent { - irq_id: irq_event.irq_id, - evt, - }); - Ok(()) - } - Err(e) => Err(e), + (Ok(evt), Ok(resample_evt)) => match vm.register_irqfd_resample( + &evt, + &resample_evt, + irq_event.irq_id, + ) { + Ok(()) => { + response_fds.push(evt.as_raw_fd()); + response_fds.push(resample_evt.as_raw_fd()); + response_files.push(downcast_file(resample_evt)); + entry.insert(PluginObject::IrqEvent { + irq_id: irq_event.irq_id, + evt, + }); + Ok(()) } - } + Err(e) => Err(e), + }, (Err(e), _) | (_, Err(e)) => Err(e), } } else { diff --git a/src/plugin/vcpu.rs b/src/plugin/vcpu.rs index 5ff5366..76c58cc 100644 --- a/src/plugin/vcpu.rs +++ b/src/plugin/vcpu.rs @@ -4,21 +4,23 @@ use std::cell::{Cell, RefCell}; use std::cmp::min; -use std::cmp::{self, Ord, PartialOrd, PartialEq}; +use std::cmp::{self, Ord, PartialEq, PartialOrd}; use std::collections::btree_set::BTreeSet; use std::mem::size_of; use std::os::unix::net::UnixDatagram; use std::sync::{Arc, Mutex, RwLock}; -use libc::{EINVAL, EPROTO, ENOENT, EPERM, EPIPE, EDEADLK, ENOTTY}; +use libc::{EDEADLK, EINVAL, ENOENT, ENOTTY, EPERM, EPIPE, EPROTO}; use protobuf; use protobuf::Message; use data_model::DataInit; -use kvm::{Vcpu, CpuId}; -use kvm_sys::{kvm_regs, kvm_sregs, kvm_fpu, kvm_debugregs, kvm_xcrs, kvm_msrs, kvm_msr_entry, - KVM_CPUID_FLAG_SIGNIFCANT_INDEX, kvm_lapic_state, kvm_mp_state, kvm_vcpu_events}; +use kvm::{CpuId, Vcpu}; +use kvm_sys::{ + kvm_debugregs, kvm_fpu, kvm_lapic_state, kvm_mp_state, kvm_msr_entry, kvm_msrs, kvm_regs, + kvm_sregs, kvm_vcpu_events, kvm_xcrs, KVM_CPUID_FLAG_SIGNIFCANT_INDEX, +}; use plugin_proto::*; use super::*; @@ -81,65 +83,56 @@ unsafe impl DataInit for VcpuEvents {} fn get_vcpu_state(vcpu: &Vcpu, state_set: VcpuRequest_StateSet) -> SysResult<Vec<u8>> { Ok(match state_set { - VcpuRequest_StateSet::REGS => VcpuRegs(vcpu.get_regs()?).as_slice().to_vec(), - VcpuRequest_StateSet::SREGS => VcpuSregs(vcpu.get_sregs()?).as_slice().to_vec(), - VcpuRequest_StateSet::FPU => VcpuFpu(vcpu.get_fpu()?).as_slice().to_vec(), - VcpuRequest_StateSet::DEBUGREGS => { - VcpuDebugregs(vcpu.get_debugregs()?).as_slice().to_vec() - } - VcpuRequest_StateSet::XCREGS => VcpuXcregs(vcpu.get_xcrs()?).as_slice().to_vec(), - VcpuRequest_StateSet::LAPIC => VcpuLapicState(vcpu.get_lapic()?).as_slice().to_vec(), - VcpuRequest_StateSet::MP => VcpuMpState(vcpu.get_mp_state()?).as_slice().to_vec(), - VcpuRequest_StateSet::EVENTS => VcpuEvents(vcpu.get_vcpu_events()?).as_slice().to_vec(), - }) + VcpuRequest_StateSet::REGS => VcpuRegs(vcpu.get_regs()?).as_slice().to_vec(), + VcpuRequest_StateSet::SREGS => VcpuSregs(vcpu.get_sregs()?).as_slice().to_vec(), + VcpuRequest_StateSet::FPU => VcpuFpu(vcpu.get_fpu()?).as_slice().to_vec(), + VcpuRequest_StateSet::DEBUGREGS => VcpuDebugregs(vcpu.get_debugregs()?).as_slice().to_vec(), + VcpuRequest_StateSet::XCREGS => VcpuXcregs(vcpu.get_xcrs()?).as_slice().to_vec(), + VcpuRequest_StateSet::LAPIC => VcpuLapicState(vcpu.get_lapic()?).as_slice().to_vec(), + VcpuRequest_StateSet::MP => VcpuMpState(vcpu.get_mp_state()?).as_slice().to_vec(), + VcpuRequest_StateSet::EVENTS => VcpuEvents(vcpu.get_vcpu_events()?).as_slice().to_vec(), + }) } fn set_vcpu_state(vcpu: &Vcpu, state_set: VcpuRequest_StateSet, state: &[u8]) -> SysResult<()> { match state_set { VcpuRequest_StateSet::REGS => { - vcpu.set_regs(&VcpuRegs::from_slice(state) - .ok_or(SysError::new(EINVAL))? - .0) + vcpu.set_regs(&VcpuRegs::from_slice(state).ok_or(SysError::new(EINVAL))?.0) } VcpuRequest_StateSet::SREGS => { - vcpu.set_sregs(&VcpuSregs::from_slice(state) - .ok_or(SysError::new(EINVAL))? - .0) + vcpu.set_sregs(&VcpuSregs::from_slice(state).ok_or(SysError::new(EINVAL))?.0) } VcpuRequest_StateSet::FPU => { - vcpu.set_fpu(&VcpuFpu::from_slice(state) - .ok_or(SysError::new(EINVAL))? - .0) - } - VcpuRequest_StateSet::DEBUGREGS => { - vcpu.set_debugregs(&VcpuDebugregs::from_slice(state) - .ok_or(SysError::new(EINVAL))? - .0) - } - VcpuRequest_StateSet::XCREGS => { - vcpu.set_xcrs(&VcpuXcregs::from_slice(state) - .ok_or(SysError::new(EINVAL))? - .0) - } - VcpuRequest_StateSet::LAPIC => { - vcpu.set_lapic(&VcpuLapicState::from_slice(state) - .ok_or(SysError::new(EINVAL))? - .0) - } - VcpuRequest_StateSet::MP => { - vcpu.set_mp_state(&VcpuMpState::from_slice(state) - .ok_or(SysError::new(EINVAL))? - .0) - } - VcpuRequest_StateSet::EVENTS => { - vcpu.set_vcpu_events(&VcpuEvents::from_slice(state) - .ok_or(SysError::new(EINVAL))? - .0) + vcpu.set_fpu(&VcpuFpu::from_slice(state).ok_or(SysError::new(EINVAL))?.0) } + VcpuRequest_StateSet::DEBUGREGS => vcpu.set_debugregs( + &VcpuDebugregs::from_slice(state) + .ok_or(SysError::new(EINVAL))? + .0, + ), + VcpuRequest_StateSet::XCREGS => vcpu.set_xcrs( + &VcpuXcregs::from_slice(state) + .ok_or(SysError::new(EINVAL))? + .0, + ), + VcpuRequest_StateSet::LAPIC => vcpu.set_lapic( + &VcpuLapicState::from_slice(state) + .ok_or(SysError::new(EINVAL))? + .0, + ), + VcpuRequest_StateSet::MP => vcpu.set_mp_state( + &VcpuMpState::from_slice(state) + .ok_or(SysError::new(EINVAL))? + .0, + ), + VcpuRequest_StateSet::EVENTS => vcpu.set_vcpu_events( + &VcpuEvents::from_slice(state) + .ok_or(SysError::new(EINVAL))? + .0, + ), } } - /// State shared by every VCPU, grouped together to make edits to the state coherent across VCPUs. #[derive(Default)] pub struct SharedVcpuState { @@ -171,10 +164,7 @@ impl SharedVcpuState { IoSpace::Mmio => &mut self.mmio_regions, }; - match space - .range(..Range(last_address, 0)) - .next_back() - .cloned() { + match space.range(..Range(last_address, 0)).next_back().cloned() { Some(Range(existing_start, _)) if existing_start >= start => Err(SysError::new(EPERM)), _ => { space.insert(Range(start, length)); @@ -291,10 +281,11 @@ pub struct PluginVcpu { impl PluginVcpu { /// Creates the plugin state and connection container for a VCPU thread. - pub fn new(shared_vcpu_state: Arc<RwLock<SharedVcpuState>>, - per_vcpu_state: Arc<Mutex<PerVcpuState>>, - connection: UnixDatagram) - -> PluginVcpu { + pub fn new( + shared_vcpu_state: Arc<RwLock<SharedVcpuState>>, + per_vcpu_state: Arc<Mutex<PerVcpuState>>, + connection: UnixDatagram, + ) -> PluginVcpu { PluginVcpu { shared_vcpu_state, per_vcpu_state, @@ -320,7 +311,8 @@ impl PluginVcpu { /// to this VCPU. pub fn pre_run(&self, vcpu: &Vcpu) -> SysResult<()> { let request = { - let mut lock = self.per_vcpu_state + let mut lock = self + .per_vcpu_state .lock() .map_err(|_| SysError::new(EDEADLK))?; lock.pause_request.take() @@ -403,11 +395,11 @@ impl PluginVcpu { let mut request_buffer = self.request_buffer.borrow_mut(); request_buffer.resize(MAX_VCPU_DATAGRAM_SIZE, 0); - let msg_size = self.connection + let msg_size = self + .connection .recv(&mut request_buffer) .map_err(io_to_sys_err)?; - let mut request = protobuf::parse_from_bytes::<VcpuRequest>(&request_buffer[..msg_size]) .map_err(proto_to_sys_err)?; @@ -449,9 +441,9 @@ impl PluginVcpu { let mut msr_entries = Vec::with_capacity(entry_indices.len()); for &index in entry_indices { msr_entries.push(kvm_msr_entry { - index, - ..Default::default() - }); + index, + ..Default::default() + }); } match vcpu.get_msrs(&mut msr_entries) { Ok(()) => { @@ -465,8 +457,8 @@ impl PluginVcpu { } else if request.has_set_msrs() { response.mut_set_msrs(); let request_entries = &request.get_set_msrs().entries; - let vec_size_bytes = size_of::<kvm_msrs>() + - (request_entries.len() * size_of::<kvm_msr_entry>()); + let vec_size_bytes = + size_of::<kvm_msrs>() + (request_entries.len() * size_of::<kvm_msr_entry>()); let vec: Vec<u8> = vec![0; vec_size_bytes]; let kvm_msrs: &mut kvm_msrs = unsafe { // Converting the vector's memory to a struct is unsafe. Carefully using the read- @@ -493,7 +485,8 @@ impl PluginVcpu { { let cpuid_entries = cpuid.mut_entries_slice(); for (request_entry, cpuid_entry) in - request_entries.iter().zip(cpuid_entries.iter_mut()) { + request_entries.iter().zip(cpuid_entries.iter_mut()) + { cpuid_entry.function = request_entry.function; if request_entry.has_index { cpuid_entry.index = request_entry.index; |