Skip to content

Commit fa424ca

Browse files
author
Hui Zhu
committed
Add get_host_address_and_hugepages() to GuestMemory
Virtio-balloon can release the unused host memory to decrease the memory usage of the VMM. Release normal pages and hugepages require different operations. (madvise MADV_DONTNEED and fallocate64 FALLOC_FL_PUNCH_HOLE) This commit add get_host_address_and_hugepages() to GuestMemory to help VMM decide if this is a hugepages address or not. Signed-off-by: Hui Zhu <[email protected]>
1 parent 54c8934 commit fa424ca

File tree

4 files changed

+114
-3
lines changed

4 files changed

+114
-3
lines changed

src/guest_memory.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
288288
fn as_volatile_slice(&self) -> Result<volatile_memory::VolatileSlice> {
289289
self.get_slice(MemoryRegionAddress(0), self.len() as usize)
290290
}
291+
292+
/// Returns true if the region is hugepages
293+
fn is_hugepages(&self) -> bool {
294+
false
295+
}
291296
}
292297

293298
/// `GuestAddressSpace` provides a way to retrieve a `GuestMemory` object.
@@ -614,6 +619,13 @@ pub trait GuestMemory {
614619
.and_then(|(r, addr)| r.get_host_address(addr))
615620
}
616621

622+
/// Get the host virtual address corresponding to the guest address and the hugepages.
623+
fn get_host_address_and_hugepages(&self, addr: GuestAddress) -> Result<(*mut u8, bool)> {
624+
self.to_region_addr(addr)
625+
.ok_or_else(|| Error::InvalidGuestAddress(addr))
626+
.and_then(|(r, addr)| Ok((r.get_host_address(addr)?, r.is_hugepages())))
627+
}
628+
617629
/// Returns a [`VolatileSlice`](struct.VolatileSlice.html) of `count` bytes starting at
618630
/// `addr`.
619631
fn get_slice(

src/mmap.rs

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,10 @@ impl GuestMemoryRegion for GuestRegionMmap {
403403
let slice = self.mapping.get_slice(offset.raw_value() as usize, count)?;
404404
Ok(slice)
405405
}
406+
407+
fn is_hugepages(&self) -> bool {
408+
self.mapping.hugepages()
409+
}
406410
}
407411

408412
/// [`GuestMemory`](trait.GuestMemory.html) implementation that mmaps the guest's memory
@@ -434,6 +438,22 @@ impl GuestMemoryMmap {
434438
/// Valid memory regions are specified as a sequence of (Address, Size, Option<FileOffset>)
435439
/// tuples sorted by Address.
436440
pub fn from_ranges_with_files<A, T>(ranges: T) -> result::Result<Self, Error>
441+
where
442+
A: Borrow<(GuestAddress, usize, Option<FileOffset>)>,
443+
T: IntoIterator<Item = A>,
444+
{
445+
Self::from_ranges_with_files_and_hugepages(ranges, false)
446+
}
447+
448+
/// Creates a container and allocates anonymous memory for guest memory regions.
449+
/// And set guest memory regions hugepages.
450+
///
451+
/// Valid memory regions are specified as a sequence of (Address, Size, Option<FileOffset>)
452+
/// tuples sorted by Address.
453+
pub fn from_ranges_with_files_and_hugepages<A, T>(
454+
ranges: T,
455+
hugepages: bool,
456+
) -> result::Result<Self, Error>
437457
where
438458
A: Borrow<(GuestAddress, usize, Option<FileOffset>)>,
439459
T: IntoIterator<Item = A>,
@@ -445,13 +465,15 @@ impl GuestMemoryMmap {
445465
let guest_base = x.borrow().0;
446466
let size = x.borrow().1;
447467

448-
if let Some(ref f_off) = x.borrow().2 {
468+
let mut r = if let Some(ref f_off) = x.borrow().2 {
449469
MmapRegion::from_file(f_off.clone(), size)
450470
} else {
451471
MmapRegion::new(size)
452472
}
453-
.map_err(Error::MmapRegion)
454-
.and_then(|r| GuestRegionMmap::new(r, guest_base))
473+
.map_err(Error::MmapRegion)?;
474+
r.set_hugepages(hugepages);
475+
476+
GuestRegionMmap::new(r, guest_base)
455477
})
456478
.collect::<result::Result<Vec<_>, Error>>()?,
457479
)
@@ -989,6 +1011,64 @@ mod tests {
9891011
}
9901012
}
9911013

