diff --git a/vm-virtio/src/device.rs b/vm-virtio/src/device.rs index a5d7699f8..ab05ef073 100644 --- a/vm-virtio/src/device.rs +++ b/vm-virtio/src/device.rs @@ -42,6 +42,8 @@ pub struct VirtioSharedMemory { #[derive(Clone)] pub struct VirtioSharedMemoryList { + pub host_addr: u64, + pub mem_slot: u32, pub addr: GuestAddress, pub len: GuestUsize, pub region_list: Vec, @@ -97,6 +99,14 @@ pub trait VirtioDevice: Send { None } + /// Updates the list of shared memory regions required by the device. + fn set_shm_regions( + &mut self, + _shm_regions: VirtioSharedMemoryList, + ) -> std::result::Result<(), Error> { + std::unimplemented!() + } + fn iommu_translate(&self, addr: u64) -> u64 { addr } diff --git a/vm-virtio/src/lib.rs b/vm-virtio/src/lib.rs index ba32d708a..68958c3c3 100755 --- a/vm-virtio/src/lib.rs +++ b/vm-virtio/src/lib.rs @@ -186,4 +186,5 @@ pub enum Error { FailedSignalingDriver(io::Error), VhostUserUpdateMemory(vhost_user::Error), EventfdError(io::Error), + SetShmRegionsNotSupported, } diff --git a/vm-virtio/src/vhost_user/fs.rs b/vm-virtio/src/vhost_user/fs.rs index 4bfbbecd7..31095859c 100644 --- a/vm-virtio/src/vhost_user/fs.rs +++ b/vm-virtio/src/vhost_user/fs.rs @@ -261,7 +261,7 @@ pub struct Fs { pause_evt: Option, // Hold ownership of the memory that is allocated for the device // which will be automatically dropped when the device is dropped - cache: Option<(VirtioSharedMemoryList, u64, MmapRegion)>, + cache: Option<(VirtioSharedMemoryList, MmapRegion)>, slave_req_support: bool, queue_evts: Option>, interrupt_cb: Option>, @@ -276,7 +276,7 @@ impl Fs { tag: &str, req_num_queues: usize, queue_size: u16, - cache: Option<(VirtioSharedMemoryList, u64, MmapRegion)>, + cache: Option<(VirtioSharedMemoryList, MmapRegion)>, ) -> Result { let mut slave_req_support = false; @@ -478,7 +478,7 @@ impl VirtioDevice for Fs { let vu_master_req_handler = Arc::new(Mutex::new(SlaveReqHandler { cache_offset: cache.0.addr, cache_size: cache.0.len, - mmap_cache_addr: cache.1, + mmap_cache_addr: cache.0.host_addr, })); let req_handler = MasterReqHandler::new(vu_master_req_handler).map_err(|e| { @@ -552,6 +552,18 @@ impl VirtioDevice for Fs { } } + fn set_shm_regions( + &mut self, + shm_regions: VirtioSharedMemoryList, + ) -> std::result::Result<(), crate::Error> { + if let Some(mut cache) = self.cache.as_mut() { + cache.0 = shm_regions; + Ok(()) + } else { + Err(crate::Error::SetShmRegionsNotSupported) + } + } + fn update_memory(&mut self, mem: &GuestMemoryMmap) -> std::result::Result<(), crate::Error> { update_mem_table(&mut self.vu, mem).map_err(crate::Error::VhostUserUpdateMemory) } diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index d7dd1fb19..7d32ff301 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -450,6 +450,48 @@ impl DeviceRelocation for AddressManager { .register_ioevent(event, &io_addr, NoDatamatch) .map_err(|e| io::Error::from_raw_os_error(e.errno()))?; } + } else { + let virtio_dev = virtio_pci_dev.virtio_device(); + 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 mut mem_region = kvm_bindings::kvm_userspace_memory_region { + slot: shm_regions.mem_slot, + guest_phys_addr: old_base, + memory_size: 0, + userspace_addr: shm_regions.host_addr, + flags: 0, + }; + + // Safe because removing an existing guest region. + unsafe { + self.vm_fd + .set_user_memory_region(mem_region) + .map_err(|e| io::Error::from_raw_os_error(e.errno()))?; + } + + // Create new mapping by inserting new region to KVM. + mem_region.guest_phys_addr = new_base; + mem_region.memory_size = shm_regions.len; + + // Safe because the guest regions are guaranteed not to overlap. + unsafe { + self.vm_fd + .set_user_memory_region(mem_region) + .map_err(|e| io::Error::from_raw_os_error(e.errno()))?; + } + + // Update shared memory regions to reflect the new mapping. + shm_regions.addr = GuestAddress(new_base); + virtio_dev.set_shm_regions(shm_regions).map_err(|e| { + io::Error::new( + io::ErrorKind::Other, + format!("failed to update shared memory regions: {:?}", e), + ) + })?; + } + } } } @@ -1403,15 +1445,16 @@ impl DeviceManager { libc::MAP_ANONYMOUS | libc::MAP_PRIVATE, ) .map_err(DeviceManagerError::NewMmapRegion)?; - let addr: u64 = mmap_region.as_ptr() as u64; + let host_addr: u64 = mmap_region.as_ptr() as u64; - self.memory_manager + let mem_slot = self + .memory_manager .lock() .unwrap() .create_userspace_mapping( fs_guest_addr.raw_value(), fs_cache, - addr, + host_addr, false, false, ) @@ -1425,11 +1468,12 @@ impl DeviceManager { Some(( VirtioSharedMemoryList { + host_addr, + mem_slot, addr: fs_guest_addr, len: fs_cache as GuestUsize, region_list, }, - addr, mmap_region, )) } else {