vm-virtio, vmm, vfio: Store GuestMemoryMmap in an Arc<ArcSwap<T>>

This allows us to change the memory map that is being used by the
devices via an atomic swap (by replacing the map with another one). The
ArcSwap provides the mechanism for atomically swapping from to another
whilst still giving good read performace. It is inside an Arc so that we
can use a single ArcSwap for all users.

Not covered by this change is replacing the GuestMemoryMmap itself.

This change also removes some vertical whitespace from use blocks in the
files that this commit also changed. Vertical whitespace was being used
inconsistently and broke rustfmt's behaviour of ordering the imports as
it would only do it within the block.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford
2019-12-31 10:49:11 +00:00
parent 5c0bb38a65
commit b2589d4f3f
28 changed files with 213 additions and 222 deletions

View File

@@ -8,27 +8,23 @@
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
//
use std::cmp;
use std::os::unix::thread::JoinHandleExt;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Barrier, Mutex, RwLock, Weak};
use std::thread;
use std::{fmt, io, result};
use libc::{c_void, siginfo_t};
use crate::device_manager::DeviceManager;
#[cfg(feature = "acpi")]
use acpi_tables::{aml, aml::Aml, sdt::SDT};
use arc_swap::ArcSwap;
use arch::layout;
use devices::{ioapic, BusDevice};
use kvm_bindings::CpuId;
use kvm_ioctls::*;
use libc::{c_void, siginfo_t};
use std::cmp;
use std::os::unix::thread::JoinHandleExt;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Barrier, Mutex, Weak};
use std::thread;
use std::{fmt, io, result};
use vm_device::{Migratable, MigratableError, Pausable, Snapshotable};
use vm_memory::{Address, GuestAddress, GuestMemoryMmap};
use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::signal::{register_signal_handler, SIGRTMIN};
@@ -279,7 +275,7 @@ impl Vcpu {
pub fn configure(
&mut self,
kernel_start_addr: Option<GuestAddress>,
vm_memory: &Arc<RwLock<GuestMemoryMmap>>,
vm_memory: &Arc<ArcSwap<GuestMemoryMmap>>,
cpuid: CpuId,
) -> Result<()> {
let mut cpuid = cpuid;
@@ -299,7 +295,7 @@ impl Vcpu {
)
.map_err(Error::REGSConfiguration)?;
arch::x86_64::regs::setup_fpu(&self.fd).map_err(Error::FPUConfiguration)?;
arch::x86_64::regs::setup_sregs(&vm_memory.read().unwrap(), &self.fd)
arch::x86_64::regs::setup_sregs(&vm_memory.load(), &self.fd)
.map_err(Error::SREGSConfiguration)?;
}
arch::x86_64::interrupts::set_lint(&self.fd).map_err(Error::LocalIntConfiguration)?;
@@ -378,7 +374,7 @@ pub struct CpuManager {
io_bus: Weak<devices::Bus>,
mmio_bus: Arc<devices::Bus>,
ioapic: Option<Arc<Mutex<ioapic::Ioapic>>>,
vm_memory: Arc<RwLock<GuestMemoryMmap>>,
vm_memory: Arc<ArcSwap<GuestMemoryMmap>>,
cpuid: CpuId,
fd: Arc<VmFd>,
vcpus_kill_signalled: Arc<AtomicBool>,
@@ -498,7 +494,7 @@ impl CpuManager {
boot_vcpus: u8,
max_vcpus: u8,
device_manager: &DeviceManager,
guest_memory: Arc<RwLock<GuestMemoryMmap>>,
guest_memory: Arc<ArcSwap<GuestMemoryMmap>>,
fd: Arc<VmFd>,
cpuid: CpuId,
reset_evt: EventFd,

View File

@@ -16,13 +16,14 @@ use crate::memory_manager::{Error as MemoryManagerError, MemoryManager};
use crate::vm::VmInfo;
#[cfg(feature = "acpi")]
use acpi_tables::{aml, aml::Aml};
use arc_swap::ArcSwap;
use arch::layout;
use arch::layout::{APIC_START, IOAPIC_SIZE, IOAPIC_START};
use devices::{ioapic, HotPlugNotificationType};
use kvm_bindings::kvm_irq_routing_entry;
use kvm_ioctls::*;
use libc::O_TMPFILE;
use libc::TIOCGWINSZ;
use net_util::Tap;
#[cfg(feature = "pci_support")]
use pci::{
@@ -30,20 +31,17 @@ use pci::{
PciConfigIo, PciConfigMmio, PciDevice, PciRoot,
};
use qcow::{self, ImageType, QcowFile};
use std::fs::{File, OpenOptions};
use std::io::{self, sink, stdout};
use arch::layout::{APIC_START, IOAPIC_SIZE, IOAPIC_START};
use std::cmp;
use std::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::io::{self, sink, stdout};
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::ptr::null_mut;
use std::result;
#[cfg(feature = "pci_support")]
use std::sync::Weak;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::{Arc, Mutex};
#[cfg(feature = "pci_support")]
use vfio::{VfioDevice, VfioDmaMapping, VfioPciDevice, VfioPciError};
use vm_allocator::SystemAllocator;
@@ -741,7 +739,7 @@ impl DeviceManager {
{
// Add a CMOS emulated device
use vm_memory::GuestMemory;
let mem_size = _vm_info.memory.as_ref().read().unwrap().end_addr().0 + 1;
let mem_size = _vm_info.memory.load().end_addr().0 + 1;
let mem_below_4g = std::cmp::min(arch::layout::MEM_32BIT_RESERVED_START.0, mem_size);
let mem_above_4g = mem_size.saturating_sub(arch::layout::RAM_64BIT_START.0);
@@ -1402,7 +1400,7 @@ impl DeviceManager {
#[allow(clippy::too_many_arguments)]
fn add_virtio_pci_device(
virtio_device: Arc<Mutex<dyn vm_virtio::VirtioDevice>>,
memory: &Arc<RwLock<GuestMemoryMmap>>,
memory: &Arc<ArcSwap<GuestMemoryMmap>>,
address_manager: &Arc<AddressManager>,
vm_fd: &Arc<VmFd>,
pci: &mut PciBus,
@@ -1523,7 +1521,7 @@ impl DeviceManager {
#[cfg(feature = "mmio_support")]
fn add_virtio_mmio_device(
virtio_device: Arc<Mutex<dyn vm_virtio::VirtioDevice>>,
memory: &Arc<RwLock<GuestMemoryMmap>>,
memory: &Arc<ArcSwap<GuestMemoryMmap>>,
address_manager: &Arc<AddressManager>,
vm_fd: &Arc<VmFd>,
interrupt_info: &InterruptInfo,

View File

@@ -3,9 +3,9 @@
// SPDX-License-Identifier: Apache-2.0
//
extern crate arc_swap;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate serde;

View File

@@ -3,12 +3,15 @@
// SPDX-License-Identifier: Apache-2.0
//
use arc_swap::ArcSwap;
use arch::RegionType;
use kvm_bindings::kvm_userspace_memory_region;
use kvm_ioctls::*;
use std::fs::{File, OpenOptions};
use std::io;
use std::os::unix::io::FromRawFd;
use std::path::PathBuf;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::{Arc, Mutex};
use vm_allocator::SystemAllocator;
use vm_memory::guest_memory::FileOffset;
use vm_memory::{
@@ -16,11 +19,8 @@ use vm_memory::{
GuestUsize,
};
use kvm_bindings::kvm_userspace_memory_region;
use kvm_ioctls::*;
pub struct MemoryManager {
guest_memory: Arc<RwLock<GuestMemoryMmap>>,
guest_memory: Arc<ArcSwap<GuestMemoryMmap>>,
next_kvm_memory_slot: u32,
start_of_device_area: GuestAddress,
end_of_device_area: GuestAddress,
@@ -131,11 +131,7 @@ impl MemoryManager {
mem_end.unchecked_add(1)
};
// Convert the guest memory into an Arc. The point being able to use it
// anywhere in the code, no matter which thread might use it.
// Add the RwLock aspect to guest memory as we might want to perform
// additions to the memory during runtime.
let guest_memory = Arc::new(RwLock::new(guest_memory));
let guest_memory = Arc::new(ArcSwap::new(Arc::new(guest_memory)));
let memory_manager = Arc::new(Mutex::new(MemoryManager {
guest_memory: guest_memory.clone(),
@@ -145,7 +141,7 @@ impl MemoryManager {
fd,
}));
guest_memory.read().unwrap().with_regions(|_, region| {
guest_memory.load().with_regions(|_, region| {
let _ = memory_manager.lock().unwrap().create_userspace_mapping(
region.start_addr().raw_value(),
region.len() as u64,
@@ -167,7 +163,7 @@ impl MemoryManager {
Ok(memory_manager)
}
pub fn guest_memory(&self) -> Arc<RwLock<GuestMemoryMmap>> {
pub fn guest_memory(&self) -> Arc<ArcSwap<GuestMemoryMmap>> {
self.guest_memory.clone()
}

View File

@@ -29,19 +29,17 @@ use crate::cpu;
use crate::device_manager::{get_win_size, Console, DeviceManager, DeviceManagerError};
use crate::memory_manager::{get_host_cpu_phys_bits, Error as MemoryManagerError, MemoryManager};
use anyhow::anyhow;
use arc_swap::ArcSwap;
use arch::layout;
use devices::{ioapic, HotPlugNotificationType};
use kvm_bindings::{kvm_enable_cap, kvm_userspace_memory_region, KVM_CAP_SPLIT_IRQCHIP};
use kvm_ioctls::*;
use linux_loader::cmdline::Cmdline;
use linux_loader::loader::KernelLoader;
use signal_hook::{iterator::Signals, SIGINT, SIGTERM, SIGWINCH};
use std::ffi::CString;
use std::fs::File;
use std::io;
use std::ops::Deref;
use std::sync::{Arc, Mutex, RwLock};
use std::{result, str, thread};
use vm_allocator::{GsiApic, SystemAllocator};
@@ -159,7 +157,7 @@ pub enum Error {
pub type Result<T> = result::Result<T, Error>;
pub struct VmInfo<'a> {
pub memory: &'a Arc<RwLock<GuestMemoryMmap>>,
pub memory: &'a Arc<ArcSwap<GuestMemoryMmap>>,
pub vm_fd: &'a Arc<VmFd>,
pub vm_cfg: Arc<Mutex<VmConfig>>,
}
@@ -371,9 +369,9 @@ impl Vm {
let cmdline_cstring = CString::new(cmdline).map_err(|_| Error::CmdLine)?;
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
let mem = guest_memory.read().unwrap();
let mem = guest_memory.load_full();
let entry_addr = match linux_loader::loader::Elf::load(
mem.deref(),
mem.as_ref(),
None,
&mut self.kernel,
Some(arch::layout::HIGH_RAM_START),
@@ -381,7 +379,7 @@ impl Vm {
Ok(entry_addr) => entry_addr,
Err(linux_loader::loader::Error::InvalidElfMagicNumber) => {
linux_loader::loader::BzImage::load(
mem.deref(),
mem.as_ref(),
None,
&mut self.kernel,
Some(arch::layout::HIGH_RAM_START),
@@ -392,7 +390,7 @@ impl Vm {
};
linux_loader::loader::load_cmdline(
mem.deref(),
mem.as_ref(),
arch::layout::CMDLINE_START,
&cmdline_cstring,
)