1014+
#[cfg(all(feature = "backend-mmap", unix))]
1015+
#[test]
1016+
fn test_get_host_address_and_hugepages() {
1017+
let f1 = TempFile::new().unwrap().into_file();
1018+
f1.set_len(0x400).unwrap();
1019+
let f2 = TempFile::new().unwrap().into_file();
1020+
f2.set_len(0x400).unwrap();
1021+
1022+
let start_addr1 = GuestAddress(0x0);
1023+
let start_addr2 = GuestAddress(0x800);
1024+
let guest_mem =
1025+
GuestMemoryMmap::from_ranges(&[(start_addr1, 0x400), (start_addr2, 0x400)]).unwrap();
1026+
let guest_mem_backed_by_file = GuestMemoryMmap::from_ranges_with_files_and_hugepages(
1027+
&[
1028+
(start_addr1, 0x400, Some(FileOffset::new(f1, 0))),
1029+
(start_addr2, 0x400, Some(FileOffset::new(f2, 0))),
1030+
],
1031+
true,
1032+
)
1033+
.unwrap();
1034+
1035+
let guest_mem_list = vec![guest_mem];
1036+
for guest_mem in guest_mem_list.iter() {
1037+
assert!(guest_mem.get_host_address(GuestAddress(0x600)).is_err());
1038+
let (ptr0, ptr0_huge) = guest_mem
1039+
.get_host_address_and_hugepages(GuestAddress(0x800))
1040+
.unwrap();
1041+
let (ptr1, ptr1_huge) = guest_mem
1042+
.get_host_address_and_hugepages(GuestAddress(0xa00))
1043+
.unwrap();
1044+
assert_eq!(
1045+
ptr0,
1046+
guest_mem.find_region(GuestAddress(0x800)).unwrap().as_ptr()
1047+
);
1048+
assert_eq!(ptr0_huge, false);
1049+
assert_eq!(ptr1_huge, false);
1050+
assert_eq!(unsafe { ptr0.offset(0x200) }, ptr1);
1051+
}
1052+
1053+
let guest_mem_list = vec![guest_mem_backed_by_file];
1054+
for guest_mem in guest_mem_list.iter() {
1055+
assert!(guest_mem.get_host_address(GuestAddress(0x600)).is_err());
1056+
let (ptr0, ptr0_huge) = guest_mem
1057+
.get_host_address_and_hugepages(GuestAddress(0x800))
1058+
.unwrap();
1059+
let (ptr1, ptr1_huge) = guest_mem
1060+
.get_host_address_and_hugepages(GuestAddress(0xa00))
1061+
.unwrap();
1062+
assert_eq!(
1063+
ptr0,
1064+
guest_mem.find_region(GuestAddress(0x800)).unwrap().as_ptr()
1065+
);
1066+
assert_eq!(ptr0_huge, true);
1067+
assert_eq!(ptr1_huge, true);
1068+
assert_eq!(unsafe { ptr0.offset(0x200) }, ptr1);
1069+
}
1070+
}
1071+
9921072
#[test]
9931073
fn test_deref() {
9941074
let f = TempFile::new().unwrap().into_file();

src/mmap_unix.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ pub struct MmapRegion {
9090
prot: i32,
9191
flags: i32,
9292
owned: bool,
93+
hugepages: bool,
9394
}
9495

9596
// Send and Sync aren't automatically inherited for the raw address pointer.
@@ -172,6 +173,7 @@ impl MmapRegion {
172173
prot,
173174
flags,
174175
owned: true,
176+
hugepages: false,
175177
})
176178
}
177179

@@ -213,6 +215,7 @@ impl MmapRegion {
213215
prot,
214216
flags,
215217
owned: false,
218+
hugepages: false,
216219
})
217220
}
218221

@@ -248,6 +251,16 @@ impl MmapRegion {
248251
self.owned
249252
}
250253

254+
/// Set the hugepages of the region
255+
pub fn set_hugepages(&mut self, hugepages: bool) {
256+
self.hugepages = hugepages
257+
}
258+
259+
/// Returns `true` if the region is hugepages
260+
pub fn hugepages(&self) -> bool {
261+
self.hugepages
262+
}
263+
251264
/// Checks whether this region and `other` are backed by overlapping
252265
/// [`FileOffset`](struct.FileOffset.html) objects.
253266
///

src/mmap_windows.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ impl MmapRegion {
175175
pub fn file_offset(&self) -> Option<&FileOffset> {
176176
self.file_offset.as_ref()
177177
}
178+
179+
pub fn set_hugepages(&mut self, _hugepages: bool) {}
180+
181+
pub fn hugepages(&self) -> bool {
182+
false
183+
}
178184
}
179185

180186
impl AsSlice for MmapRegion {

0 commit comments

Comments
 (0)