vmm: hypervisor: split set_user_memory_region to two functions

Previously the same function was used to both create and remove regions.
This worked on KVM because it uses size 0 to indicate removal.

MSHV has two calls -- one for creation and one for removal. It also
requires having the size field available because it is not slot based.

Split set_user_memory_region to {create/remove}_user_memory_region. For
KVM they still use set_user_memory_region underneath, but for MSHV they
map to different functions.

This fixes user memory region removal on MSHV.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
Wei Liu 2021-07-03 13:58:39 +00:00 committed by Sebastien Boeuf
parent 63b8d2eb58
commit 1f2915bff0
7 changed files with 65 additions and 33 deletions

View File

@ -234,7 +234,7 @@ impl vm::Vm for KvmVm {
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
}
///
/// Creates a memory region structure that can be used with set_user_memory_region
/// Creates a memory region structure that can be used with {create/remove}_user_memory_region
///
fn make_user_memory_region(
&self,
@ -259,14 +259,29 @@ impl vm::Vm for KvmVm {
}
}
///
/// Creates/modifies a guest physical memory slot.
/// Creates a guest physical memory region.
///
fn set_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
fn create_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
// Safe because guest regions are guaranteed not to overlap.
unsafe {
self.fd
.set_user_memory_region(user_memory_region)
.map_err(|e| vm::HypervisorVmError::SetUserMemory(e.into()))
.map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into()))
}
}
///
/// Removes a guest physical memory region.
///
fn remove_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
let mut region = user_memory_region;
// Setting the size to 0 means "remove"
region.memory_size = 0;
// Safe because guest regions are guaranteed not to overlap.
unsafe {
self.fd
.set_user_memory_region(region)
.map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into()))
}
}
///

View File

@ -798,11 +798,19 @@ impl vm::Vm for MshvVm {
.map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into()))
}
/// Creates/modifies a guest physical memory slot.
fn set_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
/// Creates a guest physical memory region.
fn create_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
self.fd
.map_user_memory(user_memory_region)
.map_err(|e| vm::HypervisorVmError::SetUserMemory(e.into()))?;
.map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into()))?;
Ok(())
}
/// Removes a guest physical memory region.
fn remove_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
self.fd
.unmap_user_memory(user_memory_region)
.map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into()))?;
Ok(())
}

View File

