Skip to content

Commit cab5150

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 1f26f45 commit cab5150

File tree

5 files changed

+50
-18
lines changed

5 files changed

+50
-18
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, Write};
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;
@@ -115,7 +115,7 @@ impl<S: Seek> Seek for Bounce<S> {
115115
/// A memory region, described in terms of `kvm_userspace_memory_region`
116116
#[derive(Debug)]
117117
pub struct KvmRegion {
118-
region: kvm_userspace_memory_region,
118+
region: kvm_userspace_memory_region2,
119119
bitmap: Option<AtomicBitmap>,
120120
file_offset: Option<FileOffset>,
121121
}
@@ -129,7 +129,7 @@ impl KvmRegion {
129129
/// `kvm_region.userspace_addr as *mut u8` is valid for reads and writes of length
130130
/// `kvm_region.memory_size`.
131131
pub unsafe fn new(
132-
region: kvm_userspace_memory_region,
132+
region: kvm_userspace_memory_region2,
133133
bitmap: Option<AtomicBitmap>,
134134
file_offset: Option<FileOffset>,
135135
) -> Self {
@@ -140,34 +140,46 @@ impl KvmRegion {
140140
}
141141
}
142142

143-
pub(crate) fn from_mmap_region(region: GuestRegionMmap, slot: u32) -> Self {
143+
pub(crate) fn from_mmap_region(
144+
region: GuestRegionMmap,
145+
slot: u32,
146+
guest_memfd: Option<&FileOffset>,
147+
) -> Self {
144148
let region = ManuallyDrop::new(region);
145149
let flags = if region.bitmap().is_some() {
146150
KVM_MEM_LOG_DIRTY_PAGES
147151
} else {
148152
0
149153
};
150154

155+
#[allow(clippy::cast_sign_loss)]
156+
let (guest_memfd, guest_memfd_offset) = guest_memfd
157+
.map(|fo| (fo.file().as_raw_fd() as u32, fo.start()))
158+
.unwrap_or((0, 0));
159+
151160
// SAFETY: `GuestRegionMmap` is essentially a fat pointer, and ensures that
152161
// region.as_ptr() is valid for reads and writes of length region.len(),
153162
// and by placing our region into a `ManuallyDrop` we ensure that its `Drop`
154163
// impl won't run and free the memory away from underneath us.
155164
unsafe {
156165
Self::new(
157-
kvm_userspace_memory_region {
166+
kvm_userspace_memory_region2 {
158167
slot,
159168
flags,
160169
guest_phys_addr: region.start_addr().0,
161170
memory_size: region.len(),
162171
userspace_addr: region.as_ptr() as u64,
172+
guest_memfd,
173+
guest_memfd_offset,
174+
..Default::default()
163175
},
164176
region.bitmap().clone(),
165177
region.file_offset().cloned(),
166178
)
167179
}
168180
}
169181

170-
pub(crate) fn inner(&self) -> &kvm_userspace_memory_region {
182+
pub(crate) fn inner(&self) -> &kvm_userspace_memory_region2 {
171183
&self.region
172184
}
173185
}
@@ -546,7 +558,7 @@ mod tests {
546558
regions
547559
.into_iter()
548560
.zip(0u32..) // assign dummy slots
549-
.map(|(region, slot)| KvmRegion::from_mmap_region(region, slot))
561+
.map(|(region, slot)| KvmRegion::from_mmap_region(region, slot, None))
550562
.collect(),
551563
)
552564
.unwrap()

src/vmm/src/vstate/vm.rs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::os::fd::FromRawFd;
1212
use std::path::Path;
1313
use std::sync::Arc;
1414

15-
use kvm_bindings::kvm_create_guest_memfd;
15+
use kvm_bindings::{kvm_create_guest_memfd, kvm_userspace_memory_region};
1616
use kvm_ioctls::{Cap, VmFd};
1717
use userfaultfd::{FeatureFlags, Uffd, UffdBuilder};
1818
use vmm_sys_util::eventfd::EventFd;
@@ -186,15 +186,35 @@ impl Vm {
186186
return Err(VmError::NotEnoughMemorySlots);
187187
}
188188

189-
Ok(KvmRegion::from_mmap_region(region, next_slot))
189+
Ok(KvmRegion::from_mmap_region(region, next_slot, None))
190190
}
191191

192192
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)?;
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+
unsafe {
208+
self.fd()
209+
.set_user_memory_region(kvm_userspace_memory_region {
210+
slot: region.inner().slot,
211+
flags: region.inner().flags,
212+
guest_phys_addr: region.inner().guest_phys_addr,
213+
memory_size: region.inner().memory_size,
214+
userspace_addr: region.inner().userspace_addr,
215+
})
216+
.map_err(VmError::SetUserMemoryRegion)?;
217+
}
198218
}
199219

200220
Ok(())

0 commit comments

Comments
 (0)