Make KVM path configurable

Most users will want to keep the default `/dev/kvm` path. However, in
certain environments, namely Borg, the KVM device node may be located
elsewhere.

This is the first of a set of related changes that will make hard-coded
device paths configurable.

BUG=None
TEST=./ci/builder --vm ./run_tests

Change-Id: I6087879c535be3779e20eff1f8fb5080f80cf020
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2736520
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Commit-Queue: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
Christian Blichmann 2021-03-04 19:03:54 +01:00 committed by Commit Bot
parent d854217d99
commit 33d5677804
6 changed files with 46 additions and 15 deletions

View file

@ -16,9 +16,11 @@ use std::cell::RefCell;
use std::cmp::{min, Reverse};
use std::collections::{BTreeMap, BinaryHeap};
use std::convert::TryFrom;
use std::ffi::CString;
use std::mem::{size_of, ManuallyDrop};
use std::os::raw::{c_char, c_int, c_ulong, c_void};
use std::os::unix::io::AsRawFd;
use std::os::raw::{c_int, c_ulong, c_void};
use std::os::unix::{io::AsRawFd, prelude::OsStrExt};
use std::path::{Path, PathBuf};
use std::ptr::copy_nonoverlapping;
use std::sync::atomic::AtomicU64;
use std::sync::Arc;
@ -94,11 +96,10 @@ pub struct Kvm {
type KvmCap = kvm::Cap;
impl Kvm {
/// Opens `/dev/kvm/` and returns a Kvm object on success.
pub fn new() -> Result<Kvm> {
// Open calls are safe because we give a constant nul-terminated string and verify the
// result.
let ret = unsafe { open("/dev/kvm\0".as_ptr() as *const c_char, O_RDWR | O_CLOEXEC) };
pub fn new_with_path(device_path: &Path) -> Result<Kvm> {
// Open calls are safe because we give a nul-terminated string and verify the result.
let c_path = CString::new(device_path.as_os_str().as_bytes()).unwrap();
let ret = unsafe { open(c_path.as_ptr(), O_RDWR | O_CLOEXEC) };
if ret < 0 {
return errno_result();
}
@ -108,6 +109,11 @@ impl Kvm {
})
}
/// Opens `/dev/kvm/` and returns a Kvm object on success.
pub fn new() -> Result<Kvm> {
Kvm::new_with_path(&PathBuf::from("/dev/kvm"))
}
/// Gets the size of the mmap required to use vcpu's `kvm_run` structure.
pub fn get_vcpu_mmap_size(&self) -> Result<usize> {
// Safe because we know that our file is a KVM fd and we verify the return result.

View file

@ -9,10 +9,13 @@ mod cap;
use std::cell::RefCell;
use std::cmp::{min, Ordering};
use std::collections::{BTreeMap, BinaryHeap};
use std::ffi::CString;
use std::fs::File;
use std::mem::size_of;
use std::ops::{Deref, DerefMut};
use std::os::raw::*;
use std::os::unix::prelude::OsStrExt;
use std::path::{Path, PathBuf};
use std::ptr::copy_nonoverlapping;
use std::sync::Arc;
use sync::Mutex;
@ -94,9 +97,14 @@ pub struct Kvm {
impl Kvm {
/// Opens `/dev/kvm/` and returns a Kvm object on success.
pub fn new() -> Result<Kvm> {
// Open calls are safe because we give a constant nul-terminated string and verify the
// result.
let ret = unsafe { open("/dev/kvm\0".as_ptr() as *const c_char, O_RDWR | O_CLOEXEC) };
Kvm::new_with_path(&PathBuf::from("/dev/kvm"))
}
/// Opens a KVM device at `device_path` and returns a Kvm object on success.
pub fn new_with_path(device_path: &Path) -> Result<Kvm> {
// Open calls are safe because we give a nul-terminated string and verify the result.
let c_path = CString::new(device_path.as_os_str().as_bytes()).unwrap();
let ret = unsafe { open(c_path.as_ptr(), O_RDWR | O_CLOEXEC) };
if ret < 0 {
return errno_result();
}

View file

@ -29,6 +29,7 @@ use devices::ProtectionType;
use libc::{getegid, geteuid};
use vm_control::BatteryType;
static KVM_PATH: &str = "/dev/kvm";
static SECCOMP_POLICY_DIR: &str = "/usr/share/policy/crosvm";
/// Indicates the location and kind of executable kernel for a VM.
@ -174,6 +175,7 @@ impl Default for SharedDir {
/// Aggregate of all configurable options for a running VM.
pub struct Config {
pub kvm_device_path: PathBuf,
pub vcpu_count: Option<usize>,
pub rt_cpus: Vec<usize>,
pub vcpu_affinity: Option<VcpuAffinity>,
@ -234,6 +236,7 @@ pub struct Config {
impl Default for Config {
fn default() -> Config {
Config {
kvm_device_path: PathBuf::from(KVM_PATH),
vcpu_count: None,
rt_cpus: Vec::new(),
vcpu_affinity: None,

View file

@ -2164,8 +2164,8 @@ fn file_to_i64<P: AsRef<Path>>(path: P, nth: usize) -> io::Result<i64> {
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "empty file"))
}
fn create_kvm(mem: GuestMemory) -> base::Result<KvmVm> {
let kvm = Kvm::new()?;
fn create_kvm(device_path: &Path, mem: GuestMemory) -> base::Result<KvmVm> {
let kvm = Kvm::new_with_path(device_path)?;
let vm = KvmVm::new(&kvm, mem)?;
Ok(vm)
}
@ -2190,6 +2190,8 @@ fn create_kvm_split_irq_chip(
}
pub fn run_config(cfg: Config) -> Result<()> {
let kvm_device_path = cfg.kvm_device_path.clone();
let create_kvm_with_path = |mem| create_kvm(&kvm_device_path, mem);
if cfg.split_irqchip {
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
{
@ -2198,10 +2200,10 @@ pub fn run_config(cfg: Config) -> Result<()> {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
run_vm::<_, KvmVcpu, _, _, _>(cfg, create_kvm, create_kvm_split_irq_chip)
run_vm::<_, KvmVcpu, _, _, _>(cfg, create_kvm_with_path, create_kvm_split_irq_chip)
}
} else {
run_vm::<_, KvmVcpu, _, _, _>(cfg, create_kvm, create_kvm_kernel_irq_chip)
run_vm::<_, KvmVcpu, _, _, _>(cfg, create_kvm_with_path, create_kvm_kernel_irq_chip)
}
}

View file

@ -676,6 +676,17 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
}
cfg.executable_path = Some(Executable::Kernel(kernel_path));
}
"kvm-device" => {
let kvm_device_path = PathBuf::from(value.unwrap());
if !kvm_device_path.exists() {
return Err(argument::Error::InvalidValue {
value: value.unwrap().to_owned(),
expected: String::from("this kvm device path does not exist"),
});
}
cfg.kvm_device_path = kvm_device_path;
}
"android-fstab" => {
if cfg.android_fstab.is_some()
&& !cfg.android_fstab.as_ref().unwrap().as_os_str().is_empty()
@ -1595,6 +1606,7 @@ 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("kvm-device", "PATH", "Path to the KVM device. (default /dev/kvm)"),
Argument::value("android-fstab", "PATH", "Path to Android fstab"),
Argument::short_value('i', "initrd", "PATH", "Initial ramdisk to load."),
Argument::short_value('p',

View file

@ -691,7 +691,7 @@ pub fn run_config(cfg: Config) -> Result<()> {
};
let vcpu_count = cfg.vcpu_count.unwrap_or(1) as u32;
let mem = GuestMemory::new(&[]).unwrap();
let kvm = Kvm::new().map_err(Error::CreateKvm)?;
let kvm = Kvm::new_with_path(&cfg.kvm_device_path).map_err(Error::CreateKvm)?;
let mut vm = Vm::new(&kvm, mem).map_err(Error::CreateVm)?;
vm.create_irq_chip().map_err(Error::CreateIrqChip)?;
vm.create_pit().map_err(Error::CreatePIT)?;