Skip to content

Commit 0a024c4

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 2f694f0 commit 0a024c4

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
@@ -48,7 +48,7 @@ pub fn multi_region_mem(regions: &[(GuestAddress, usize)]) -> GuestMemoryMmap {
4848
memory::anonymous(regions.iter().copied(), false, HugePageConfig::None)
4949
.expect("Cannot initialize memory")
5050
.into_iter()
51-
.map(|region| KvmRegion::from_mmap_region(region, 0))
51+
.map(|region| KvmRegion::from_mmap_region(region, 0, None))
5252
.collect(),
5353
)
5454
.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;
@@ -106,7 +107,7 @@ impl<S: Seek> Seek for Bounce<S> {
106107
/// A memory region, described in terms of `kvm_userspace_memory_region`
107108
#[derive(Debug)]
108109
pub struct KvmRegion {
109-
region: kvm_userspace_memory_region,
110+
region: kvm_userspace_memory_region2,
110111
bitmap: Option<AtomicBitmap>,
111112
file_offset: Option<FileOffset>,
112113
}
@@ -120,7 +121,7 @@ impl KvmRegion {
120121
/// `kvm_region.userspace_addr as *mut u8` is valid for reads and writes of length
121122
/// `kvm_region.memory_size`.
122123
pub unsafe fn new(
123-
region: kvm_userspace_memory_region,
124+
region: kvm_userspace_memory_region2,
124125
bitmap: Option<AtomicBitmap>,
125126
file_offset: Option<FileOffset>,
126127
) -> Self {
@@ -131,34 +132,46 @@ impl KvmRegion {
131132
}
132133
}
133134

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

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

161-
pub(crate) fn inner(&self) -> &kvm_userspace_memory_region {
174+
pub(crate) fn inner(&self) -> &kvm_userspace_memory_region2 {
162175
&self.region
163176
}
164177
}
@@ -536,7 +549,7 @@ mod tests {
536549
regions
537550
.into_iter()
538551
.zip(0u32..) // assign dummy slots
539-
.map(|(region, slot)| KvmRegion::from_mmap_region(region, slot))
552+
.map(|(region, slot)| KvmRegion::from_mmap_region(region, slot, None))
540553
.collect(),
541554
)
542555
.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;
@@ -186,15 +187,32 @@ impl Vm {
186187
return Err(VmError::NotEnoughMemorySlots);
187188
}
188189

189-
Ok(KvmRegion::from_mmap_region(region, next_slot))
190+
Ok(KvmRegion::from_mmap_region(region, next_slot, None))
190191
}
191192

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

200218
Ok(())

0 commit comments

Comments
 (0)