@ -92,10 +92,15 @@ pub enum HypervisorVmError {
#[error("Failed to set GSI routing: {0}")]
SetGsiRouting(#[source] anyhow::Error),
///
/// Set user memory error
/// Create user memory error
///
#[error("Failed to set user memory: {0}")]
SetUserMemory(#[source] anyhow::Error),
#[error("Failed to create user memory: {0}")]
CreateUserMemory(#[source] anyhow::Error),
///
/// Remove user memory region error
///
#[error("Failed to remove user memory: {0}")]
RemoveUserMemory(#[source] anyhow::Error),
///
/// Create device error
///
@ -218,7 +223,7 @@ pub trait Vm: Send + Sync {
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>;
/// Sets the GSI routing table entries, overwriting any previously set
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> Result<()>;
/// Creates a memory region structure that can be used with set_user_memory_region
/// Creates a memory region structure that can be used with {create/remove}_user_memory_region
fn make_user_memory_region(
&self,
slot: u32,
@ -228,8 +233,10 @@ pub trait Vm: Send + Sync {
readonly: bool,
log_dirty_pages: bool,
) -> MemoryRegion;
/// Creates/modifies a guest physical memory slot.
fn set_user_memory_region(&self, user_memory_region: MemoryRegion) -> Result<()>;
/// Creates a guest physical memory slot.
fn create_user_memory_region(&self, user_memory_region: MemoryRegion) -> Result<()>;
/// Removes a guest physical memory slot.
fn remove_user_memory_region(&self, user_memory_region: MemoryRegion) -> Result<()>;
#[cfg(feature = "kvm")]
/// Creates an emulated device in the kernel.
fn create_device(&self, device: &mut CreateDevice) -> Result<Arc<dyn Device>>;

View File

@ -679,7 +679,7 @@ impl VfioPciDevice {
false,
);
vm.set_user_memory_region(mem_region)
vm.create_user_memory_region(mem_region)
.map_err(|e| VfioPciError::MapRegionGuest(e.into()))?;
// Update the region with memory mapped info.
@ -703,13 +703,13 @@ impl VfioPciDevice {
let r = self.vm.make_user_memory_region(
mem_slot,
region.start.raw_value() + mmap_offset,
0,
mmap_size as u64,
host_addr as u64,
false,
false,
);
if let Err(e) = self.vm.set_user_memory_region(r) {
if let Err(e) = self.vm.remove_user_memory_region(r) {
error!("Could not remove the userspace memory region: {}", e);
}
@ -1137,14 +1137,14 @@ impl PciDevice for VfioPciDevice {
let old_mem_region = self.vm.make_user_memory_region(
mem_slot,
old_base + mmap_offset,
0,
mmap_size as u64,
host_addr as u64,
false,
false,
);
self.vm
.set_user_memory_region(old_mem_region)
.remove_user_memory_region(old_mem_region)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
// Insert new region
@ -1158,7 +1158,7 @@ impl PciDevice for VfioPciDevice {
);
self.vm
.set_user_memory_region(new_mem_region)
.create_user_memory_region(new_mem_region)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
}
}

View File

@ -727,20 +727,19 @@ impl DeviceRelocation for AddressManager {
let mut virtio_dev = virtio_dev.lock().unwrap();
if let Some(mut shm_regions) = virtio_dev.get_shm_regions() {
if shm_regions.addr.raw_value() == old_base {
// Remove old region from KVM by passing a size of 0.
let mem_region = self.vm.make_user_memory_region(
shm_regions.mem_slot,
old_base,
0,
shm_regions.len,
shm_regions.host_addr,
false,
false,
);
self.vm.set_user_memory_region(mem_region).map_err(|e| {
self.vm.remove_user_memory_region(mem_region).map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("failed to set user memory region: {:?}", e),
format!("failed to remove user memory region: {:?}", e),
)
})?;
@ -754,10 +753,10 @@ impl DeviceRelocation for AddressManager {
false,
);
self.vm.set_user_memory_region(mem_region).map_err(|e| {
self.vm.create_user_memory_region(mem_region).map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("failed to set user memory regions: {:?}", e),
format!("failed to create user memory regions: {:?}", e),
)
})?;

View File

@ -176,8 +176,11 @@ pub enum Error {
/// The requested hotplug memory addition is not a valid size
InvalidSize,
/// Failed to set the user memory region.
SetUserMemoryRegion(hypervisor::HypervisorVmError),
/// Failed to create the user memory region.
CreateUserMemoryRegion(hypervisor::HypervisorVmError),
/// Failed to remove the user memory region.
RemoveUserMemoryRegion(hypervisor::HypervisorVmError),
/// Failed to EventFd.
EventFdFail(io::Error),
@ -1212,8 +1215,8 @@ impl MemoryManager {
);
self.vm
.set_user_memory_region(mem_region)
.map_err(Error::SetUserMemoryRegion)?;
.create_user_memory_region(mem_region)
.map_err(Error::CreateUserMemoryRegion)?;
// Mark the pages as mergeable if explicitly asked for.
if mergeable {
@ -1259,15 +1262,15 @@ impl MemoryManager {
let mem_region = self.vm.make_user_memory_region(
slot,
guest_phys_addr,
0, /* memory_size -- using 0 removes this slot */
memory_size,
userspace_addr,
false, /* readonly -- don't care */
false, /* log dirty */
);
self.vm
.set_user_memory_region(mem_region)
.map_err(Error::SetUserMemoryRegion)?;
.remove_user_memory_region(mem_region)
.map_err(Error::RemoveUserMemoryRegion)?;
// Mark the pages as unmergeable if there were previously marked as
// mergeable.

View File

@ -2551,7 +2551,7 @@ pub fn test_vm() {
false,
);
vm.set_user_memory_region(mem_region)
vm.create_user_memory_region(mem_region)
.expect("Cannot configure guest memory");
}
mem.write_slice(&code, load_addr)