Commit graph

35 commits

Author SHA1 Message Date
Zach Reizner
55a9e504be 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>
2018-10-09 21:14:05 -07:00
Daniel Verkamp
36d4ec520e sys_util: use fallocate64 for large file support
Rust's libc crate exports the default off_t definition on 32-bit
platforms, rather than the _FILE_OFFSET_BITS=64 variant, so we need to
explicitly use the 64-bit API to get support for files larger than 2 GB.

The Rust libc crate does not currently export fallocate64, so declare it
ourselves for now.  This declaration can be removed once fallocate64 is
added upstream.

BUG=chromium:850998
TEST=Run fstrim on Kevin (32-bit ARM) and verify it works

Change-Id: Id0aa7a6e7e6080f4c53e10c3ad1d105f15ee2549
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1238850
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-09-26 10:33:14 -07:00
Dylan Reid
059a188d0d Arch: Big refactor and add an empty PCI bus
When setting up IO, accept an optional PciRoot device to put on the IO
bus.

For aarch64, it's currently ignored. For x86_64, it will be added at
0xcf8.

 break up mmio device creation and registration

Moving forward registration will be handled by the architecture specific
code. However, creation will be handled by the common code. To make that
easier split up the two steps so a list of devices is created, then each
is registered later.

Start moving to a model where the configuration generates a set of
components that are passed to the architecture. The architecture will
crate a VM from the components.

Break up the big run_config function and move architecture specific
parts to the various architectures.

This doesn't refactor the function calls each architecture makes, but
moves the setup flow in to the arch impls so that they can diverge in
the future.

Change-Id: I5b10d092896606796dc0c9afc5e34a1b288b867b
Signed-off-by: Dylan Reid <dgreid@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1099860
Commit-Ready: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: Daniel Verkamp <dverkamp@chromium.org>
2018-09-10 17:17:35 -07:00
Daniel Verkamp
a3d11edaa6 sys_util: add WriteZeroes trait and impl for File
BUG=chromium:850998
TEST=cargo test -p sys_util write_zeroes

Change-Id: I90f670fffed055f39e141b26819d56948b1bf30d
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1187017
Reviewed-by: Stephen Barber <smbarber@chromium.org>
2018-09-05 01:25:49 -07:00
Daniel Verkamp
0e8f6fa96e sys_util: add safe wrapper for fallocate()
BUG=chromium:850998
TEST=None

Change-Id: I1b6864f7d508cf7f24248a8cc9783af2d8b00891
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1187016
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
2018-09-05 01:25:49 -07:00
Chirantan Ekbote
448516e3f9 balloon: Implement device policy
Implement a policy for the balloon device so that it starts taking
memory away from the VM when the system is under low memory conditions.
There are a few pieces here:

* Change the madvise call in MemoryMapping::dont_need_range to use
  MADV_REMOVE instead of MADV_DONTNEED.  The latter does nothing when
  the memory mapping is shared across multiple processes while the
  former immediately gives the pages in the specified range back to the
  kernel.  Subsequent accesses to memory in that range returns zero
  pages.
* Change the protocol between the balloon device process and the main
  crosvm process.  Previously, the device process expected the main
  process to send it increments in the amount of memory consumed by the
  balloon device.  Now, it instead just expects the absolute value of
  the memory that should be consumed.  To properly implement the policy
  the main process needs to keep track of the total memory consumed by
  the balloon device so this makes it easier to handle all the policy in
  one place.
* Add a policy for dealing with low memory situations.  When the VM
  starts up, we determine the maximum amount of memory that the balloon
  device should consume:

    * If the VM has more than 1.5GB of memory, the balloon device max is
      the size of the VM memory minus 1GB.
    * Otherwise, if the VM has at least 500MB, the balloon device max is
      50% of the size of the VM memory.
    * Otherwise, the max is 0.

  The increment used to change the size of the balloon is defined as
  1/16 of the max memory that the balloon device will consume.  When the
  crosvm main process detects that the system is low on memory, it
  immediately increases the balloon size by the increment (unless it has
  already reached the max).  It then starts 2 timers: one to check for
  low memory conditions again in 1 seconds (+ jitter) and another to
  check if the system is no longer low on memory in 1 minute (+ jitter)
  with a subsequent interval of 30 seconds (+ jitter).

  Under persistent low memory conditions the balloon device will consume
  the maximum memory after 16 seconds.  Once there is enough available
  memory the balloon size will shrink back down to 0 after at most 9
  minutes.

BUG=chromium:866193
TEST=manual
Start 2 VMs and write out a large file (size > system RAM) in each.
Observe /sys/kernel/mm/chromeos-low_mem/available and see that the
available memory steadily decreases until it goes under the low memory
margin at which point the available memory bounces back up as crosvm
frees up pages.
CQ-DEPEND=CL:1152214

