mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-28 17:44:10 +00:00
crosvm: implement lock-guest-memory feature.
This CL adds a command-line flag to crosm that locks the entire guest memory, per http://go/host-assisted-vm-swap. The change relies on existing balloon device code that punches holes within the guest memory region upon "inflate". BUG=b:236210703 TEST=manual startup, roblox+instagram and various chrome sessions Change-Id: I11e0e5b0b0cb6450f47124a6a8b6c4befd9de6ae Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3725731 Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org> Reviewed-by: David Stevens <stevensd@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Alexandre Marciano Gimenez <raging@google.com> Auto-Submit: Alexandre Marciano Gimenez <raging@google.com>
This commit is contained in:
parent
10574227dc
commit
ed071b6edd
5 changed files with 71 additions and 2 deletions
|
@ -12,6 +12,8 @@ use std::{
|
|||
ptr::{copy_nonoverlapping, null_mut, read_unaligned, write_unaligned},
|
||||
};
|
||||
|
||||
use log::warn;
|
||||
|
||||
use crate::{
|
||||
external_mapping::ExternalMapping, AsRawDescriptor, Descriptor,
|
||||
MemoryMapping as CrateMemoryMapping, MemoryMappingBuilder, RawDescriptor, SafeDescriptor,
|
||||
|
@ -703,6 +705,34 @@ impl MemoryMapping {
|
|||
}
|
||||
}
|
||||
|
||||
/// Disable host swap for this mapping.
|
||||
pub fn lock_all(&self) -> Result<()> {
|
||||
let ret = unsafe {
|
||||
// Safe because MLOCK_ONFAULT only affects the swap behavior of the kernel, so it
|
||||
// has no impact on rust semantics.
|
||||
// TODO(raging): use the explicit declaration of mlock2, which was being merged
|
||||
// as of when the call below was being worked on.
|
||||
libc::syscall(
|
||||
libc::SYS_mlock2,
|
||||
(self.addr as usize) as *const libc::c_void,
|
||||
self.size(),
|
||||
libc::MLOCK_ONFAULT,
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
let errno = super::Error::last();
|
||||
warn!(
|
||||
"failed to mlock at {:#x} with length {}: {}",
|
||||
(self.addr as usize) as u64,
|
||||
self.size(),
|
||||
errno,
|
||||
);
|
||||
Err(Error::SystemCallFailed(errno))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Check that offset+count is valid and return the sum.
|
||||
fn range_end(&self, offset: usize, count: usize) -> Result<usize> {
|
||||
let mem_end = offset.checked_add(count).ok_or(Error::InvalidAddress)?;
|
||||
|
@ -990,13 +1020,19 @@ impl CrateMemoryMapping {
|
|||
}
|
||||
|
||||
pub trait Unix {
|
||||
/// Remove the specified range from the mapping.
|
||||
fn remove_range(&self, mem_offset: usize, count: usize) -> Result<()>;
|
||||
/// Disable host swap for this mapping.
|
||||
fn lock_all(&self) -> Result<()>;
|
||||
}
|
||||
|
||||
impl Unix for CrateMemoryMapping {
|
||||
fn remove_range(&self, mem_offset: usize, count: usize) -> Result<()> {
|
||||
self.mapping.remove_range(mem_offset, count)
|
||||
}
|
||||
fn lock_all(&self) -> Result<()> {
|
||||
self.mapping.lock_all()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MemoryMappingBuilderUnix<'a> {
|
||||
|
|
|
@ -651,6 +651,9 @@ pub struct RunCommand {
|
|||
#[argh(option, long = "kvm-device", arg_name = "PATH")]
|
||||
/// path to the KVM device. (default /dev/kvm)
|
||||
pub kvm_device_path: Option<PathBuf>,
|
||||
#[argh(switch)]
|
||||
/// disable host swap on guest VM pages.
|
||||
pub lock_guest_memory: bool,
|
||||
#[cfg(unix)]
|
||||
#[argh(option, arg_name = "MAC", long = "mac")]
|
||||
/// MAC address for VM
|
||||
|
@ -1197,6 +1200,8 @@ impl TryFrom<RunCommand> for super::config::Config {
|
|||
|
||||
cfg.hugepages = cmd.hugepages;
|
||||
|
||||
cfg.lock_guest_memory = cmd.lock_guest_memory;
|
||||
|
||||
#[cfg(feature = "audio")]
|
||||
{
|
||||
cfg.ac97_parameters = cmd.ac97;
|
||||
|
|
|
@ -1720,6 +1720,7 @@ pub struct Config {
|
|||
pub itmt: bool,
|
||||
pub jail_config: Option<JailConfig>,
|
||||
pub kvm_device_path: PathBuf,
|
||||
pub lock_guest_memory: bool,
|
||||
pub mac_address: Option<net_util::MacAddress>,
|
||||
pub memory: Option<u64>,
|
||||
pub memory_file: Option<PathBuf>,
|
||||
|
@ -1856,6 +1857,7 @@ impl Default for Config {
|
|||
None
|
||||
},
|
||||
kvm_device_path: PathBuf::from(KVM_PATH),
|
||||
lock_guest_memory: false,
|
||||
mac_address: None,
|
||||
memory: None,
|
||||
memory_file: None,
|
||||
|
@ -2137,6 +2139,10 @@ pub fn validate_config(cfg: &mut Config) -> std::result::Result<(), String> {
|
|||
return Err("'balloon-control' requires enabled balloon".to_string());
|
||||
}
|
||||
|
||||
if cfg.lock_guest_memory && cfg.jail_config.is_none() {
|
||||
return Err("'lock-guest-memory' and 'disable-sandbox' are mutually exclusive".to_string());
|
||||
}
|
||||
|
||||
set_default_serial_parameters(
|
||||
&mut cfg.serial_parameters,
|
||||
!cfg.vhost_user_console.is_empty(),
|
||||
|
|
|
@ -1201,6 +1201,10 @@ pub fn run_config(cfg: Config) -> Result<ExitState> {
|
|||
if components.hugepages {
|
||||
mem_policy |= MemoryPolicy::USE_HUGEPAGES;
|
||||
}
|
||||
|
||||
if cfg.lock_guest_memory {
|
||||
mem_policy |= MemoryPolicy::LOCK_GUEST_MEMORY;
|
||||
}
|
||||
guest_mem.set_memory_policy(mem_policy);
|
||||
|
||||
if cfg.kvm_device_path.exists() {
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::{Error, GuestAddress, GuestMemory, Result};
|
|||
bitflags! {
|
||||
pub struct MemoryPolicy: u32 {
|
||||
const USE_HUGEPAGES = 1;
|
||||
const LOCK_GUEST_MEMORY = (1 << 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,14 +42,31 @@ impl GuestMemory {
|
|||
|
||||
/// Handles guest memory policy hints/advices.
|
||||
pub fn set_memory_policy(&self, mem_policy: MemoryPolicy) {
|
||||
if mem_policy.contains(MemoryPolicy::USE_HUGEPAGES) {
|
||||
for (_, region) in self.regions.iter().enumerate() {
|
||||
if mem_policy.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
for (_, region) in self.regions.iter().enumerate() {
|
||||
if mem_policy.contains(MemoryPolicy::USE_HUGEPAGES) {
|
||||
let ret = region.mapping.use_hugepages();
|
||||
|
||||
if let Err(err) = ret {
|
||||
println!("Failed to enable HUGEPAGE for mapping {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
if mem_policy.contains(MemoryPolicy::LOCK_GUEST_MEMORY) {
|
||||
// This is done in coordination with remove_range() calls, which are
|
||||
// performed by the virtio-balloon process (they must be performed by
|
||||
// a different process from the one that issues the locks).
|
||||
// We also prevent this from happening in single-process configurations,
|
||||
// when we compute configuration flags.
|
||||
let ret = region.mapping.lock_all();
|
||||
|
||||
if let Err(err) = ret {
|
||||
println!("Failed to lock memory for mapping {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue