crosvm: virtio-pmem device

Adds support for virtio-pmem device as an alternative for virtio-blk.

Exposing disk image to guest as virtio-blk device results in both guest
and host independently caching the disk I/O. Using virtio-pmem device
allows to mount disk image as direct access (DAX) in the guest and thus
bypass the guest cache. This will reduce memory foodprint of the VMs.

BUG=None
TEST=cargo test
TEST=Boot patched termina kernel in crosvm; mount virtio-pmem device as
DAX and run xfstests.

Change-Id: I935fc8fc7527f79e5169f07ec7927e4ea4fa6027
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1605517
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Commit-Queue: Jakub StaroĊ„ <jstaron@google.com>
diff --git a/src/main.rs b/src/main.rs
index 530d119..d57174b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -102,6 +102,7 @@
     plugin_mounts: Vec<BindMount>,
     plugin_gid_maps: Vec<GidMap>,
     disks: Vec<DiskOption>,
+    pmem_devices: Vec<DiskOption>,
     host_ip: Option<net::Ipv4Addr>,
     netmask: Option<net::Ipv4Addr>,
     mac_address: Option<net_util::MacAddress>,
@@ -143,6 +144,7 @@
             plugin_mounts: Vec::new(),
             plugin_gid_maps: Vec::new(),
             disks: Vec::new(),
+            pmem_devices: Vec::new(),
             host_ip: None,
             netmask: None,
             mac_address: None,
@@ -440,6 +442,20 @@
                 read_only: !name.starts_with("rw"),
             });
         }
+        "pmem-device" | "rw-pmem-device" => {
+            let disk_path = PathBuf::from(value.unwrap());
+            if !disk_path.exists() {
+                return Err(argument::Error::InvalidValue {
+                    value: value.unwrap().to_owned(),
+                    expected: "this disk path does not exist",
+                });
+            }
+
+            cfg.pmem_devices.push(DiskOption {
+                path: disk_path,
+                read_only: !name.starts_with("rw"),
+            });
+        }
         "host_ip" => {
             if cfg.host_ip.is_some() {
                 return Err(argument::Error::TooManyArguments(
@@ -805,6 +821,8 @@
           Argument::value("qcow", "PATH", "Path to a qcow2 disk image. (Deprecated; use --disk instead.)"),
           Argument::value("rwdisk", "PATH", "Path to a writable disk image."),
           Argument::value("rwqcow", "PATH", "Path to a writable qcow2 disk image. (Deprecated; use --rwdisk instead.)"),
+          Argument::value("rw-pmem-device", "PATH", "Path to a writable disk image."),
+          Argument::value("pmem-device", "PATH", "Path to a disk image."),
           Argument::value("host_ip",
                           "IP",
                           "IP address to assign to host tap interface."),