Change-Id: I2046729683aa081c9d7ed039d902ad11737c1d52
Signed-off-by: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1149155
Reviewed-by: Sonny Rao <sonnyrao@chromium.org>
2018-07-27 15:29:07 -07:00
Zach Reizner
298b41cf82 sys_util: move round_to_page_size to sys_util
This function will be used elsewhere in gpu_display.

TEST=None
BUG=None

Change-Id: I58b820511ea5a55a53ad640fdfe7c96d2dbdc73b
Reviewed-on: https://chromium-review.googlesource.com/1105481
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>
2018-06-21 16:31:43 -07:00
Zach Reizner
3afab33a8d sys_util: add type to get open file flags
The only instance of libstd getting file flags is the debug formatter
for `File` which would be hacky to depend on. This change adds a type
and method to directly get open file flags.

TEST=cargo test -p sys_util
BUG=chromium:793688

Change-Id: I9fe411d8cb45d2993e2334ffe41f2eb6ec48de70
Reviewed-on: https://chromium-review.googlesource.com/985615
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
2018-03-29 21:59:44 -07:00
Zach Reizner
2948450282 sys_util: add function for creating pipe pairs
Rust's libstd only supports creating socket pairs or pipes for spawning
processes. This change supports creating a unidirectional pipe pair for
any purpose.

BUG=chromium:793688
TEST=None

Change-Id: Ie148735f18c5b8859d8981b9035d87f806a487ff
Reviewed-on: https://chromium-review.googlesource.com/985614
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-03-29 21:59:43 -07:00
Zach Reizner
25c6bc137e sys_util: custom derive for PollToken
Using an enum implementing PollToken is the recommended way to use
PollContext, but writing the trait impls for each enum is mechanical yet
error prone. This is a perfect candidate for a custom derive, which
automates away the process using a simple derive attribute on an enum.

BUG=chromium:816692
TEST=cargo test -p sys_util

Change-Id: If21d0f94f9af4b4f6cef1f24c78fc36b50471053
Reviewed-on: https://chromium-review.googlesource.com/940865
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
2018-03-07 16:54:46 -08:00
Dmitry Torokhov
42d194de3f kvm: plumb in KVM_SET_SIGNAL_MASK ioctl
We need this ioctl to implement race-free support for kicking/pausing VCPUs.

TEST=cargo test --features plugin; cargo test -p kvm; ./build_test
BUG=chromium:800626

Change-Id: I5dcff54f7eb34568a8d8503e0dde86b6a36ac693
Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/932443
Reviewed-by: Zach Reizner <zachr@chromium.org>
2018-02-26 22:07:11 -08:00
Stephen Barber
c79de2d0b2 crosvm: add advisory locking for disk images
Disk images should never be mounted as writable by multiple VMs at once.
Add advisory locking to prevent this.

BUG=chromium:810576
TEST=run crosvm twice with same rwdisk, check that second VM fails to start

Change-Id: I5e6c178515eafa570812a093449eef5a4edc1740
Reviewed-on: https://chromium-review.googlesource.com/929994
Commit-Ready: Stephen Barber <smbarber@chromium.org>
Tested-by: Stephen Barber <smbarber@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
2018-02-21 22:26:53 -08:00
Zach Reizner
ee2f1fe770 sys_util: replace sysconf(_SC_PAGESIZE) with a safe wrapper
There were a few places that used this to get the page size inside of an
unsafe block, For convenience, this adds a safe wrapper in sys_util and
replaces all extant usage of sysconf with the wrapper version.

BUG=chromium:800626
TEST=./build_test

Change-Id: Ic65bf72aea90eabd4158fbdcdbe25c3f13ca93ac
Reviewed-on: https://chromium-review.googlesource.com/857907
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2018-01-10 15:44:31 -08:00
Stephen Barber
f70a9d46e7 sys_util: add chown wrapper
BUG=none
TEST=compile

Change-Id: I3ae66955b48c8cd7ae2f468da8780c85fce539d2
Reviewed-on: https://chromium-review.googlesource.com/733731
Commit-Ready: Stephen Barber <smbarber@chromium.org>
Tested-by: Stephen Barber <smbarber@chromium.org>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
2017-10-26 04:17:52 -07:00
Stephen Barber
5bf651c0e4 sys_util: add get_user_id and get_group_id functions
Add safe wrappers for getpwnam_r and getgrnam_r.

BUG=none
TEST=./build_test

Change-Id: I737b4d264334ed788884a7320f5649cfc2266709
Reviewed-on: https://chromium-review.googlesource.com/733730
Commit-Ready: Stephen Barber <smbarber@chromium.org>
Tested-by: Stephen Barber <smbarber@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-10-26 04:17:52 -07:00
Zach Reizner
3cbded2c51 fix armv7a and aarch64 build errors and warnings
BUG=None
TEST=cargo build --target=armv7a-cros-linux-gnueabi &&
     cargo build --target=aarch64-cros-linux-gnu

