Skip to content

Commit 4e934af

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 ada71a1 commit 4e934af

File tree

5 files changed

+47
-17
lines changed

5 files changed

+47
-17
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 & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
use std::fs::File;
99
use std::io::{Read, Seek, SeekFrom};
1010
use std::mem::ManuallyDrop;
11-
use std::os::fd::AsFd;
11+
use std::os::fd::{AsFd, AsRawFd};
1212
use std::sync::Arc;
1313

14-
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};
1515
use serde::{Deserialize, Serialize};
1616
pub use vm_memory::bitmap::{AtomicBitmap, BS, Bitmap, BitmapSlice};
1717
pub use vm_memory::mmap::MmapRegionBuilder;
@@ -98,7 +98,7 @@ impl<S: Seek> Seek for Bounce<S> {
9898
/// A memory region, described in terms of `kvm_userspace_memory_region`
9999
#[derive(Debug)]
100100
pub struct KvmRegion {
101-
region: kvm_userspace_memory_region,
101+
region: kvm_userspace_memory_region2,
102102
bitmap: Option<AtomicBitmap>,
103103
file_offset: Option<FileOffset>,
104104
}
@@ -112,7 +112,7 @@ impl KvmRegion {
112112
/// `kvm_region.userspace_addr as *mut u8` is valid for reads and writes of length
113113
/// `kvm_region.memory_size`.
114114
pub unsafe fn new(
115-
region: kvm_userspace_memory_region,
115+
region: kvm_userspace_memory_region2,
116116
bitmap: Option<AtomicBitmap>,
117117
file_offset: Option<FileOffset>,
118118
) -> Self {
@@ -123,34 +123,46 @@ impl KvmRegion {
123123
}
124124
}
125125

126-
pub(crate) fn from_mmap_region(region: GuestRegionMmap, slot: u32) -> Self {
126+
pub(crate) fn from_mmap_region(
127+
region: GuestRegionMmap,
128+
slot: u32,
129+
guest_memfd: Option<&FileOffset>,
130+
) -> Self {
127131
let region = ManuallyDrop::new(region);
128132
let flags = if region.bitmap().is_some() {
129133
KVM_MEM_LOG_DIRTY_PAGES
130134
} else {
131135
0
132136
};
133137

138+
#[allow(clippy::cast_sign_loss)]
139+
let (guest_memfd, guest_memfd_offset) = guest_memfd
140+
.map(|fo| (fo.file().as_raw_fd() as u32, fo.start()))
141+
.unwrap_or((0, 0));
142+
134143
// SAFETY: `GuestRegionMmap` is essentially a fat pointer, and ensures that
135144
// region.as_ptr() is valid for reads and writes of length region.len(),
136145
// and by placing our region into a `ManuallyDrop` we ensure that its `Drop`
137146
// impl won't run and free the memory away from underneath us.
138147
unsafe {
139148
Self::new(
140-
kvm_userspace_memory_region {
149+
kvm_userspace_memory_region2 {
141150
slot,
142151
flags,
143152
guest_phys_addr: region.start_addr().0,
144153
memory_size: region.len(),
145154
userspace_addr: region.as_ptr() as u64,
155+
guest_memfd,
156+
guest_memfd_offset,
157+
..Default::default()
146158
},
147159
region.bitmap().clone(),
148160
region.file_offset().cloned(),
149161
)
150162
}
151163
}
152164

153-
pub(crate) fn inner(&self) -> &kvm_userspace_memory_region {
165+
pub(crate) fn inner(&self) -> &kvm_userspace_memory_region2 {
154166
&self.region
155167
}
156168
}
@@ -528,7 +540,7 @@ mod tests {
528540
regions
529541
.into_iter()
530542
.zip(0u32..) // assign dummy slots
531-
.map(|(region, slot)| KvmRegion::from_mmap_region(region, slot))
543+
.map(|(region, slot)| KvmRegion::from_mmap_region(region, slot, None))
532544
.collect(),
533545
)
534546
.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)