Skip to content

Commit a849eda

Browse files
committed
switch to using kvm_userspace_region2
Fall back to kvm_user_memory_region in case the 2 version of the struct isnt supported. Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
1 parent 03606fc commit a849eda

File tree

5 files changed

+47
-16
lines changed

5 files changed

+47
-16
lines changed

src/vmm/src/devices/virtio/block/virtio/io/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ pub mod tests {
240240
)
241241
.unwrap()
242242
.into_iter()
243-
.map(|region| KvmRegion::from_mmap_region(region, 0))
243+
.map(|region| KvmRegion::from_mmap_region(region, 0, None))
244244
.collect(),
245245
)
246246
.unwrap()

src/vmm/src/devices/virtio/vhost_user.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ pub(crate) mod tests {
482482
)
483483
.unwrap()
484484
.into_iter()
485-
.map(|region| KvmRegion::from_mmap_region(region, 0))
485+
.map(|region| KvmRegion::from_mmap_region(region, 0, None))
486486
.collect(),
487487
)
488488
.unwrap()

src/vmm/src/test_utils/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub fn multi_region_mem(regions: &[(GuestAddress, usize)]) -> GuestMemoryMmap {
4747
memory::anonymous(regions.iter().copied(), false, HugePageConfig::None)
4848
.expect("Cannot initialize memory")
4949
.into_iter()
50-
.map(|region| KvmRegion::from_mmap_region(region, 0))
50+
.map(|region| KvmRegion::from_mmap_region(region, 0, None))
5151
.collect(),
5252
)
5353
.unwrap()

src/vmm/src/vstate/memory.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
use std::fs::File;
99
use std::io::{Read, Seek, SeekFrom};
1010
use std::mem::ManuallyDrop;
11+
use std::os::fd::AsRawFd;
1112
use std::sync::Arc;
1213