Change-Id: I954c152f3c8086e24c4809dd5aabb5043fdd63af
Reviewed-on: https://chromium-review.googlesource.com/644408
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Jason Clinton <jclinton@chromium.org>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-09-01 12:39:18 -07:00
Zach Reizner
56158c873a sys_util: add safe wrappers getpid,geteuid,getguid,waitpid,kill
These functions are trivially safe and by adding them to sys_util, we
can remove some unsafe blocks from crosvm. This CL also replaces the
unsafe call sites with the safe alternatives.

There are no previous usages of gete{g,u}id(2), but they will be needed
in a future change.

TEST=None
BUG=None

Change-Id: Ief8787b298cfaa5b7fd1b83f0eba6660369e687d
Reviewed-on: https://chromium-review.googlesource.com/634268
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-08-28 18:21:37 -07:00
Zach Reizner
29ad3c7d0f crosvm: refactor and expand vm control socket IPC
This CL adds VM request capabilities to the control socket. These
requests include the basic exit as well as the essential ioeventfd and
irqfd requests. For virtio wayland, the register/unregister device
memory request was added.

TEST=cargo test
BUG=chromium:738638

Change-Id: I0cbf62d85a299cf454bcf6924a4e1d52d5b7183f
Reviewed-on: https://chromium-review.googlesource.com/602593
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-08-25 19:54:11 -07:00
Zach Reizner
bf36bcbc4a sys_util: add sock_ctrl_msg module for transmitting messages with FD
This CL also includes the gcc build time dependency for building the
sock_ctrl_msg.c helper code.

TEST=cargo test
BUG=chromium:738638

Change-Id: I4adc2360b7fab4ed7d557603aa7bad2e738b69b4
Reviewed-on: https://chromium-review.googlesource.com/562574
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-07-20 21:21:29 -07:00
Stephen Barber
c4968f7de9 sys_util: add ioctl module
Factor out common ioctl wrappers and macros into their own module.

Signed-off-by: Stephen Barber <smbarber@chromium.org>

BUG=none
TEST=cargo test

Change-Id: Ibede8a853f5cc6c6d62565930f312b11024cc5b5
Reviewed-on: https://chromium-review.googlesource.com/566540
Commit-Ready: Stephen Barber <smbarber@chromium.org>
Tested-by: Stephen Barber <smbarber@chromium.org>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
2017-07-13 22:03:30 -07:00
Stephen Barber
79d07c9727 sys_util: add signalfd module
Dealing with signals is unpleasant business. SignalFd wraps a kernel
signalfd for a signal, and blocks the default handling for the signal.

Signed-off-by: Stephen Barber <smbarber@chromium.org>

BUG=none
TEST=cargo test

Change-Id: I161c992b65b98ffa5c07d546f13efa6b56890df4
Reviewed-on: https://chromium-review.googlesource.com/557459
Commit-Ready: Stephen Barber <smbarber@chromium.org>
Tested-by: Stephen Barber <smbarber@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
2017-07-13 11:44:37 -07:00
Zach Reizner
2b2952ff1f sys_util: add fork module for cloning process
This module is designed as a safe wrapper around clone for use by the
proxy device. It includes safe guards that prevent errors with typical
forking applications in rust.

TEST=cargo test
BUG=None

Change-Id: I09132a4cae61ebdaa97ec3b95d22567c36c5f15d
Reviewed-on: https://chromium-review.googlesource.com/518446
Commit-Ready: Stephen Barber <smbarber@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-07-13 11:44:36 -07:00
Zach Reizner
fd3425db47 sys_util: add shared memory module
This CL adds the SharedMemory structure for managing memory attached to
a file descriptor, which can be sent to external processes.

TEST=cargo test
BUG=chromium:738638

Change-Id: I2b6a10e0e7275367ddb578831a73de6956d231bb
Reviewed-on: https://chromium-review.googlesource.com/562509
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-07-10 11:22:37 -07:00
Zach Reizner
61e2a71b32 sys_util: add syslog module for logging to syslog
TEST=cargo test
BUG=None

Change-Id: Ia7ae04976d0ccbabd6d1656ddd9275f16cce218a
Reviewed-on: https://chromium-review.googlesource.com/553741
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
2017-07-05 21:54:50 -07:00
Zach Reizner
422e6502de sys_util: add signal module for killing threads
The signal module is used for registering signal handlers and for
signalling threads. Normally signals would be a method of last resort,
but in this case it's the only possible way to trigger a VM exit on a
thread currently inside of a KVM_RUN call.

BUG=None
TEST=None

