vmm: Create shared memory region for virtio-fs

When the cache_size parameter from virtio-fs device is not empty, the
VMM creates a dedicated memory region where the shared files will be
memory mapped by the virtio-fs device.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2019-08-05 13:04:24 -07:00 committed by Samuel Ortiz
parent 74225ab5b3
commit 3c29c47783
2 changed files with 81 additions and 3 deletions

View File

@ -3,7 +3,9 @@
use super::Error as DeviceError;
use super::{ActivateError, ActivateResult, Queue, VirtioDevice, VirtioDeviceType};
use crate::{VirtioInterrupt, VirtioInterruptType, VIRTIO_F_VERSION_1_BITMASK};
use crate::{
VirtioInterrupt, VirtioInterruptType, VirtioSharedMemoryList, VIRTIO_F_VERSION_1_BITMASK,
};
use epoll;
use libc::EFD_NONBLOCK;
use std::cmp;
@ -183,7 +185,13 @@ pub struct Fs {
impl Fs {
/// Create a new virtio-fs device.
pub fn new(path: &str, tag: &str, req_num_queues: usize, queue_size: u16) -> Result<Fs> {
pub fn new(
path: &str,
tag: &str,
req_num_queues: usize,
queue_size: u16,
_cache_addr: Option<(VirtioSharedMemoryList, u64)>,
) -> Result<Fs> {
// Calculate the actual number of queues needed.
let num_queues = NUM_QUEUE_OFFSET + req_num_queues;
// Connect to the vhost-user socket.

View File

@ -56,6 +56,7 @@ use vm_memory::{
GuestMemoryRegion, GuestUsize,
};
use vm_virtio::transport::VirtioPciDevice;
use vm_virtio::{VirtioSharedMemory, VirtioSharedMemoryList};
use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::signal::register_signal_handler;
use vmm_sys_util::terminal::Terminal;
@ -244,6 +245,9 @@ pub enum DeviceManagerError {
/// Cannot find a memory range for persistent memory
PmemRangeAllocation,
/// Cannot find a memory range for virtio-fs
FsRangeAllocation,
/// Error creating serial output file
SerialOutputFileOpen(io::Error),
@ -261,6 +265,9 @@ pub enum DeviceManagerError {
/// Failed to create the KVM device.
CreateKvmDevice(io::Error),
/// Failed to memory map.
Mmap(io::Error),
}
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
@ -685,7 +692,14 @@ impl DeviceManager {
DeviceManager::add_virtio_rng_devices(vm_info, allocator, pci, buses, &interrupt_info)?;
// Add virtio-fs if required
DeviceManager::add_virtio_fs_devices(vm_info, allocator, pci, buses, &interrupt_info)?;
DeviceManager::add_virtio_fs_devices(
vm_info,
allocator,
pci,
buses,
&interrupt_info,
&mut mem_slots,
)?;
// Add virtio-pmem if required
DeviceManager::add_virtio_pmem_devices(
@ -820,16 +834,72 @@ impl DeviceManager {
pci: &mut PciConfigIo,
buses: &mut BusInfo,
interrupt_info: &InterruptInfo,
mem_slots: &mut u32,
) -> DeviceManagerResult<()> {
// Add virtio-fs if required
if let Some(fs_list_cfg) = &vm_info.vm_cfg.fs {
for fs_cfg in fs_list_cfg.iter() {
if let Some(fs_sock) = fs_cfg.sock.to_str() {
let mut cache: Option<(VirtioSharedMemoryList, u64)> = None;
if let Some(fs_cache) = fs_cfg.cache_size {
// The memory needs to be 2MiB aligned in order to support
// hugepages.
let fs_guest_addr = allocator
.allocate_mmio_addresses(
None,
fs_cache as GuestUsize,
Some(0x0020_0000),
)
.ok_or(DeviceManagerError::FsRangeAllocation)?;
let addr = unsafe {
libc::mmap(
null_mut(),
fs_cache as usize,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_NORESERVE | libc::MAP_ANONYMOUS | libc::MAP_PRIVATE,
-1,
0 as libc::off_t,
)
};
if addr == libc::MAP_FAILED {
return Err(DeviceManagerError::Mmap(io::Error::last_os_error()));
}
let mem_region = kvm_userspace_memory_region {
slot: *mem_slots as u32,
guest_phys_addr: fs_guest_addr.raw_value(),
memory_size: fs_cache,
userspace_addr: addr as u64,
flags: 0,
};
// Safe because the guest regions are guaranteed not to overlap.
let _ = unsafe { vm_info.vm_fd.set_user_memory_region(mem_region) };
// Increment the KVM slot number
*mem_slots += 1;
let mut region_list = Vec::new();
region_list.push(VirtioSharedMemory {
offset: 0,
len: fs_cache,
});
cache = Some((
VirtioSharedMemoryList {
addr: fs_guest_addr,
len: fs_cache as GuestUsize,
region_list,
},
addr as u64,
));
}
let virtio_fs_device = vm_virtio::Fs::new(
fs_sock,
fs_cfg.tag,
fs_cfg.num_queues,
fs_cfg.queue_size,
cache,
)
.map_err(DeviceManagerError::CreateVirtioFs)?;