13-
use kvm_bindings::{KVM_MEM_LOG_DIRTY_PAGES, kvm_userspace_memory_region};
14+
use kvm_bindings::{KVM_MEM_LOG_DIRTY_PAGES, kvm_userspace_memory_region2};
1415
use serde::{Deserialize, Serialize};
1516
pub use vm_memory::bitmap::{AtomicBitmap, BS, Bitmap, BitmapSlice};
1617
pub use vm_memory::mmap::MmapRegionBuilder;
@@ -107,7 +108,7 @@ impl<S: Seek> Seek for Bounce<S> {
107108
/// A memory region, described in terms of `kvm_userspace_memory_region`
108109
#[derive(Debug)]
109110
pub struct KvmRegion {
110-
region: kvm_userspace_memory_region,
111+
region: kvm_userspace_memory_region2,
111112
bitmap: Option<AtomicBitmap>,
112113
file_offset: Option<FileOffset>,
113114
}
@@ -121,7 +122,7 @@ impl KvmRegion {
121122
/// `kvm_region.userspace_addr as *mut u8` is valid for reads and writes of length
122123
/// `kvm_region.memory_size`.
123124
pub unsafe fn new(
124-
region: kvm_userspace_memory_region,
125+
region: kvm_userspace_memory_region2,
125126
bitmap: Option<AtomicBitmap>,
126127
file_offset: Option<FileOffset>,
127128
) -> Self {
@@ -132,34 +133,46 @@ impl KvmRegion {
132133
}
133134
}
134135

135-
pub(crate) fn from_mmap_region(region: GuestRegionMmap, slot: u32) -> Self {
136+
pub(crate) fn from_mmap_region(
137+
region: GuestRegionMmap,
138+
slot: u32,
139+
guest_memfd: Option<&FileOffset>,
140+
) -> Self {
136141
let region = ManuallyDrop::new(region);
137142
let flags = if region.bitmap().is_some() {
138143
KVM_MEM_LOG_DIRTY_PAGES
139144
} else {
140145
0
141146
};
142147

148+
#[allow(clippy::cast_sign_loss)]
149+
let (guest_memfd, guest_memfd_offset) = guest_memfd
150+
.map(|fo| (fo.file().as_raw_fd() as u32, fo.start()))
151+
.unwrap_or((0, 0));
152+
143153
// SAFETY: `GuestRegionMmap` is essentially a fat pointer, and ensures that
144154
// region.as_ptr() is valid for reads and writes of length region.len(),
145155
// and by placing our region into a `ManuallyDrop` we ensure that its `Drop`
146156
// impl won't run and free the memory away from underneath us.
147157
unsafe {
148158
Self::new(
149-
kvm_userspace_memory_region {
159+
kvm_userspace_memory_region2 {
150160
slot,
151161
flags,
152162
guest_phys_addr: region.start_addr().0,
153163
memory_size: region.len(),
154164
userspace_addr: region.as_ptr() as u64,
165+
guest_memfd,
166+
guest_memfd_offset,
167+
..Default::default()
155168
},
156169
region.bitmap().clone(),
157170
region.file_offset().cloned(),
158171
)
159172
}
160173
}
161174

162-
pub(crate) fn inner(&self) -> &kvm_userspace_memory_region {
175+
pub(crate) fn inner(&self) -> &kvm_userspace_memory_region2 {
163176
&self.region
164177
}
165178
}
@@ -537,7 +550,7 @@ mod tests {
537550
regions
538551
.into_iter()
539552
.zip(0u32..) // assign dummy slots
540-
.map(|(region, slot)| KvmRegion::from_mmap_region(region, slot))
553+
.map(|(region, slot)| KvmRegion::from_mmap_region(region, slot, None))
541554
.collect(),
542555
)
543556
.unwrap()

src/vmm/src/vstate/vm.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use std::collections::HashMap;
99
use std::fs::{File, OpenOptions};
1010
use std::io::Write;
11+
use std::mem;
1112
use std::os::fd::FromRawFd;
1213
use std::path::Path;
1314
use std::sync::Arc;
@@ -185,15 +186,32 @@ impl Vm {
185186
return Err(VmError::NotEnoughMemorySlots);
186187
}
187188

188-
Ok(KvmRegion::from_mmap_region(region, next_slot))
189+
Ok(KvmRegion::from_mmap_region(region, next_slot, None))
189190
}
190191

191192
fn register_kvm_region(&mut self, region: &KvmRegion) -> Result<(), VmError> {
192-
// SAFETY: Safe because the fd is a valid KVM file descriptor.
193-
unsafe {
194-
self.fd()
195-
.set_user_memory_region(*region.inner())
196-
.map_err(VmError::SetUserMemoryRegion)?;
193+
if self.fd().check_extension(Cap::UserMemory2) {
194+
// SAFETY: Safe because the fd is a valid KVM file descriptor.
195+
unsafe {
196+
self.fd()
197+
.set_user_memory_region2(*region.inner())
198+
.map_err(VmError::SetUserMemoryRegion)?;
199+
}
200+
} else {
201+
// Something is seriously wrong if we manage to set these fields on a host that doesn't
202+
// even allow creation of guest_memfds!
203+
assert_eq!(region.inner().guest_memfd, 0);
204+
assert_eq!(region.inner().guest_memfd_offset, 0);
205+
206+
// SAFETY: We are passing a valid memory region and operate on a valid KVM FD.
207+
// transmute_copy is safe because kvm_user_memory_region is binary compatible with
208+
// the first sizeof::<kvm_user_memory_region>() fields of kvm_user_memory_region2
209+
// TODO: no transmute_copy here lol
210+
unsafe {
211+
self.fd()
212+
.set_user_memory_region(mem::transmute_copy(region.inner()))
213+
.map_err(VmError::SetUserMemoryRegion)?;
214+
}
197215
}
198216

199217
Ok(())

0 commit comments

Comments
 (0)