Change-Id: If1db1e17937d1af08fc24b422c460be754cf9d22
Reviewed-on: https://chromium-review.googlesource.com/514415
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-06-30 12:51:24 -07:00
Zach Reizner
8266b87e0e src_util: add terminal module
The terminal module is for configuring pseudo-terminals in raw mode.

TEST=None
BUG=None

Change-Id: Ic724309e0a0f338fb3b35974643c5ab281eb525e
Reviewed-on: https://chromium-review.googlesource.com/514414
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-06-30 12:51:24 -07:00
Zach Reizner
a053a28685 src_util: add poll module
The poll module adds the Poller object for waiting on mutliple file
descriptors at once. The Pollable trait is introduced so rust objects
can expose a file descriptor useful for polling. An impl for EventFd is
included with this change for testing.

TEST=cargo test
BUG=None

Change-Id: I94fd15a17fe0527c0d29c623badb90668d708689
Reviewed-on: https://chromium-review.googlesource.com/514413
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-06-30 12:51:24 -07:00
Zach Reizner
79b2a73272 sys_util: move handle_eintr!() to sys_util so it can be reused
This CL takes the handle_intr!() macro, changes its name to
handle_eintr!(), and overloads it so it can handle EINTR embedded in
other kinds of Result types.

BUG=None
TEST=cargo test

Change-Id: I920ea7d9f156137f42e9e8ea44a3e6946d06b746
Reviewed-on: https://chromium-review.googlesource.com/556348
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-06-30 12:51:24 -07:00
Zach Reizner
0d4f8dff72 crosvm: add virtio block device
This device is useful for exposing a block device, for example a rootfs
image, to the guest.

TEST=None
BUG=None

Change-Id: Ida0d24ed57602f25352563893a1c85b171771c7a
Reviewed-on: https://chromium-review.googlesource.com/514688
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-06-27 06:39:56 -07:00
Dylan Reid
0584fe9fb2 Limit types that can be read from guest memory
Not all types are safe to read from guest memory.  Any type with a
reference or pointer will be initialized to random bits that don't refer
to a valid address.  This can cause dangling pointer and general
unsafe behavior.

To fix this, limit types that can be read with read_obj to those that
implement the unsafe trait `DataInit`.  Provide implementations of
`DataInit` for intrinsic types that are obviously safe to initialize
with random data.

Implement the needed traits for bootparam types as they are read from
the kernel image directly.

Change-Id: I1040f5bc1b2fc4c58c87d8a2ce3f618edcf6f9b1
Signed-off-by: Dylan Reid <dgreid@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/540750
Reviewed-by: Zach Reizner <zachr@chromium.org>
2017-06-27 00:20:33 -07:00
Dylan Reid
71501e0937 sys_util: Add TempDir class
This will be used to create temporary directories that are lifetime
managed for running jails.

Change-Id: I35dfeae76a211c820db090b65baf72277d9e2d8a
Signed-off-by: Dylan Reid <dgreid@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/520706
Reviewed-by: Zach Reizner <zachr@chromium.org>
2017-06-09 21:44:04 -07:00
Dylan Reid
d4eaa4056f sys_util: Add guest_memory
Add a module for accessing guest memory.
This module will replace all the slices that are used to access it
currently as those slices aren't valid because the memory is volatile
and a volatile slice doesn't exist in rust.

Modify the existing users so they no longer depend on the deprecated slice
access.

Change-Id: Ic0e86dacf66f68bd88ed9cc197cb14e45ada891d
Signed-off-by: Dylan Reid <dgreid@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/509919
2017-05-25 22:51:14 -07:00
Dylan Reid
5d084600e9 sys_util: Add struct utils
These utilities are used for reading structs from u8 slices.
Often the kernel returns pointers to void pointers that represent a struct.
This helps convert back to the struct.

Change-Id: I6e59fb772f3ba75f006c9370412267ff565dfe4c
Signed-off-by: Dylan Reid <dgreid@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/497768
Reviewed-by: Zach Reizner <zachr@chromium.org>
2017-05-10 20:58:06 -07:00
Zach Reizner
48faad1bc6 sys_util: add eventfd module
In KVM, eventfd's are essential for sending and receiving signals to the
VM. This CL adds a safe wrapper around their usage.

TEST=cargo test
BUG=None

Change-Id: I04cd9036db156bfa8b9bd49281347a2460fbff2c
Reviewed-on: https://chromium-review.googlesource.com/496988
Commit-Ready: Dylan Reid <dgreid@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-05-08 12:40:51 -07:00
Zach Reizner
00f90a4bba sys_util: add sys_util crate for misc system modules
This initial commit includes an mmap wrapper.

TEST=cargo test
BUG=None

Change-Id: I9625bd446fcd4801b2e16188897e84714b4e4ce0
Reviewed-on: https://chromium-review.googlesource.com/496987
Commit-Ready: Dylan Reid <dgreid@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
2017-05-08 12:40:50 -07:00