memory: Allow memory to be backed by a file

In the context of vhost-user, we need the guest RAM to be backed by
a file in order to be accessed by an external process. This patch
adds the new flag "file=" to the "--memory" option so that we can
specify from the command line if the memory needs to be backed, and
by which specific file.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2019-05-24 12:21:23 -07:00 committed by Samuel Ortiz
parent 2ede30b6d3
commit 53085c7ccc
3 changed files with 73 additions and 37 deletions

View File

@ -26,7 +26,10 @@ fn main() {
.arg(
Arg::with_name("memory")
.long("memory")
.help("Amount of RAM (in MiB)")
.help(
"Memory parameters \"size=<guest_memory_size>,\
file=<backing_file_path>\"",
)
.default_value(config::DEFAULT_MEMORY),
)
.arg(
@ -118,7 +121,7 @@ fn main() {
"Cloud Hypervisor Guest\n\tvCPUs: {}\n\tMemory: {} MB\
\n\tKernel: {:?}\n\tKernel cmdline: {}\n\tDisk(s): {:?}",
u8::from(&vm_config.cpus),
u64::from(&vm_config.memory),
vm_config.memory.size,
vm_config.kernel.path,
vm_config.cmdline.args.as_str(),
vm_config.disks,
@ -242,7 +245,7 @@ mod tests {
let (disks, fw_path) = prepare_files();
let mut child = Command::new("target/debug/cloud-hypervisor")
.args(&["--cpus", "1"])
.args(&["--memory", "512"])
.args(&["--memory", "size=512"])
.args(&["--kernel", fw_path.as_str()])
.args(&["--disk", disks[0], disks[1]])
.args(&["--net", "tap=,mac=,ip=192.168.2.1,mask=255.255.255.0"])
@ -270,7 +273,7 @@ mod tests {
let (disks, fw_path) = prepare_files();
let mut child = Command::new("target/debug/cloud-hypervisor")
.args(&["--cpus", "2"])
.args(&["--memory", "512"])
.args(&["--memory", "size=512"])
.args(&["--kernel", fw_path.as_str()])
.args(&["--disk", disks[0], disks[1]])
.args(&["--net", "tap=,mac=,ip=192.168.2.1,mask=255.255.255.0"])
@ -295,7 +298,7 @@ mod tests {
let (disks, fw_path) = prepare_files();
let mut child = Command::new("target/debug/cloud-hypervisor")
.args(&["--cpus", "1"])
.args(&["--memory", "5120"])
.args(&["--memory", "size=5120"])
.args(&["--kernel", fw_path.as_str()])
.args(&["--disk", disks[0], disks[1]])
.args(&["--net", "tap=,mac=,ip=192.168.2.1,mask=255.255.255.0"])
@ -320,7 +323,7 @@ mod tests {
let (disks, fw_path) = prepare_files();
let mut child = Command::new("target/debug/cloud-hypervisor")
.args(&["--cpus", "1"])
.args(&["--memory", "512"])
.args(&["--memory", "size=512"])
.args(&["--kernel", fw_path.as_str()])
.args(&["--disk", disks[0], disks[1]])
.args(&["--net", "tap=,mac=,ip=192.168.2.1,mask=255.255.255.0"])
@ -358,7 +361,7 @@ mod tests {
let mut child = Command::new("target/debug/cloud-hypervisor")
.args(&["--cpus", "1"])
.args(&["--memory", "512"])
.args(&["--memory", "size=512"])
.args(&["--kernel", kernel_path.to_str().unwrap()])
.args(&["--disk", disks[0], disks[1]])
.args(&["--net", "tap=,mac=,ip=192.168.2.1,mask=255.255.255.0"])
@ -400,7 +403,7 @@ mod tests {
let mut child = Command::new("target/debug/cloud-hypervisor")
.args(&["--cpus", "1"])
.args(&["--memory", "512"])
.args(&["--memory", "size=512"])
.args(&["--kernel", kernel_path.to_str().unwrap()])
.args(&["--disk", disks[0], disks[1]])
.args(&["--net", "tap=,mac=,ip=192.168.2.1,mask=255.255.255.0"])

View File

@ -13,7 +13,7 @@ use std::result;
use vm_memory::GuestAddress;
pub const DEFAULT_VCPUS: &str = "1";
pub const DEFAULT_MEMORY: &str = "512";
pub const DEFAULT_MEMORY: &str = "size=512";
pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom";
const CMDLINE_OFFSET: GuestAddress = GuestAddress(0x20000);
@ -22,8 +22,10 @@ const CMDLINE_OFFSET: GuestAddress = GuestAddress(0x20000);
pub enum Error<'a> {
/// Failed parsing cpus parameters.
ParseCpusParams(std::num::ParseIntError),
/// Failed parsing memory parameters.
ParseMemoryParams(std::num::ParseIntError),
/// Failed parsing memory size parameter.
ParseMemorySizeParam(std::num::ParseIntError),
/// Failed parsing memory file parameter.
ParseMemoryFileParam,
/// Failed parsing kernel parameters.
ParseKernelParams,
/// Failed parsing kernel command line parameters.
@ -76,19 +78,45 @@ impl From<&CpusConfig> for u8 {
}
}
pub struct MemoryConfig(pub u64);
impl MemoryConfig {
pub fn parse(memory: &str) -> Result<Self> {
Ok(MemoryConfig(
memory.parse::<u64>().map_err(Error::ParseMemoryParams)?,
))
}
pub struct MemoryConfig<'a> {
pub size: u64,
pub file: Option<&'a Path>,
}
impl From<&MemoryConfig> for u64 {
fn from(val: &MemoryConfig) -> Self {
val.0
impl<'a> MemoryConfig<'a> {
pub fn parse(memory: &'a str) -> Result<Self> {
// Split the parameters based on the comma delimiter
let params_list: Vec<&str> = memory.split(',').collect();
let mut size_str: &str = "";
let mut file_str: &str = "";
let mut backed = false;
for param in params_list.iter() {
if param.starts_with("size=") {
size_str = &param[5..];
} else if param.starts_with("file=") {
backed = true;
file_str = &param[5..];
}
}
let file = if backed {
if file_str.is_empty() {
return Err(Error::ParseMemoryFileParam);
}
Some(Path::new(file_str))
} else {
None
};
Ok(MemoryConfig {
size: size_str
.parse::<u64>()
.map_err(Error::ParseMemorySizeParam)?,
file,
})
}
}
@ -268,7 +296,7 @@ impl<'a> FsConfig<'a> {
pub struct VmConfig<'a> {
pub cpus: CpusConfig,
pub memory: MemoryConfig,
pub memory: MemoryConfig<'a>,
pub kernel: KernelConfig<'a>,
pub cmdline: CmdlineConfig,
pub disks: Vec<DiskConfig<'a>>,

View File

@ -843,24 +843,29 @@ impl<'a> Vm<'a> {
let fd = Arc::new(fd);
// Init guest memory
let arch_mem_regions = arch::arch_memory_regions(u64::from(&config.memory) << 20);
let arch_mem_regions = arch::arch_memory_regions(config.memory.size << 20);
let mut mem_regions = Vec::<(GuestAddress, usize, Option<FileOffset>)>::new();
for region in arch_mem_regions.iter() {
let file = OpenOptions::new()
.read(true)
.write(true)
.custom_flags(O_TMPFILE)
.open("/dev/shm")
.map_err(Error::SharedFileCreate)?;
let guest_memory = match config.memory.file {
Some(file) => {
let mut mem_regions = Vec::<(GuestAddress, usize, Option<FileOffset>)>::new();
for region in arch_mem_regions.iter() {
let file = OpenOptions::new()
.read(true)
.write(true)
.custom_flags(O_TMPFILE)
.open(file)
.map_err(Error::SharedFileCreate)?;
file.set_len(region.1 as u64)
.map_err(Error::SharedFileSetLen)?;
file.set_len(region.1 as u64)
.map_err(Error::SharedFileSetLen)?;
mem_regions.push((region.0, region.1, Some(FileOffset::new(file, 0))));
}
mem_regions.push((region.0, region.1, Some(FileOffset::new(file, 0))));
}
let guest_memory = GuestMemoryMmap::with_files(&mem_regions).map_err(Error::GuestMemory)?;
GuestMemoryMmap::with_files(&mem_regions).map_err(Error::GuestMemory)?
}
None => GuestMemoryMmap::new(&arch_mem_regions).map_err(Error::GuestMemory)?,
};
guest_memory
.with_regions(|index, region| {