summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md32
-rw-r--r--README.md12
-rw-r--r--arch/src/lib.rs4
-rwxr-xr-xbin/clippy2
-rwxr-xr-xbin/fmt2
-rwxr-xr-xbin/smoke_test2
-rw-r--r--bit_field/bit_field_derive/bit_field_derive.rs2
-rwxr-xr-xbuild_test.py2
-rw-r--r--devices/src/pci/pci_configuration.rs17
-rw-r--r--devices/src/pci/vfio_pci.rs5
-rw-r--r--devices/src/virtio/balloon.rs2
-rw-r--r--devices/src/virtio/descriptor_utils.rs2
-rw-r--r--devices/src/virtio/input/mod.rs2
-rw-r--r--devices/src/virtio/rng.rs2
-rw-r--r--devices/src/virtio/wl.rs13
-rw-r--r--docs/architecture.md238
-rw-r--r--enumn/src/lib.rs2
-rw-r--r--kernel_cmdline/src/kernel_cmdline.rs5
-rw-r--r--msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs51
-rw-r--r--msg_socket/src/msg_on_socket.rs13
-rw-r--r--p9/wire_format_derive/wire_format_derive.rs2
-rw-r--r--resources/src/lib.rs6
-rw-r--r--seccomp/x86_64/9p_device.policy1
-rw-r--r--seccomp/x86_64/gpu_device.policy1
-rw-r--r--seccomp/x86_64/xhci.policy1
-rw-r--r--src/argument.rs36
-rw-r--r--src/linux.rs2
-rw-r--r--src/main.rs570
-rw-r--r--src/plugin/vcpu.rs5
-rw-r--r--sys_util/poll_token_derive/poll_token_derive.rs2
-rw-r--r--sys_util/src/handle_eintr.rs10
-rw-r--r--sys_util/src/poll.rs10
-rw-r--r--vm_control/src/lib.rs2
33 files changed, 770 insertions, 288 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 63ed15d..8889318 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,6 +1,8 @@
 ## Intro
 
-This article goes into detail about multiple areas of interest to contributors, which includes reviewers, developers, and integrators who each share an interest in guiding crosvm's direction.
+This article goes into detail about multiple areas of interest to contributors,
+which includes reviewers, developers, and integrators who each share an interest
+in guiding crosvm's direction.
 
 ## Guidelines
 
@@ -9,32 +11,48 @@ The following is high level guidance for producing contributions to crosvm.
 - Prefer mechanism to policy.
 - Use existing protocols when they are adequate, such as virtio.
 - Prefer security over code re-use and speed of development.
-- Only the version of Rust in use by the Chrome OS toolchain is supported. This is ordinarily the stable version of Rust, but can be behind a version for a few weeks.
+- Only the version of Rust in use by the Chrome OS toolchain is supported. This
+  is ordinarily the stable version of Rust, but can be behind a version for a
+  few weeks.
 - Avoid distribution specific code.
 
 ## Code Health
 
 ### Scripts
 
-In the `bin/` directory of the crosvm repository, there is the `clippy` script which lints the Rust code and the `fmt` script which will format the crosvm Rust code inplace. When submitting changes, the `bin/smoke_test` script, which checks Rust format and unit tests, will be run by Kokoro, the internal Google run cloud builder, and the results will be posted to the change. Kokoro is only informational, so if Kokoro rejects a change, it can still be submitted.
+In the `bin/` directory of the crosvm repository, there is the `clippy` script
+which lints the Rust code and the `fmt` script which will format the crosvm Rust
+code inplace. When submitting changes, the `bin/smoke_test` script, which checks
+Rust format and unit tests, will be run by Kokoro, the internal Google run cloud
+builder, and the results will be posted to the change. Kokoro is only
+informational, so if Kokoro rejects a change, it can still be submitted.
 
 ###  Submitting Code
 
 See also, [Chrome OS Contributing Guide](https://chromium.googlesource.com/chromiumos/docs/+/master/contributing.md)
 
-When a change is approved, verified, and added to the [commit queue](https://chromium.googlesource.com/chromiumos/docs/+/master/contributing.md#send-your-changes-to-the-commit-queue), crosvm will be built and the unit tests (with some exceptions) will be run by the Chrome OS infrastructure. Only if that passes, will the change be submitted. Failures here will cause the commit queue to reject the change until it is re-added (CQ+2). Unfortunately, it is extremely common for false negatives to cause a change to get rejected, so be ready to re-apply the CQ+2 label if you're the owner of a ready to submit change.
+When a change is approved, verified, and added to the [commit queue](https://chromium.googlesource.com/chromiumos/docs/+/master/contributing.md#send-your-changes-to-the-commit-queue), crosvm will
+be built and the unit tests (with some exceptions) will be run by the Chrome OS
+infrastructure. Only if that passes, will the change be submitted. Failures here
+will cause the commit queue to reject the change until it is re-added
+(CQ+2). Unfortunately, it is extremely common for false negatives to cause a
+change to get rejected, so be ready to re-apply the CQ+2 label if you're the
+owner of a ready to submit change.
 
 ### Style guidelines
 
-To format all code, crosvm defers to rustfmt. In addition, the code adheres to the following rules:
+To format all code, crosvm defers to rustfmt. In addition, the code adheres to
+the following rules:
 
 The `use` statements for each module should be grouped in this order
 
-1.  `std`
+1. `std`
 2. third-party crates
 3. chrome os crates
 4. crosvm crates
 5. `crate`
 
-crosvm uses the [remain](https://github.com/dtolnay/remain) crate to keep error enums sorted, along with the `#[sorted]` attribute to keep their corresponding match statements in the same order.
+crosvm uses the [remain](https://github.com/dtolnay/remain) crate to keep error
+enums sorted, along with the `#[sorted]` attribute to keep their corresponding
+match statements in the same order.
 
diff --git a/README.md b/README.md
index f23e208..9b48c29 100644
--- a/README.md
+++ b/README.md
@@ -142,14 +142,17 @@ the `--disable-sandbox` option.
 
 ### Virtio Wayland
 
-Virtio Wayland support requires special support on the part of the guest and as
-such is unlikely to work out of the box unless you are using a Chrome OS kernel
-along with a `termina` rootfs.
+Virtio Wayland support requires special support on the part of the
+guest and as such is unlikely to work out of the box unless you have
+the virtio_wl driver from the Chromium OS kernel, and are running
+[Sommelier][] inside the VM.
 
 To use it, ensure that the `XDG_RUNTIME_DIR` enviroment variable is set and that
 the path `$XDG_RUNTIME_DIR/wayland-0` points to the socket of the Wayland
 compositor you would like the guest to use.
 
+[Sommelier]: https://chromium.googlesource.com/chromiumos/platform2/+/vm_tools/sommelier
+
 ## Defaults
 
 The following are crosvm's default arguments and how to override them.
@@ -172,7 +175,8 @@ requirements:
 * `virtio-wayland` - The `memfd_create` syscall, introduced in Linux 3.17, and a Wayland compositor.
 * `vsock` - Host Linux kernel with vhost-vsock support, introduced in Linux 4.8.
 * `multiprocess` - Host Linux kernel with seccomp-bpf and Linux namespacing support.
-* `virtio-net` - Host Linux kernel with TUN/TAP support (check for `/dev/net/tun`) and running with `CAP_NET_ADMIN` privileges.
+* `virtio-net` - Host Linux kernel with TUN/TAP support (check for
+  `/dev/net/tun`) and running with `CAP_NET_ADMIN` privileges.
 
 ## Emulated Devices
 
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index 5aa8c67..bab679a 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -124,9 +124,9 @@ pub enum DeviceRegistrationError {
     AllocateDeviceAddrs(PciDeviceError),
     /// Could not allocate an IRQ number.
     AllocateIrq,
-    // Unable to create a pipe.
+    /// Unable to create a pipe.
     CreatePipe(sys_util::Error),
-    // Unable to create serial device from serial parameters
+    /// Unable to create serial device from serial parameters.
     CreateSerialDevice(serial::Error),
     /// Could not clone an event fd.
     EventFdClone(sys_util::Error),
diff --git a/bin/clippy b/bin/clippy
index 03f85c8..3adce5f 100755
--- a/bin/clippy
+++ b/bin/clippy
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 
 # Copyright 2019 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
diff --git a/bin/fmt b/bin/fmt
index 60070dd..b1bf5fe 100755
--- a/bin/fmt
+++ b/bin/fmt
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 
 # Copyright 2019 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
diff --git a/bin/smoke_test b/bin/smoke_test
index 7467c75..74e1cd0 100755
--- a/bin/smoke_test
+++ b/bin/smoke_test
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 # Copyright 2019 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
diff --git a/bit_field/bit_field_derive/bit_field_derive.rs b/bit_field/bit_field_derive/bit_field_derive.rs
index 92fea94..9d9042b 100644
--- a/bit_field/bit_field_derive/bit_field_derive.rs
+++ b/bit_field/bit_field_derive/bit_field_derive.rs
@@ -4,8 +4,6 @@
 
 #![recursion_limit = "256"]
 
-extern crate proc_macro;
-
 use proc_macro2::{Span, TokenStream};
 use quote::{quote, quote_spanned};
 use syn::parse::{Error, Result};
diff --git a/build_test.py b/build_test.py
index f0a78c4..4745138 100755
--- a/build_test.py
+++ b/build_test.py
@@ -222,7 +222,7 @@ def get_parser():
 def main(argv):
   opts = get_parser().parse_args(argv)
   build_test_cases = (
-      #(sysroot path, target triple, debug/release, should test?)
+      #(sysroot path, target triple, debug/release, should test?, should clean?)
       (opts.arm_sysroot, ARM_TRIPLE, "debug", False, opts.clean),
       (opts.arm_sysroot, ARM_TRIPLE, "release", False, opts.clean),
       (opts.aarch64_sysroot, AARCH64_TRIPLE, "debug", False, opts.clean),
diff --git a/devices/src/pci/pci_configuration.rs b/devices/src/pci/pci_configuration.rs
index ebfa2a6..ff2da1a 100644
--- a/devices/src/pci/pci_configuration.rs
+++ b/devices/src/pci/pci_configuration.rs
@@ -25,7 +25,7 @@ const INTERRUPT_LINE_PIN_REG: usize = 15;
 
 /// Represents the types of PCI headers allowed in the configuration registers.
 #[allow(dead_code)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum PciHeaderType {
     Device,
     Bridge,
@@ -33,7 +33,7 @@ pub enum PciHeaderType {
 
 /// Classes of PCI nodes.
 #[allow(dead_code)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum PciClassCode {
     TooOld,
     MassStorage,
@@ -70,7 +70,7 @@ pub trait PciSubclass {
 
 /// Subclasses of the MultimediaController class.
 #[allow(dead_code)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum PciMultimediaSubclass {
     VideoController = 0x00,
     AudioController = 0x01,
@@ -87,7 +87,7 @@ impl PciSubclass for PciMultimediaSubclass {
 
 /// Subclasses of the BridgeDevice
 #[allow(dead_code)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum PciBridgeSubclass {
     HostBridge = 0x00,
     IsaBridge = 0x01,
@@ -111,7 +111,7 @@ impl PciSubclass for PciBridgeSubclass {
 
 /// Subclass of the SerialBus
 #[allow(dead_code)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum PciSerialBusSubClass {
     Firewire = 0x00,
     ACCESSbus = 0x01,
@@ -135,6 +135,7 @@ pub trait PciProgrammingInterface {
 }
 
 /// Types of PCI capabilities.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub enum PciCapabilityID {
     ListID = 0,
     PowerManagement = 0x01,
@@ -177,20 +178,20 @@ pub struct PciConfiguration {
 }
 
 /// See pci_regs.h in kernel
-#[derive(Copy, Clone, Debug, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum PciBarRegionType {
     Memory32BitRegion = 0,
     IORegion = 0x01,
     Memory64BitRegion = 0x04,
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum PciBarPrefetchable {
     NotPrefetchable = 0,
     Prefetchable = 0x08,
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub struct PciBarConfiguration {
     addr: u64,
     size: u64,
diff --git a/devices/src/pci/vfio_pci.rs b/devices/src/pci/vfio_pci.rs
index fa27dec..5f6998e 100644
--- a/devices/src/pci/vfio_pci.rs
+++ b/devices/src/pci/vfio_pci.rs
@@ -832,10 +832,7 @@ impl PciDevice for VfioPciDevice {
             low = self.config.read_config_dword(offset);
 
             let low_flag = low & 0xf;
-            let is_64bit = match low_flag & 0x4 {
-                0x4 => true,
-                _ => false,
-            };
+            let is_64bit = (low_flag & 0x4) == 0x4;
             if (low_flag & 0x1 == 0 || i == VFIO_PCI_ROM_REGION_INDEX) && low != 0 {
                 let mut upper: u32 = 0xffffffff;
                 if is_64bit {
diff --git a/devices/src/virtio/balloon.rs b/devices/src/virtio/balloon.rs
index 30417fa..b549258 100644
--- a/devices/src/virtio/balloon.rs
+++ b/devices/src/virtio/balloon.rs
@@ -28,7 +28,7 @@ pub enum BalloonError {
     /// Failure wriitng the config notification event.
     WritingConfigEvent(sys_util::Error),
 }
-pub type Result<T> = std::result::Result<T, BalloonError>;
+type Result<T> = std::result::Result<T, BalloonError>;
 
 impl Display for BalloonError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
diff --git a/devices/src/virtio/descriptor_utils.rs b/devices/src/virtio/descriptor_utils.rs
index c878a45..902e3c3 100644
--- a/devices/src/virtio/descriptor_utils.rs
+++ b/devices/src/virtio/descriptor_utils.rs
@@ -46,7 +46,7 @@ impl Display for Error {
     }
 }
 
-pub type Result<T> = result::Result<T, Error>;
+type Result<T> = result::Result<T, Error>;
 
 impl std::error::Error for Error {}
 
diff --git a/devices/src/virtio/input/mod.rs b/devices/src/virtio/input/mod.rs
index c789dd8..452a003 100644
--- a/devices/src/virtio/input/mod.rs
+++ b/devices/src/virtio/input/mod.rs
@@ -61,7 +61,7 @@ pub enum InputError {
     WriteQueue(std::io::Error),
 }
 
-pub type Result<T> = std::result::Result<T, InputError>;
+type Result<T> = std::result::Result<T, InputError>;
 
 impl Display for InputError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
diff --git a/devices/src/virtio/rng.rs b/devices/src/virtio/rng.rs
index 3d7801f..3897ee3 100644
--- a/devices/src/virtio/rng.rs
+++ b/devices/src/virtio/rng.rs
@@ -20,7 +20,7 @@ pub enum RngError {
     /// Can't access /dev/urandom
     AccessingRandomDev(io::Error),
 }
-pub type Result<T> = std::result::Result<T, RngError>;
+type Result<T> = std::result::Result<T, RngError>;
 
 impl Display for RngError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs
index 3a5ecee..6fefd51 100644
--- a/devices/src/virtio/wl.rs
+++ b/devices/src/virtio/wl.rs
@@ -28,7 +28,6 @@
 //! the virtio queue, and routing messages in and out of `WlState`. Possible events include the kill
 //! event, available descriptors on the `in` or `out` queue, and incoming data on any vfd's socket.
 
-use std::cell::RefCell;
 use std::collections::btree_map::Entry;
 use std::collections::{BTreeMap as Map, BTreeSet as Set, VecDeque};
 use std::convert::From;
@@ -327,21 +326,19 @@ impl From<VolatileMemoryError> for WlError {
 
 #[derive(Clone)]
 struct VmRequester {
-    inner: Rc<RefCell<VmMemoryControlRequestSocket>>,
+    vm_socket: Rc<VmMemoryControlRequestSocket>,
 }
 
 impl VmRequester {
     fn new(vm_socket: VmMemoryControlRequestSocket) -> VmRequester {
         VmRequester {
-            inner: Rc::new(RefCell::new(vm_socket)),
+            vm_socket: Rc::new(vm_socket),
         }
     }
 
     fn request(&self, request: VmMemoryRequest) -> WlResult<VmMemoryResponse> {
-        let mut inner = self.inner.borrow_mut();
-        let vm_socket = &mut *inner;
-        vm_socket.send(&request).map_err(WlError::VmControl)?;
-        vm_socket.recv().map_err(WlError::VmControl)
+        self.vm_socket.send(&request).map_err(WlError::VmControl)?;
+        self.vm_socket.recv().map_err(WlError::VmControl)
     }
 }
 
@@ -1252,7 +1249,7 @@ impl WlState {
                 self.new_context(ctrl.id.into(), name)
             }
             op_type => {
-                warn!("unexpected command {}", op_type);
+                warn!("unexpected command {:#x}", op_type);
                 Ok(WlResp::InvalidCommand)
             }
         }
diff --git a/docs/architecture.md b/docs/architecture.md
index ab830b4..381f0e1 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -1,4 +1,4 @@
-# Architectural Overview (last edit: January 21, 2020)
+# Architectural Overview
 
 The principle characteristics of crosvm are:
 
@@ -7,76 +7,240 @@ The principle characteristics of crosvm are:
 - Takes full advantage of KVM and low-level Linux syscalls, and so only runs on Linux
 - Written in Rust for security and safety
 
-A typical session of crosvm starts in `main.rs` where command line parsing is done to build up a `Config` structure. The `Config` is used by `run_config` in `linux.rs` to setup and execute a VM. Broken down into rough steps:
+A typical session of crosvm starts in `main.rs` where command line
+parsing is done to build up a `Config` structure. The `Config` is used by
+`run_config` in `linux.rs` to setup and execute a VM. Broken down into
+rough steps:
 
 1. Load the linux kernel from an ELF file.
-1. Create a handful of control sockets used by the virtual devices.
-1. Invoke the architecture specific VM builder `Arch::build_vm` (located in `x86_64/src/lib.rs` or `aarch64/src/lib.rs`).
-1. `Arch::build_vm` will itself invoke the provided `create_devices` function from `linux.rs`
-1. `create_devices` creates every PCI device, including the virtio devices, that were configured in `Config`, along with matching [minijail] configs for each.
-1. `Arch::generate_pci_root`, using a list of every PCI device with optional `Minijail`, will finally jail the PCI devices and construct a `PciRoot` that communicates with them.
-1. Once the VM has been built, it's contained within a `RunnableLinuxVm` object that is used by the VCPUs and control loop to service requests until shutdown.
+2. Create a handful of control sockets used by the virtual devices.
+3. Invoke the architecture specific VM builder `Arch::build_vm` (located
+   in `x86_64/src/lib.rs` or `aarch64/src/lib.rs`).
+4. `Arch::build_vm` will itself invoke the provided `create_devices`
+   function from `linux.rs`
+5. `create_devices` creates every PCI device, including the virtio
+   devices, that were configured in `Config`, along with matching
+   [minijail] configs for each.
+6. `Arch::generate_pci_root`, using a list of every PCI device with
+   optional `Minijail`, will finally jail the PCI devices and construct
+   a `PciRoot` that communicates with them.
+7. Once the VM has been built, it's contained within a `RunnableLinuxVm`
+   object that is used by the VCPUs and control loop to service
+   requests until shutdown.
 
 ## Forking
 
-During the device creation routine, each device will be created and then wrapped in a `ProxyDevice` which will internally `fork` (but not `exec`) and [minijail] the device, while dropping it for the main process. The only interaction that the device is capable of having with the main process is via the proxied trait methods of `BusDevice`, shared memory mappings such as the guest memory, and file descriptors that were specifically whitelisted by that device's security policy. This can lead to some surprising behavior to be aware of such as why some file descriptors which were once valid are now invalid.
+During the device creation routine, each device will be created and
+then wrapped in a `ProxyDevice` which will internally `fork` (but not
+`exec`) and [minijail] the device, while dropping it for the main
+process. The only interaction that the device is capable of having
+with the main process is via the proxied trait methods of `BusDevice`,
+shared memory mappings such as the guest memory, and file descriptors
+that were specifically whitelisted by that device's security
+policy. This can lead to some surprising behavior to be aware of such
+as why some file descriptors which were once valid are now invalid.
 
 ## Sandboxing Policy
 
-Every sandbox is made with [minijail], invoked using the `io_jail` crate in crosvm, and starts with `create_base_minijail` in `linux.rs` which set some very restrictive settings. Linux namespaces and seccomp filters are used extensively. Each seccomp policy can be found under `seccomp/{arch}/{device}.policy` and should start by `@include`-ing the `common_device.policy`. With the exception of architecture specific devices (such as `Pl030` on ARM or `I8042` on x86_64), every device will need a different policy for each supported architecture.
+Every sandbox is made with [minijail], invoked using the `io_jail` crate
+in crosvm, and starts with `create_base_minijail` in `linux.rs` which set
+some very restrictive settings. Linux namespaces and seccomp filters
+are used extensively. Each seccomp policy can be found under
+`seccomp/{arch}/{device}.policy` and should start by `@include`-ing the
+`common_device.policy`. With the exception of architecture specific
+devices (such as `Pl030` on ARM or `I8042` on x86_64), every device will
+need a different policy for each supported architecture.
 
 ## The VM Control Sockets
 
-For the operations that devices need to perform on the global VM state, such as mapping into guest memory address space, there are the vm control sockets. There are a few kinds, split by the type of request and response that the socket will process. This also proves basic security privilege separation in case a device becomes compromised by a malicious guest. For example, a rogue device that is able to allocate MSI routes would not be able to use the same socket to (de)register guest memory. During the device initialization stage, each device that requires some aspect of VM control will have a constructor that requires the corresponding control socket. The control socket will get preserved when the device is sandboxed and and the other side of the socket will be waited on in the main process's control loop.
-
-The socket exposed by crosvm with the `--socket` command line argument is another form of the VM control socket. Because the protocol of the control socket is internal and unstable, the only supported way of using that resulting named unix domain socket is via crosvm command line subcommands such as `crosvm stop`.
+For the operations that devices need to perform on the global VM
+state, such as mapping into guest memory address space, there are the
+vm control sockets. There are a few kinds, split by the type of
+request and response that the socket will process. This also proves
+basic security privilege separation in case a device becomes
+compromised by a malicious guest. For example, a rogue device that is
+able to allocate MSI routes would not be able to use the same socket
+to (de)register guest memory. During the device initialization stage,
+each device that requires some aspect of VM control will have a
+constructor that requires the corresponding control socket. The
+control socket will get preserved when the device is sandboxed and and
+the other side of the socket will be waited on in the main process's
+control loop.
+
+The socket exposed by crosvm with the `--socket` command line argument
+is another form of the VM control socket. Because the protocol of the
+control socket is internal and unstable, the only supported way of
+using that resulting named unix domain socket is via crosvm command
+line subcommands such as `crosvm stop`.
 
 ## GuestMemory
 
-`GuestMemory` and its friends `VolatileMemory`, `VolatileSlice`, `MemoryMapping`, and `SharedMemory`, are common types used throughout crosvm to interact with guest memory. Know which one to use in what place using some guidelines
-
-- `GuestMemory` is for sending around references to all of the guest memory. It can be cloned freely, but the underlying guest memory is always the same. Internally, it's implemented using `MemoryMapping` and `SharedMemory`. Note that `GuestMemory` is mapped into the host address space, but it is non-contiguous. Device memory, such as mapped DMA-Bufs, are not present in `GuestMemory`.
-- `SharedMemory` wraps a `memfd` and can be mapped using `MemoryMapping` to access its data. `SharedMemory` can't be cloned.
-- `VolatileMemory` is a trait that exposes generic access to non-contiguous memory. `GuestMemory` implements this trait. Use this trait for functions that operate on a memory space but don't necessarily need it to be guest memory.
-- `VolatileSlice` is analogous to a Rust slice, but unlike those, a `VolatileSlice` has data that changes asynchronously by all those that reference it. Exclusive mutability and data synchronization are not available when it comes to a `VolatileSlice`. This type is useful for functions that operate on contiguous shared memory, such as a single entry from a scatter gather table, or for safe wrappers around functions which operate on pointers, such as a `read` or `write` syscall.
-- `MemoryMapping` is a safe wrapper around anonymous and file mappings. Access via Rust references is forbidden, but indirect reading and writing is available via `VolatileSlice` and several convenience functions. This type is most useful for mapping memory unrelated to `GuestMemory`.
+`GuestMemory` and its friends `VolatileMemory`, `VolatileSlice`,
+`MemoryMapping`, and `SharedMemory`, are common types used throughout
+crosvm to interact with guest memory. Know which one to use in what
+place using some guidelines
+
+- `GuestMemory` is for sending around references to all of the guest
+  memory. It can be cloned freely, but the underlying guest memory is
+  always the same. Internally, it's implemented using `MemoryMapping`
+  and `SharedMemory`. Note that `GuestMemory` is mapped into the host
+  address space, but it is non-contiguous. Device memory, such as
+  mapped DMA-Bufs, are not present in `GuestMemory`.
+- `SharedMemory` wraps a `memfd` and can be mapped using `MemoryMapping` to
+  access its data. `SharedMemory` can't be cloned.
+- `VolatileMemory` is a trait that exposes generic access to
+  non-contiguous memory. `GuestMemory` implements this trait. Use this
+  trait for functions that operate on a memory space but don't
+  necessarily need it to be guest memory.
+- `VolatileSlice` is analogous to a Rust slice, but unlike those, a
+  `VolatileSlice` has data that changes asynchronously by all those that
+  reference it. Exclusive mutability and data synchronization are not
+  available when it comes to a `VolatileSlice`. This type is useful for
+  functions that operate on contiguous shared memory, such as a single
+  entry from a scatter gather table, or for safe wrappers around
+  functions which operate on pointers, such as a `read` or `write`
+  syscall.
+- `MemoryMapping` is a safe wrapper around anonymous and file
+  mappings. Access via Rust references is forbidden, but indirect
+  reading and writing is available via `VolatileSlice` and several
+  convenience functions. This type is most useful for mapping memory
+  unrelated to `GuestMemory`.
 
 ### Device Model
 
 ### `Bus`/`BusDevice`
 
-The root of the crosvm device model is the `Bus` structure and its friend the `BusDevice` trait. The `Bus` structure is a virtual computer bus used to emulate the memory-mapped I/O bus and also I/O ports for x86 VMs. On a read or write to an address on a VM's bus, the corresponding `Bus` object is queried for a `BusDevice` that occupies that address. `Bus` will then forward the read/write to the `BusDevice`. Because of this behavior, only one `BusDevice` may exist at any given address. However, a `BusDevice` may be placed at more than one address range. Depending on how a `BusDevice` was inserted into the `Bus`, the forwarded read/write will be relative to 0 or to the start of the address range that the `BusDevice` occupies (which would be ambiguous if the `BusDevice` occupied more than one range).
-
-Only the base address of a multi-byte read/write is used to search for a device, so a device implementation should be aware that the last address of a single read/write may be outside its address range. For example, if a `BusDevice` was inserted at base address 0x1000 with a length of 0x40, a 4-byte read by a VCPU at 0x39 would be forwarded to that `BusDevice`.
-
-Each `BusDevice` is reference counted and wrapped in a mutex, so implementations of `BusDevice` need not worry about synchronizing their access across multiple VCPUs and threads. Each VCPU will get a complete copy of the `Bus`, so there is no contention for querying the `Bus` about an address. Once the `BusDevice` is found, the `Bus` will acquire an exclusive lock to the device and forward the VCPU's read/write. The implementation of the `BusDevice` will block execution of the VCPU that invoked it, as well as any other VCPU attempting access, until it returns from its method.
-
-Most devices in crosvm do not implement `BusDevice` directly, but some are examples are `i8042` and `Serial`. With the exception of PCI devices, all devices are inserted by architecture specific code (which may call into the architecture-neutral `arch` crate). A `BusDevice` can be proxied to a sandboxed process using `ProxyDevice`, which will create the second process using a fork, with no exec.
+The root of the crosvm device model is the `Bus` structure and its
+friend the `BusDevice` trait. The `Bus` structure is a virtual computer
+bus used to emulate the memory-mapped I/O bus and also I/O ports for
+x86 VMs. On a read or write to an address on a VM's bus, the
+corresponding `Bus` object is queried for a `BusDevice` that occupies that
+address. `Bus` will then forward the read/write to the
+`BusDevice`. Because of this behavior, only one `BusDevice` may exist at
+any given address. However, a `BusDevice` may be placed at more than one
+address range. Depending on how a `BusDevice` was inserted into the `Bus`,
+the forwarded read/write will be relative to 0 or to the start of the
+address range that the `BusDevice` occupies (which would be ambiguous if
+the `BusDevice` occupied more than one range).
+
+Only the base address of a multi-byte read/write is used to search for
+a device, so a device implementation should be aware that the last
+address of a single read/write may be outside its address range. For
+example, if a `BusDevice` was inserted at base address 0x1000 with a
+length of 0x40, a 4-byte read by a VCPU at 0x39 would be forwarded to
+that `BusDevice`.
+
+Each `BusDevice` is reference counted and wrapped in a mutex, so
+implementations of `BusDevice` need not worry about synchronizing their
+access across multiple VCPUs and threads. Each VCPU will get a
+complete copy of the `Bus`, so there is no contention for querying the
+`Bus` about an address. Once the `BusDevice` is found, the `Bus` will
+acquire an exclusive lock to the device and forward the VCPU's
+read/write. The implementation of the `BusDevice` will block execution
+of the VCPU that invoked it, as well as any other VCPU attempting
+access, until it returns from its method.
+
+Most devices in crosvm do not implement `BusDevice` directly, but some
+are examples are `i8042` and `Serial`. With the exception of PCI devices,
+all devices are inserted by architecture specific code (which may call
+into the architecture-neutral `arch` crate). A `BusDevice` can be proxied
+to a sandboxed process using `ProxyDevice`, which will create the second
+process using a fork, with no exec.
 
 ### `PciConfigIo`/`PciConfigMmio`
 
-In order to use the more complex PCI bus, there are a couple adapters that implement `BusDevice` and call into a `PciRoot` with higher level calls to `config_space_read`/`config_space_write`. The `PciConfigMmio` is a `BusDevice` for insertion into the MMIO `Bus` for ARM devices. For x86_64, `PciConfigIo` is inserted into the I/O port `Bus`. There is only one implementation of `PciRoot` that is used by either of the `PciConfig*` structures. Because these devices are very simple, they have very little code or state. They aren't sandboxed and are run as part of the main process.
+In order to use the more complex PCI bus, there are a couple adapters
+that implement `BusDevice` and call into a `PciRoot` with higher level
+calls to `config_space_read`/`config_space_write`. The `PciConfigMmio` is a
+`BusDevice` for insertion into the MMIO `Bus` for ARM devices. For x86_64,
+`PciConfigIo` is inserted into the I/O port `Bus`. There is only one
+implementation of `PciRoot` that is used by either of the `PciConfig*`
+structures. Because these devices are very simple, they have very
+little code or state. They aren't sandboxed and are run as part of the
+main process.
 
 ### `PciRoot`/`PciDevice`/`VirtioPciDevice`
 
-The `PciRoot`, analogous to `BusDevice` for `Bus`s, contains all the `PciDevice` trait objects. Because of a shortcut (or hack), the `ProxyDevice` only supports jailing `BusDevice` traits. Therefore, `PciRoot` only contains `BusDevice`s, even though they also implement `PciDevice`. In fact, every `PciDevice` also implements `BusDevice` because of a blanket implementation (`impl<T: PciDevice> BusDevice for T { … }`). There are a few PCI related methods in `BusDevice` to allow the `PciRoot` to still communicate with the underlying `PciDevice` (yes, this abstraction is very leaky). Most devices will not implement `PciDevice` directly, instead using the `VirtioPciDevice` implementation for virtio devices, but the xHCI (USB) controller is an example that implements `PciDevice` directly. The `VirtioPciDevice` is an implementation of `PciDevice` that wraps a `VirtioDevice`, which is how the virtio specified PCI transport is adapted to a transport agnostic `VirtioDevice` implementation.
+The `PciRoot`, analogous to `BusDevice` for `Bus`s, contains all the
+`PciDevice` trait objects. Because of a shortcut (or hack), the
+`ProxyDevice` only supports jailing `BusDevice` traits. Therefore, `PciRoot`
+only contains `BusDevice`s, even though they also implement
+`PciDevice`. In fact, every `PciDevice` also implements `BusDevice` because
+of a blanket implementation (`impl<T: PciDevice> BusDevice for T { …
+}`). There are a few PCI related methods in `BusDevice` to allow the
+`PciRoot` to still communicate with the underlying `PciDevice` (yes, this
+abstraction is very leaky). Most devices will not implement `PciDevice`
+directly, instead using the `VirtioPciDevice` implementation for virtio
+devices, but the xHCI (USB) controller is an example that implements
+`PciDevice` directly. The `VirtioPciDevice` is an implementation of
+`PciDevice` that wraps a `VirtioDevice`, which is how the virtio specified
+PCI transport is adapted to a transport agnostic `VirtioDevice`
+implementation.
 
 ### `VirtioDevice`
 
-The `VirtioDevice` is the most widely implemented trait among the device traits. Each of the different virtio devices (block, rng, net, etc.) implement this trait directly and they follow a similar pattern. Most of the trait methods are easily filled in with basic information about the specific device, but `activate` will be the heart of the implementation. It's called by the virtio transport after the guest's driver has indicated the device has been configured and is ready to run. The virtio device implementation will receive the run time related resources (`GuestMemory`, `Interrupt`, etc.) for processing virtio queues and associated interrupts via the arguments to `activate`, but `activate` can't spend its time actually processing the queues. A VCPU will be blocked as long as `activate` is running. Every device uses `activate` to launch a worker thread that takes ownership of run time resources to do the actual processing. There is some subtlety in dealing with virtio queues, so the smart thing to do is copy a simpler device and adapt it, such as the rng device (`rng.rs`).
+The `VirtioDevice` is the most widely implemented trait among the device
+traits. Each of the different virtio devices (block, rng, net, etc.)
+implement this trait directly and they follow a similar pattern. Most
+of the trait methods are easily filled in with basic information about
+the specific device, but `activate` will be the heart of the
+implementation. It's called by the virtio transport after the guest's
+driver has indicated the device has been configured and is ready to
+run. The virtio device implementation will receive the run time
+related resources (`GuestMemory`, `Interrupt`, etc.) for processing virtio
+queues and associated interrupts via the arguments to `activate`, but
+`activate` can't spend its time actually processing the queues. A VCPU
+will be blocked as long as `activate` is running. Every device uses
+`activate` to launch a worker thread that takes ownership of run time
+resources to do the actual processing. There is some subtlety in
+dealing with virtio queues, so the smart thing to do is copy a simpler
+device and adapt it, such as the rng device (`rng.rs`).
 
 ## Communication Framework
 
-Because of the multi-process nature of crosvm, communication is done over several IPC primitives. The common ones are shared memory pages, unix sockets, anonymous pipes, and various other file descriptor variants (DMA-buf, eventfd, etc.). Standard methods (`read`/`write`) of using these primitives may be used, but crosvm has developed some helpers which should be used where applicable.
+Because of the multi-process nature of crosvm, communication is done
+over several IPC primitives. The common ones are shared memory pages,
+unix sockets, anonymous pipes, and various other file descriptor
+variants (DMA-buf, eventfd, etc.). Standard methods (`read`/`write`) of
+using these primitives may be used, but crosvm has developed some
+helpers which should be used where applicable.
 
 ### `PollContext`/`EpollContext`
 
-Most threads in crosvm will have a wait loop using a `PollContext`, which is a wrapper around Linux's `epoll` primitive for selecting over file descriptors. `EpollContext` is very similar but has slightly fewer features, but is usable by multiple threads at once. In either case, each FD is added to the context along with an associated token, whose type is the type parameter of `PollContext`. This token must be convertible to and from a `u64`, which is a limitation imposed by how `epoll` works. There is a custom derive `#[derive(PollToken)]` which can be applied to an `enum` declaration that makes it easy to use your own enum in a `PollContext`.
-
-Note that the limitations of `PollContext` are the same as the limitations of `epoll`. The same FD can not be inserted more than once, and the FD will be automatically removed if the process runs out of references to that FD. A `dup`/`fork` call will increment that reference count, so closing the original FD will not actually remove it from the `PollContext`. It is possible to receive tokens from `PollContext` for an FD that was closed because of a race condition in which an event was registered in the background before the `close` happened. Best practice is to remove an FD before closing it so that events associated with it can be reliably eliminated.
+Most threads in crosvm will have a wait loop using a `PollContext`,
+which is a wrapper around Linux's `epoll` primitive for selecting over
+file descriptors. `EpollContext` is very similar but has slightly fewer
+features, but is usable by multiple threads at once. In either case,
+each FD is added to the context along with an associated token, whose
+type is the type parameter of `PollContext`. This token must be
+convertible to and from a `u64`, which is a limitation imposed by how
+`epoll` works. There is a custom derive `#[derive(PollToken)]` which can
+be applied to an `enum` declaration that makes it easy to use your own
+enum in a `PollContext`.
+
+Note that the limitations of `PollContext` are the same as the
+limitations of `epoll`. The same FD can not be inserted more than once,
+and the FD will be automatically removed if the process runs out of
+references to that FD. A `dup`/`fork` call will increment that reference
+count, so closing the original FD will not actually remove it from the
+`PollContext`. It is possible to receive tokens from `PollContext` for an
+FD that was closed because of a race condition in which an event was
+registered in the background before the `close` happened. Best practice
+is to remove an FD before closing it so that events associated with it
+can be reliably eliminated.
 
 ### MsgSocket
 
-Using raw sockets and pipes to communicate is very inconvenient for rich data types. To help make this easier and less error prone, crosvm has the `msg_socket` crate. Included is a trait for messages encodable on a Unix socket (`MsgOnSocket`), a set of traits for sending and receiving (`MsgSender`/`MsgReceiver`), and implementations of those traits over `UnixSeqpacket` (`MsgSocket`/`Sender`/`Receiver`). To make implementing `MsgOnSocket` very easy, a custom derive for that trait can be utilized with `#[derive(MsgOnSocket)]`. The custom derive will work for enums and structs with nested data, primitive types, and anything that implements `AsRawFd`. However, structures with no fixed upper limit in size, such as `Vec` or `BTreeMap`, are not supported.
-
-[minijail]: https://android.googlesource.com/platform/external/minijail
\ No newline at end of file
+Using raw sockets and pipes to communicate is very inconvenient for
+rich data types. To help make this easier and less error prone, crosvm
+has the `msg_socket` crate. Included is a trait for messages encodable
+on a Unix socket (`MsgOnSocket`), a set of traits for sending and
+receiving (`MsgSender`/`MsgReceiver`), and implementations of those traits
+over `UnixSeqpacket` (`MsgSocket`/`Sender`/`Receiver`). To make implementing
+`MsgOnSocket` very easy, a custom derive for that trait can be utilized
+with `#[derive(MsgOnSocket)]`. The custom derive will work for enums and
+structs with nested data, primitive types, and anything that
+implements `AsRawFd`. However, structures with no fixed upper limit in
+size, such as `Vec` or `BTreeMap`, are not supported.
+
+[minijail]: https://android.googlesource.com/platform/external/minijail
diff --git a/enumn/src/lib.rs b/enumn/src/lib.rs
index 1441b4b..7035352 100644
--- a/enumn/src/lib.rs
+++ b/enumn/src/lib.rs
@@ -103,8 +103,6 @@
 
 #![recursion_limit = "128"]
 
-extern crate proc_macro;
-
 #[cfg(test)]
 mod tests;
 
diff --git a/kernel_cmdline/src/kernel_cmdline.rs b/kernel_cmdline/src/kernel_cmdline.rs
index d2777c7..c836e12 100644
--- a/kernel_cmdline/src/kernel_cmdline.rs
+++ b/kernel_cmdline/src/kernel_cmdline.rs
@@ -39,10 +39,7 @@ impl Display for Error {
 pub type Result<T> = result::Result<T, Error>;
 
 fn valid_char(c: char) -> bool {
-    match c {
-        ' '..='~' => true,
-        _ => false,
-    }
+    matches!(c, ' '..='~')
 }
 
 fn valid_str(s: &str) -> Result<()> {
diff --git a/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs b/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs
index d287ac0..bfca732 100644
--- a/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs
+++ b/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #![recursion_limit = "256"]
-extern crate proc_macro;
 
 use std::vec::Vec;
 
@@ -18,14 +17,14 @@ use syn::{
 #[proc_macro_derive(MsgOnSocket, attributes(msg_on_socket))]
 pub fn msg_on_socket_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
     let input = parse_macro_input!(input as DeriveInput);
-    let impl_for_input = socket_msg_impl(input);
+    let impl_for_input = msg_socket_impl(input);
     impl_for_input.into()
 }
 
-fn socket_msg_impl(input: DeriveInput) -> TokenStream {
+fn msg_socket_impl(input: DeriveInput) -> TokenStream {
     if !input.generics.params.is_empty() {
         return quote! {
-            compile_error!("derive(SocketMsg) does not support generic parameters");
+            compile_error!("derive(MsgSocket) does not support generic parameters");
         };
     }
     match input.data {
@@ -38,16 +37,13 @@ fn socket_msg_impl(input: DeriveInput) -> TokenStream {
         }
         Data::Enum(de) => impl_for_enum(input.ident, de),
         _ => quote! {
-            compile_error!("derive(SocketMsg) only support struct and enum");
+            compile_error!("derive(MsgSocket) only support struct and enum");
         },
     }
 }
 
 fn is_named_struct(ds: &DataStruct) -> bool {
-    match &ds.fields {
-        Fields::Named(_f) => true,
-        _ => false,
-    }
+    matches!(&ds.fields, Fields::Named(_))
 }
 
 /************************** Named Struct Impls ********************************************/
@@ -612,9 +608,36 @@ fn write_to_buffer_and_move_offset(name: &Ident) -> TokenStream {
 
 #[cfg(test)]
 mod tests {
-    use crate::socket_msg_impl;
+    use super::define_uses_fd_for_enum;
+    use crate::msg_socket_impl;
     use quote::quote;
-    use syn::{parse_quote, DeriveInput};
+    use syn::{parse_quote, Data, DeriveInput};
+
+    #[test]
+    fn simple_enum_uses_fd() {
+        let input: DeriveInput = parse_quote! {
+            enum Simple {
+                A,
+                B,
+            }
+        };
+
+        let data = match input.data {
+            Data::Enum(data) => data,
+            _ => unreachable!(),
+        };
+
+        let expected = quote! {
+            fn uses_fd() -> bool {
+                false
+            }
+        };
+
+        assert_eq!(
+            define_uses_fd_for_enum(&data).to_string(),
+            expected.to_string()
+        );
+    }
 
     #[test]
     fn end_to_end_struct_test() {
@@ -689,7 +712,7 @@ mod tests {
 
         };
 
-        assert_eq!(socket_msg_impl(input).to_string(), expected.to_string());
+        assert_eq!(msg_socket_impl(input).to_string(), expected.to_string());
     }
 
     #[test]
@@ -754,7 +777,7 @@ mod tests {
             }
         };
 
-        assert_eq!(socket_msg_impl(input).to_string(), expected.to_string());
+        assert_eq!(msg_socket_impl(input).to_string(), expected.to_string());
     }
 
     #[test]
@@ -863,7 +886,7 @@ mod tests {
             }
         };
 
-        assert_eq!(socket_msg_impl(input).to_string(), expected.to_string());
+        assert_eq!(msg_socket_impl(input).to_string(), expected.to_string());
     }
 
     #[test]
diff --git a/msg_socket/src/msg_on_socket.rs b/msg_socket/src/msg_on_socket.rs
index 3e87102..2101192 100644
--- a/msg_socket/src/msg_on_socket.rs
+++ b/msg_socket/src/msg_on_socket.rs
@@ -75,6 +75,8 @@ impl Display for MsgError {
     }
 }
 
+impl std::error::Error for MsgError {}
+
 /// A msg that could be serialized to and deserialize from array in little endian.
 ///
 /// For structs, we always have fixed size of bytes and fixed count of fds.
@@ -122,10 +124,11 @@ pub trait MsgOnSocket: Sized {
     }
     /// Returns (self, fd read count).
     /// This function is safe only when:
-    ///     0. fds contains valid fds, received from socket, serialized by Self::write_to_buffer.
-    ///     1. For enum, fds contains correct fd layout of the particular variant.
-    ///     2. write_to_buffer is implemented correctly(put valid fds into the buffer, has no padding,
-    ///        return correct count).
+    ///
+    /// 0. fds contains valid fds, received from socket, serialized by Self::write_to_buffer.
+    /// 1. For enum, fds contains correct fd layout of the particular variant.
+    /// 2. write_to_buffer is implemented correctly (put valid fds into the buffer, has no padding,
+    ///    return correct count).
     unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)>;
 
     /// Serialize self to buffers.
@@ -402,7 +405,7 @@ where
 macro_rules! array_impls {
     ($N:expr, $t: ident $($ts:ident)*)
     => {
-        impl<T: MsgOnSocket + Clone> MsgOnSocket for [T; $N] {
+        impl<T: MsgOnSocket> MsgOnSocket for [T; $N] {
             fn uses_fd() -> bool {
                 T::uses_fd()
             }
diff --git a/p9/wire_format_derive/wire_format_derive.rs b/p9/wire_format_derive/wire_format_derive.rs
index 6d369ae..2d1c364 100644
--- a/p9/wire_format_derive/wire_format_derive.rs
+++ b/p9/wire_format_derive/wire_format_derive.rs
@@ -8,8 +8,6 @@
 
 #![recursion_limit = "256"]
 
-extern crate proc_macro;
-
 use proc_macro2::{Span, TokenStream};
 use quote::{quote, quote_spanned};
 use syn::spanned::Spanned;
diff --git a/resources/src/lib.rs b/resources/src/lib.rs
index 95e4b98..204227b 100644
--- a/resources/src/lib.rs
+++ b/resources/src/lib.rs
@@ -4,12 +4,6 @@
 
 //! Manages system resources that can be allocated to VMs and their devices.
 
-#[cfg(feature = "wl-dmabuf")]
-extern crate gpu_buffer;
-extern crate libc;
-extern crate msg_socket;
-extern crate sys_util;
-
 use msg_socket::MsgOnSocket;
 use std::fmt::Display;
 
diff --git a/seccomp/x86_64/9p_device.policy b/seccomp/x86_64/9p_device.policy
index 114ea11..271d244 100644
--- a/seccomp/x86_64/9p_device.policy
+++ b/seccomp/x86_64/9p_device.policy
@@ -18,6 +18,7 @@ unlink: 1
 rename: 1
 pread64: 1
 getdents: 1
+getdents64: 1
 mkdir: 1
 rmdir: 1
 fsync: 1
diff --git a/seccomp/x86_64/gpu_device.policy b/seccomp/x86_64/gpu_device.policy
index 331fc49..99d2a8d 100644
--- a/seccomp/x86_64/gpu_device.policy
+++ b/seccomp/x86_64/gpu_device.policy
@@ -52,6 +52,7 @@ fstat: 1
 # Used to set of size new memfd.
 ftruncate: 1
 getdents: 1
+getdents64: 1
 geteuid: 1
 getrandom: 1
 getuid: 1
diff --git a/seccomp/x86_64/xhci.policy b/seccomp/x86_64/xhci.policy
index 4b4fc3d..3448ce2 100644
--- a/seccomp/x86_64/xhci.policy
+++ b/seccomp/x86_64/xhci.policy
@@ -38,4 +38,5 @@ ioctl: arg1 == 0xc0185500 || arg1 == 0x41045508 || arg1 == 0x8004550f || arg1 ==
 fstat: 1
 getrandom: 1
 getdents: 1
+getdents64: 1
 lseek: 1
diff --git a/src/argument.rs b/src/argument.rs
index 02e97f0..26950a9 100644
--- a/src/argument.rs
+++ b/src/argument.rs
@@ -376,28 +376,34 @@ pub fn print_help(program_name: &str, required_arg: &str, args: &[Argument]) {
         return;
     }
     println!("Argument{}:", if args.len() > 1 { "s" } else { "" });
+
     for arg in args {
-        match arg.short {
-            Some(s) => print!(" -{}, ", s),
-            None => print!("     "),
+        println!();
+
+        if let Some(s) = arg.short {
+            print!(" -{}", s);
+            if !arg.long.is_empty() {
+                print!(",");
+            }
         }
-        if arg.long.is_empty() {
-            print!("  ");
-        } else {
-            print!("--");
+
+        print!(" ");
+
+        if !arg.long.is_empty() {
+            print!("--{}", arg.long);
         }
-        print!("{:<12}", arg.long);
+
         if let Some(v) = arg.value {
-            if arg.long.is_empty() {
-                print!(" ");
-            } else {
+            if !arg.long.is_empty() {
                 print!("=");
             }
-            print!("{:<10}", v);
-        } else {
-            print!("{:<11}", "");
+            print!("{}", v);
+        }
+
+        println!();
+        for line in arg.help.lines() {
+            println!("    {}", line);
         }
-        println!("{}", arg.help);
     }
 }
 
diff --git a/src/linux.rs b/src/linux.rs
index 687aae4..ec2067c 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -1658,7 +1658,7 @@ fn file_fields_to_i64<P: AsRef<Path>>(path: P) -> io::Result<Vec<i64>> {
         .collect()
 }
 
-// Reads the contents of a file and converts them into a u64, and if there
+// Reads the contents of a file and converts them into a i64, and if there
 // are multiple fields it only returns the first one.
 fn file_to_i64<P: AsRef<Path>>(path: P) -> io::Result<i64> {
     file_fields_to_i64(path)?
diff --git a/src/main.rs b/src/main.rs
index e8a6e6c..ed7bb30 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -38,10 +38,7 @@ use vm_control::{
 };
 
 fn executable_is_plugin(executable: &Option<Executable>) -> bool {
-    match executable {
-        Some(Executable::Plugin(_)) => true,
-        _ => false,
-    }
+    matches!(executable, Some(Executable::Plugin(_)))
 }
 
 // Wait for all children to exit. Return true if they have all exited, false
@@ -1296,135 +1293,427 @@ fn validate_arguments(cfg: &mut Config) -> std::result::Result<(), argument::Err
 }
 
 fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> {
-    let arguments =
-        &[Argument::positional("KERNEL", "bzImage of kernel to run"),
-          Argument::value("android-fstab", "PATH", "Path to Android fstab"),
-          Argument::short_value('i', "initrd", "PATH", "Initial ramdisk to load."),
-          Argument::short_value('p',
-                                "params",
-                                "PARAMS",
-                                "Extra kernel or plugin command line arguments. Can be given more than once."),
-          Argument::short_value('c', "cpus", "N", "Number of VCPUs. (default: 1)"),
-          Argument::value("cpu-affinity", "CPUSET", "Comma-separated list of CPUs or CPU ranges to run VCPUs on. (e.g. 0,1-3,5) (default: no mask)"),
-          Argument::short_value('m',
-                                "mem",
-                                "N",
-                                "Amount of guest memory in MiB. (default: 256)"),
-          Argument::short_value('r',
-                                "root",
-                                "PATH[,key=value[,key=value[,...]]",
-                                "Path to a root disk image followed by optional comma-separated options.
-                              Like `--disk` but adds appropriate kernel command line option.
-                              See --disk for valid options."),
-          Argument::value("rwroot", "PATH[,key=value[,key=value[,...]]", "Path to a writable root disk image followed by optional comma-separated options.
-                              See --disk for valid options."),
-          Argument::short_value('d', "disk", "PATH[,key=value[,key=value[,...]]", "Path to a disk image followed by optional comma-separated options.
-                              Valid keys:
-                              sparse=BOOL - Indicates whether the disk should support the discard operation (default: true)
-                              block_size=BYTES - Set the reported block size of the disk (default: 512)"),
-          Argument::value("rwdisk", "PATH[,key=value[,key=value[,...]]", "Path to a writable disk image followed by optional comma-separated options.
-                              See --disk for valid options."),
-          Argument::value("rw-pmem-device", "PATH", "Path to a writable disk image."),
-          Argument::value("pmem-device", "PATH", "Path to a disk image."),
-          Argument::value("pstore", "path=PATH,size=SIZE", "Path to pstore buffer backend file follewed by size."),
-          Argument::value("host_ip",
-                          "IP",
-                          "IP address to assign to host tap interface."),
-          Argument::value("netmask", "NETMASK", "Netmask for VM subnet."),
-          Argument::value("mac", "MAC", "MAC address for VM."),
-          Argument::value("net-vq-pairs", "N", "virtio net virtual queue paris. (default: 1)"),
-          Argument::value("ac97",
-                          "[backend=BACKEND,capture=true,capture_effect=EFFECT]",
-                          "Comma separated key=value pairs for setting up Ac97 devices. Can be given more than once .
-                          Possible key values:
-                          backend=(null, cras) - Where to route the audio device. If not provided, backend will default to null.
-                          `null` for /dev/null, and  cras for CRAS server.
-                          capture - Enable audio capture
-                          capture_effects - | separated effects to be enabled for recording. The only supported effect value now is EchoCancellation or aec."),
-          Argument::value("serial",
-                          "type=TYPE,[hardware=HW,num=NUM,path=PATH,input=PATH,console,earlycon,stdin]",
-                          "Comma separated key=value pairs for setting up serial devices. Can be given more than once.
-                          Possible key values:
-                          type=(stdout,syslog,sink,file) - Where to route the serial device
-                          hardware=(serial,virtio-console) - Which type of serial hardware to emulate. Defaults to 8250 UART (serial).
-                          num=(1,2,3,4) - Serial Device Number. If not provided, num will default to 1.
-                          path=PATH - The path to the file to write to when type=file
-                          input=PATH - The path to the file to read from when not stdin
-                          console - Use this serial device as the guest console. Can only be given once. Will default to first serial port if not provided.
-                          earlycon - Use this serial device as the early console. Can only be given once.
-                          stdin - Direct standard input to this serial device. Can only be given once. Will default to first serial port if not provided.
-                          "),
-          Argument::value("syslog-tag", "TAG", "When logging to syslog, use the provided tag."),
-          Argument::value("x-display", "DISPLAY", "X11 display name to use."),
-          Argument::flag("display-window-keyboard", "Capture keyboard input from the display window."),
-          Argument::flag("display-window-mouse", "Capture keyboard input from the display window."),
-          Argument::value("wayland-sock", "PATH[,name=NAME]", "Path to the Wayland socket to use. The unnamed one is used for displaying virtual screens. Named ones are only for IPC."),
-          #[cfg(feature = "wl-dmabuf")]
-          Argument::flag("wayland-dmabuf", "Enable support for DMABufs in Wayland device."),
-          Argument::short_value('s',
-                                "socket",
-                                "PATH",
-                                "Path to put the control socket. If PATH is a directory, a name will be generated."),
-          Argument::flag("disable-sandbox", "Run all devices in one, non-sandboxed process."),
-          Argument::value("cid", "CID", "Context ID for virtual sockets."),
-          Argument::value("shared-dir", "PATH:TAG[:type=TYPE:writeback=BOOL:timeout=SECONDS:uidmap=UIDMAP:gidmap=GIDMAP:cache=CACHE]",
-                          "Colon-separated options for configuring a directory to be shared with the VM.
-The first field is the directory to be shared and the second field is the tag that the VM can use to identify the device.
-The remaining fields are key=value pairs that may appear in any order.  Valid keys are:
-type=(p9, fs) - Indicates whether the directory should be shared via virtio-9p or virtio-fs (default: p9).
-uidmap=UIDMAP - The uid map to use for the device's jail in the format \"inner outer count[,inner outer count]\" (default: 0 <current euid> 1).
-gidmap=GIDMAP - The gid map to use for the device's jail in the format \"inner outer count[,inner outer count]\" (default: 0 <current egid> 1).
-cache=(never, auto, always) - Indicates whether the VM can cache the contents of the shared directory (default: auto).  When set to \"auto\" and the type is \"fs\", the VM will use close-to-open consistency for file contents.
-timeout=SECONDS - How long the VM should consider file attributes and directory entries to be valid (default: 5).  If the VM has exclusive access to the directory, then this should be a large value.  If the directory can be modified by other processes, then this should be 0.
-writeback=BOOL - Indicates whether the VM can use writeback caching (default: false).  This is only safe to do when the VM has exclusive access to the files in a directory.  Additionally, the server should have read permission for all files as the VM may issue read requests even for files that are opened write-only.
+    let arguments = &[
+        Argument::positional("KERNEL", "bzImage of kernel to run."),
+        Argument::value("android-fstab", "PATH", "Path to Android fstab."),
+        Argument::short_value('i', "initrd", "PATH", "Initial ramdisk to load."),
+        Argument::short_value(
+            'p',
+            "params",
+            "PARAMS",
+            "\
+Extra kernel or plugin command line arguments.  Can be given more than once.
+",
+        ),
+        Argument::short_value('c', "cpus", "N", "Number of VCPUs.  (default: 1)"),
+        Argument::value(
+            "cpu-affinity",
+            "CPUSET",
+            "\
+Comma-separated list of CPUs or CPU ranges to run VCPUs on (e.g. 0,1-3,5).
+(default: no mask)
+",
+        ),
+        Argument::short_value(
+            'm',
+            "mem",
+            "N",
+            "Amount of guest memory in MiB.  (default: 256)",
+        ),
+        Argument::short_value(
+            'r',
+            "root",
+            "PATH[,key=value[,key=value[,...]]",
+            "\
+Path to a root disk image followed by optional comma-separated options.
+Like --disk but adds appropriate kernel command line option.  See --disk for
+valid options.
+",
+        ),
+        Argument::value(
+            "rwroot",
+            "PATH[,key=value[,key=value[,...]]",
+            "\
+Path to a writable root disk image followed by optional comma-separated
+options.  See --disk for valid options.
+",
+        ),
+        Argument::short_value(
+            'd',
+            "disk",
+            "PATH[,key=value[,key=value[,...]]",
+            "\
+Path to a disk image followed by optional comma-separated options.
+
+Valid keys:
+
+  sparse=BOOL
+    Indicates whether the disk should support the discard operation.
+    (default: true)
+
+  block_size=BYTES
+    Set the reported block size of the disk.
+    (default: 512)
+",
+        ),
+        Argument::value(
+            "rwdisk",
+            "PATH[,key=value[,key=value[,...]]",
+            "\
+Path to a writable disk image followed by optional comma-separated options.
+See --disk for valid options.
+",
+        ),
+        Argument::value("rw-pmem-device", "PATH", "Path to a writable disk image."),
+        Argument::value("pmem-device", "PATH", "Path to a disk image."),
+        Argument::value(
+            "pstore",
+            "path=PATH,size=SIZE",
+            "\
+Path to pstore buffer backend file follewed by size.
+",
+        ),
+        Argument::value(
+            "host_ip",
+            "IP",
+            "IP address to assign to host tap interface.",
+        ),
+        Argument::value("netmask", "NETMASK", "Netmask for VM subnet."),
+        Argument::value("mac", "MAC", "MAC address for VM."),
+        Argument::value(
+            "ac97",
+            "[backend=BACKEND,capture=true,capture_effect=EFFECT]",
+            r#"Comma separated key=value pairs for setting up Ac97 devices. Can be
+given more than once.
+
+Possible key values:
+
+  backend=(null,cras)
+    Where to route the audio device.  "null" for /dev/null, and "cras"
+    for CRAS server.
+    (default: null)
+
+  capture
+    Enable audio capture.
+
+  capture_effects
+    Separated effects to be enabled for recording.  The only supported
+    effect value now is EchoCancellation or aec.
+"#,
+        ),
+        Argument::value(
+            "serial",
+            "type=TYPE,[hardware=HW,num=NUM,path=PATH,input=PATH,console,earlycon,stdin]",
+            "\
+Comma separated key=value pairs for setting up serial devices. Can be given
+more than once.
+
+Possible key values:
+
+  type=(stdout,syslog,sink,file)
+    Where to route the serial device.
+
+  hardware=(serial,virtio-console)
+    Which type of serial hardware to emulate.  Defaults to 8250 UART
+    (serial).
+
+  num=(1,2,3,4)
+    Serial Device Number.  If not provided, num will default to 1.
+
+  path=PATH
+    The path to the file to write to when type=file.
+
+  input=PATH
+    The path to the file to read from when not stdin.
+
+  console
+    Use this serial device as the guest console.  Can only be given once.
+    Will default to first serial port if not provided.
+
+  earlycon
+    Use this serial device as the early console.  Can only be given once.
+
+  stdin
+    Direct standard input to this serial device.  Can only be given once.
+    Will default to first serial port if not provided.
+",
+        ),
+        Argument::value(
+            "syslog-tag",
+            "TAG",
+            "When logging to syslog, use the provided tag.",
+        ),
+        Argument::value("x-display", "DISPLAY", "X11 display name to use."),
+        Argument::flag(
+            "display-window-keyboard",
+            "\
+Capture keyboard input from the display window.
+",
+        ),
+        Argument::flag(
+            "display-window-mouse",
+            "Capture keyboard input from the display window.",
+        ),
+        Argument::value(
+            "net-vq-pairs",
+            "N",
+            "\
+Number of virtio-net virtual queue pairs.
+(default: 1)
+",
+        ),
+        Argument::value(
+            "wayland-sock",
+            "PATH[,name=NAME]",
+            "\
+Path to the Wayland socket to use.  The unnamed one is used for displaying
+virtual screens.  Named ones are only for IPC.
+",
+        ),
+        #[cfg(feature = "wl-dmabuf")]
+        Argument::flag(
+            "wayland-dmabuf",
+            "Enable support for DMABufs in Wayland device.",
+        ),
+        Argument::short_value(
+            's',
+            "socket",
+            "PATH",
+            "\
+Path to put the control socket.  If PATH is a directory, a name will be
+generated.
+",
+        ),
+        Argument::flag(
+            "disable-sandbox",
+            "Run all devices in one, non-sandboxed process.",
+        ),
+        Argument::value("cid", "CID", "Context ID for virtual sockets."),
+        Argument::value(
+            "shared-dir",
+            "\
+PATH:TAG[:type=TYPE:writeback=BOOL:timeout=SECONDS:uidmap=UIDMAP:gidmap=GIDMAP:cache=CACHE]",
+            r#"Colon-separated options for configuring a directory to be shared with the
+VM.
+
+The first field is the directory to be shared and the second field is the
+tag that the VM can use to identify the device.  The remaining fields are
+key=value pairs that may appear in any order.  Valid keys are:
+
+  type=(p9, fs)
+    Indicates whether the directory should be shared via virtio-9p or
+    virtio-fs.
+    (default: p9)
+
+  uidmap=UIDMAP
+    The uid map to use for the device's jail in the format
+    "inner outer count[,inner outer count]".
+    (default: 0 <current euid> 1).
+
+  gidmap=GIDMAP
+    The gid map to use for the device's jail in the format
+    "inner outer count[,inner outer count]".
+    (default: 0 <current egid> 1)
+
+  cache=(never, auto, always)
+    Indicates whether the VM can cache the contents of the shared directory.
+    When set to "auto" and the type is "fs", the VM will use
+    close-to-open consistency for file contents.
+    (default: auto)
+
+  timeout=SECONDS
+    How long the VM should consider file attributes and directory entries to
+    be valid.  If the VM has exclusive access to the directory, then this
+    should be a large value.  If the directory can be modified by other
+    processes, then this should be 0.
+    (default: 5)
+
+  writeback=BOOL
+    Indicates whether the VM can use writeback caching.  This is only safe
+    to do when the VM has exclusive access to the files in a directory.
+    Additionally, the server should have read permission for all files as
+    the VM may issue read requests even for files that are opened
+    write-only.
+    (default: false)
+"#,
+        ),
+        Argument::value(
+            "seccomp-policy-dir",
+            "PATH",
+            "Path to seccomp .policy files.",
+        ),
+        Argument::flag(
+            "seccomp-log-failures",
+            "\
+Instead of seccomp filter failures being fatal, they will be logged instead.",
+        ),
+        #[cfg(feature = "plugin")]
+        Argument::value(
+            "plugin",
+            "PATH",
+            "Absolute path to plugin process to run under crosvm.",
+        ),
+        #[cfg(feature = "plugin")]
+        Argument::value(
+            "plugin-root",
+            "PATH",
+            "\
+Absolute path to a directory that will become root filesystem for the plugin
+process.
+",
+        ),
+        #[cfg(feature = "plugin")]
+        Argument::value(
+            "plugin-mount",
+            "PATH:PATH:BOOL",
+            "\
+Path to be mounted into the plugin's root filesystem.  Can be given more
+than once.
+",
+        ),
+        #[cfg(feature = "plugin")]
+        Argument::value(
+            "plugin-mount-file",
+            "PATH",
+            "\
+Path to the file listing paths be mounted into the plugin's root filesystem.
+Can be given more than once.
+",
+        ),
+        #[cfg(feature = "plugin")]
+        Argument::value(
+            "plugin-gid-map",
+            "GID:GID:INT",
+            "\
+Supplemental GIDs that should be mapped in plugin jail.  Can be given more
+than once.
+",
+        ),
+        #[cfg(feature = "plugin")]
+        Argument::value(
+            "plugin-gid-map-file",
+            "PATH",
+            "\
+Path to the file listing supplemental GIDs that should be mapped in plugin
+jail.  Can be given more than once.
+",
+        ),
+        Argument::flag("vhost-net", "Use vhost for networking."),
+        Argument::value(
+            "tap-fd",
+            "fd",
+            "\
+File descriptor for configured tap device.  A different virtual network card
+will be added each time this argument is given.
+",
+        ),
+        #[cfg(feature = "gpu")]
+        Argument::flag_or_value(
+            "gpu",
+            "[width=INT,height=INT]",
+            "\
+(EXPERIMENTAL)
+Comma separated key=value pairs for setting up a virtio-gpu device.
+
+Possible key values:
+  backend=(2d|3d|gfxstream)
+    Which backend to use for virtio-gpu (determining rendering protocol).
+
+  width=INT
+    The width of the virtual display connected to the virtio-gpu.
+
+  height=INT
+    The height of the virtual display connected to the virtio-gpu.
+
+  egl[=true|=false]
+    If the virtio-gpu backend should use a EGL context for rendering.
+
+  glx[=true|=false]
+    If the virtio-gpu backend should use a GLX context for rendering.
+
+  surfaceless[=true|=false]
+    If the virtio-gpu backend should use a surfaceless context for rendering.
+",
+        ),
+        #[cfg(feature = "tpm")]
+        Argument::flag(
+            "software-tpm",
+            "\
+Enable a software emulated trusted platform module device.
+",
+        ),
+        Argument::value(
+            "evdev",
+            "PATH",
+            "\
+Path to an event device node. The device will be grabbed (unusable from the
+host) and made available to the guest with the same configuration it shows
+on the host.
+",
+        ),
+        Argument::value(
+            "single-touch",
+            "PATH:WIDTH:HEIGHT",
+            "\
+Path to a socket from where to read single touch input events (such as those
+from a touchscreen) and write status updates to, optionally followed by
+width and height.
+(default: 800x1280)
+",
+        ),
+        Argument::value(
+            "trackpad",
+            "PATH:WIDTH:HEIGHT",
+            "\
+Path to a socket from where to read trackpad input events and write status
+updates to, optionally followed by screen width and height.
+(default: 800x1280)
+",
+        ),
+        Argument::value(
+            "mouse",
+            "PATH",
+            "\
+Path to a socket from where to read mouse input events and write status
+updates to.
+",
+        ),
+        Argument::value(
+            "keyboard",
+            "PATH",
+            "\
+Path to a socket from where to read keyboard input events and write status
+updates to.
+",
+        ),
+        #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+        Argument::flag(
+            "split-irqchip",
+            "\
+(EXPERIMENTAL)
+Enable split-irqchip support.
+",
+        ),
+        Argument::value("bios", "PATH", "Path to BIOS/firmware ROM"),
+        Argument::value(
+            "vfio",
+            "PATH",
+            "Path to sysfs of pass through or mdev device",
+        ),
+        #[cfg(feature = "video-decoder")]
+        Argument::flag("video-decoder", "\
+(EXPERIMENTAL)
+Enable virtio-video decoder device.
+",
+        ),
+        #[cfg(feature = "video-encoder")]
+        Argument::flag("video-encoder", "\
+(EXPERIMENTAL)
+Enable virtio-video encoder device.
 "),
-          Argument::value("seccomp-policy-dir", "PATH", "Path to seccomp .policy files."),
-          Argument::flag("seccomp-log-failures", "Instead of seccomp filter failures being fatal, they will be logged instead."),
-          #[cfg(feature = "plugin")]
-          Argument::value("plugin", "PATH", "Absolute path to plugin process to run under crosvm."),
-          #[cfg(feature = "plugin")]
-          Argument::value("plugin-root", "PATH", "Absolute path to a directory that will become root filesystem for the plugin process."),
-          #[cfg(feature = "plugin")]
-          Argument::value("plugin-mount", "PATH:PATH:BOOL", "Path to be mounted into the plugin's root filesystem.  Can be given more than once."),
-          #[cfg(feature = "plugin")]
-          Argument::value("plugin-mount-file", "PATH", "Path to the file listing paths be mounted into the plugin's root filesystem.  Can be given more than once."),
-          #[cfg(feature = "plugin")]
-          Argument::value("plugin-gid-map", "GID:GID:INT", "Supplemental GIDs that should be mapped in plugin jail.  Can be given more than once."),
-          #[cfg(feature = "plugin")]
-          Argument::value("plugin-gid-map-file", "PATH", "Path to the file listing supplemental GIDs that should be mapped in plugin jail.  Can be given more than once."),
-          Argument::flag("vhost-net", "Use vhost for networking."),
-          Argument::value("tap-fd",
-                          "fd",
-                          "File descriptor for configured tap device. A different virtual network card will be added each time this argument is given."),
-          #[cfg(feature = "gpu")]
-          Argument::flag_or_value("gpu",
-                                  "[width=INT,height=INT]",
-                                  "(EXPERIMENTAL) Comma separated key=value pairs for setting up a virtio-gpu device
-                                  Possible key values:
-                                  backend=(2d|3d|gfxstream) - Which backend to use for virtio-gpu (determining rendering protocol)
-                                  width=INT - The width of the virtual display connected to the virtio-gpu.
-                                  height=INT - The height of the virtual display connected to the virtio-gpu.
-                                  egl[=true|=false] - If the virtio-gpu backend should use a EGL context for rendering.
-                                  glx[=true|=false] - If the virtio-gpu backend should use a GLX context for rendering.
-                                  surfaceless[=true|=false] - If the virtio-gpu backend should use a surfaceless context for rendering.
-                                  "),
-          #[cfg(feature = "tpm")]
-          Argument::flag("software-tpm", "enable a software emulated trusted platform module device"),
-          Argument::value("evdev", "PATH", "Path to an event device node. The device will be grabbed (unusable from the host) and made available to the guest with the same configuration it shows on the host"),
-          Argument::value("single-touch", "PATH:WIDTH:HEIGHT", "Path to a socket from where to read single touch input events (such as those from a touchscreen) and write status updates to, optionally followed by width and height (defaults to 800x1280)."),
-          Argument::value("trackpad", "PATH:WIDTH:HEIGHT", "Path to a socket from where to read trackpad input events and write status updates to, optionally followed by screen width and height (defaults to 800x1280)."),
-          Argument::value("mouse", "PATH", "Path to a socket from where to read mouse input events and write status updates to."),
-          Argument::value("keyboard", "PATH", "Path to a socket from where to read keyboard input events and write status updates to."),
-          #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-          Argument::flag("split-irqchip", "(EXPERIMENTAL) enable split-irqchip support"),
-          Argument::value("bios", "PATH", "Path to BIOS/firmware ROM"),
-          Argument::value("vfio", "PATH", "Path to sysfs of pass through or mdev device"),
-          #[cfg(feature = "video-decoder")]
-          Argument::flag("video-decoder", "(EXPERIMENTAL) enable virtio-video decoder device"),
-          #[cfg(feature = "video-encoder")]
-          Argument::flag("video-encoder", "(EXPERIMENTAL) enable virtio-video encoder device"),
-          Argument::value("acpi-table", "PATH", "Path to user provided ACPI table"),
-          Argument::short_flag('h', "help", "Print help message.")];
+        Argument::value("acpi-table", "PATH", "Path to user provided ACPI table."),
+        Argument::short_flag('h', "help", "Print help message."),
+    ];
 
     let mut cfg = Config::default();
     let match_res = set_arguments(args, &arguments[..], |name, value| {
@@ -1542,7 +1831,7 @@ fn resume_vms(args: std::env::Args) -> std::result::Result<(), ()> {
 fn balloon_vms(mut args: std::env::Args) -> std::result::Result<(), ()> {
     if args.len() < 2 {
         print_help("crosvm balloon", "SIZE VM_SOCKET...", &[]);
-        println!("Set the ballon size of the crosvm instance to `SIZE` bytes.");
+        println!("Set the balloon size of the crosvm instance to `SIZE` bytes.");
         return Err(());
     }
     let num_bytes = match args.next().unwrap().parse::<u64>() {
@@ -1871,12 +2160,15 @@ fn modify_usb(mut args: std::env::Args) -> std::result::Result<(), ()> {
 fn print_usage() {
     print_help("crosvm", "[stop|run]", &[]);
     println!("Commands:");
-    println!("    stop - Stops crosvm instances via their control sockets.");
-    println!("    run  - Start a new crosvm instance.");
-    println!("    create_qcow2  - Create a new qcow2 disk image file.");
-    println!("    disk - Manage attached virtual disk devices.");
-    println!("    usb - Manage attached virtual USB devices.");
-    println!("    version - Show package version.");
+    println!("    stop          Stops crosvm instances via their control sockets.");
+    println!("    suspend       Suspends crosvm instances via their control sockets.");
+    println!("    resume        Resumes crosvm instances via their control sockets.");
+    println!("    run           Start a new crosvm instance.");
+    println!("    balloon       Set balloon size of crosvm instances via their control sockets.");
+    println!("    create_qcow2  Create a new qcow2 disk image file.");
+    println!("    disk          Manage attached virtual disk devices.");
+    println!("    usb           Manage attached virtual USB devices.");
+    println!("    version       Show package version.");
 }
 
 fn pkg_version() -> std::result::Result<(), ()> {
diff --git a/src/plugin/vcpu.rs b/src/plugin/vcpu.rs
index 06e1861..4bd3ea8 100644
--- a/src/plugin/vcpu.rs
+++ b/src/plugin/vcpu.rs
@@ -322,10 +322,7 @@ enum VcpuRunData<'a> {
 
 impl<'a> VcpuRunData<'a> {
     fn is_write(&self) -> bool {
-        match self {
-            VcpuRunData::Write(_) => true,
-            _ => false,
-        }
+        matches!(self, VcpuRunData::Write(_))
     }
 
     fn as_slice(&self) -> &[u8] {
diff --git a/sys_util/poll_token_derive/poll_token_derive.rs b/sys_util/poll_token_derive/poll_token_derive.rs
index 7b7baac..6270cb0 100644
--- a/sys_util/poll_token_derive/poll_token_derive.rs
+++ b/sys_util/poll_token_derive/poll_token_derive.rs
@@ -4,8 +4,6 @@
 
 #![recursion_limit = "128"]
 
-extern crate proc_macro;
-
 use proc_macro2::{Ident, TokenStream};
 use quote::quote;
 use syn::{parse_macro_input, Data, DeriveInput, Field, Fields, Index, Member, Variant};
diff --git a/sys_util/src/handle_eintr.rs b/sys_util/src/handle_eintr.rs
index d8cc0b3..8e38c09 100644
--- a/sys_util/src/handle_eintr.rs
+++ b/sys_util/src/handle_eintr.rs
@@ -17,19 +17,13 @@ pub trait InterruptibleResult {
 
 impl<T> InterruptibleResult for crate::Result<T> {
     fn is_interrupted(&self) -> bool {
-        match self {
-            Err(e) if e.errno() == EINTR => true,
-            _ => false,
-        }
+        matches!(self, Err(e) if e.errno() == EINTR)
     }
 }
 
 impl<T> InterruptibleResult for io::Result<T> {
     fn is_interrupted(&self) -> bool {
-        match self {
-            Err(e) if e.kind() == io::ErrorKind::Interrupted => true,
-            _ => false,
-        }
+        matches!(self, Err(e) if e.kind() == io::ErrorKind::Interrupted)
     }
 }
 
diff --git a/sys_util/src/poll.rs b/sys_util/src/poll.rs
index 1b92c96..58c5efa 100644
--- a/sys_util/src/poll.rs
+++ b/sys_util/src/poll.rs
@@ -42,7 +42,7 @@ impl Default for EpollEvents {
 
 /// Trait for a token that can be associated with an `fd` in a `PollContext`.
 ///
-/// Simple enums that have no or primitive variant data data can use the `#[derive(PollToken)]`
+/// Simple enums that have no or primitive variant data can use the `#[derive(PollToken)]`
 /// custom derive to implement this trait. See
 /// [poll_token_derive::poll_token](../poll_token_derive/fn.poll_token.html) for details.
 pub trait PollToken {
@@ -281,10 +281,10 @@ impl WatchingEvents {
     }
 }
 
-/// EpollContext wraps linux epoll. It provides similar interface to PollContext.
-/// It is thread safe while PollContext is not. It requires user to pass in a reference of
-/// EpollEvents while PollContext does not. Always use PollContext if you don't need to access the
-/// same epoll from different threads.
+/// `EpollContext` wraps linux epoll.  It provides a similar interface to `PollContext`.
+/// It is thread safe while `PollContext` is not.  It requires the user to pass in a reference of
+/// `EpollEvent`s while `PollContext` does not.  Always use `PollContext` if you don't need to
+/// access the same epoll from different threads.
 pub struct EpollContext<T> {
     epoll_ctx: File,
     // Needed to satisfy usage of T
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs
index 5336f3b..c63fbfe 100644
--- a/vm_control/src/lib.rs
+++ b/vm_control/src/lib.rs
@@ -23,7 +23,7 @@ use msg_socket::{MsgError, MsgOnSocket, MsgReceiver, MsgResult, MsgSender, MsgSo
 use resources::{Alloc, GpuMemoryDesc, MmioType, SystemAllocator};
 use sys_util::{error, Error as SysError, EventFd, GuestAddress, MemoryMapping, MmapError, Result};
 
-/// A file descriptor either borrowed or owned by this.
+/// A data structure that either owns or borrows a file descriptor.
 #[derive(Debug)]
 pub enum MaybeOwnedFd {
     /// Owned by this enum variant, and will be destructed automatically if not moved out.