Skip to content

Commit 83b2f68

Browse files
committed
Implement guest page size policy
Signed-off-by: Michael Jarrett <[email protected]>
1 parent f7f159f commit 83b2f68

File tree

3 files changed

+83
-12
lines changed

3 files changed

+83
-12
lines changed

src/mmap.rs

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ pub enum Error {
7070
UnsortedMemoryRegions,
7171
}
7272

73+
/// Page configuration types for controlling allocation size and behavior
74+
#[derive(Debug, Copy, Clone, PartialEq)]
75+
pub enum PageSizePolicy {
76+
/// Base pages are the smallest page-size unit available on the system.
77+
BasePages,
78+
/// Transparent hugepages, if available, are managed by the host operating system.
79+
TransparentHugepages,
80+
/// Explicit hugepages swear a lot. Especially if the addresses aren't aligned.
81+
ExplicitHugepages,
82+
}
83+
7384
impl fmt::Display for Error {
7485
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7586
match self {
@@ -426,16 +437,44 @@ impl GuestMemoryMmap {
426437
///
427438
/// Valid memory regions are specified as a slice of (Address, Size) tuples sorted by Address.
428439
pub fn from_ranges(ranges: &[(GuestAddress, usize)]) -> result::Result<Self, Error> {
429-
Self::from_ranges_with_files(ranges.iter().map(|r| (r.0, r.1, None)))
440+
Self::from_ranges_with_options(
441+
ranges
442+
.iter()
443+
.map(|r| (r.0, r.1, PageSizePolicy::BasePages, None)),
444+
)
445+
}
446+
447+
/// Creates a container and allocates anonymous memory for guest memory regions.
448+
///
449+
/// Valid memory regions are specified as asequence of (Address, Size, PageSizePolicy)
450+
/// tuples sorted by Address.
451+
pub fn from_ranges_with_policy(
452+
ranges: &[(GuestAddress, usize, PageSizePolicy)],
453+
) -> result::Result<Self, Error> {
454+
Self::from_ranges_with_options(ranges.iter().map(|r| (r.0, r.1, r.2, None)))
455+
}
456+
457+
/// Creates a container and allocates anonymous memory for guest memory regions.
458+
///
459+
/// Valid memory regions are specified as a sequence of (Address, Size, Option<FileOffset>)
460+
/// tuples sorted by Address.
461+
pub fn from_ranges_with_files<A, T>(
462+
ranges: &[(GuestAddress, usize, Option<FileOffset>)],
463+
) -> result::Result<Self, Error> {
464+
Self::from_ranges_with_options(
465+
ranges
466+
.iter()
467+
.map(|r| (r.0, r.1, PageSizePolicy::BasePages, r.2.clone())),
468+
)
430469
}
431470

432471
/// Creates a container and allocates anonymous memory for guest memory regions.
433472
///
434473
/// Valid memory regions are specified as a sequence of (Address, Size, Option<FileOffset>)
435474
/// tuples sorted by Address.
436-
pub fn from_ranges_with_files<A, T>(ranges: T) -> result::Result<Self, Error>
475+
pub fn from_ranges_with_options<A, T>(ranges: T) -> result::Result<Self, Error>
437476
where
438-
A: Borrow<(GuestAddress, usize, Option<FileOffset>)>,
477+
A: Borrow<(GuestAddress, usize, PageSizePolicy, Option<FileOffset>)>,
439478
T: IntoIterator<Item = A>,
440479
{
441480
Self::from_regions(
@@ -444,11 +483,12 @@ impl GuestMemoryMmap {
444483
.map(|x| {
445484
let guest_base = x.borrow().0;
446485
let size = x.borrow().1;
486+
let policy = x.borrow().2;
447487

448-
if let Some(ref f_off) = x.borrow().2 {
449-
MmapRegion::from_file(f_off.clone(), size)
488+
if let Some(ref f_off) = x.borrow().3 {
489+
MmapRegion::from_file(f_off.clone(), size, policy)
450490
} else {
451-
MmapRegion::new(size)
491+
MmapRegion::new(size, policy)
452492
}
453493
.map_err(Error::MmapRegion)
454494
.and_then(|r| GuestRegionMmap::new(r, guest_base))

src/mmap_unix.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::ptr::null_mut;
1818
use std::result;
1919

2020
use crate::guest_memory::FileOffset;
21-
use crate::mmap::{check_file_offset, AsSlice};
21+
use crate::mmap::{check_file_offset, AsSlice, PageSizePolicy};
2222
use crate::volatile_memory::{self, compute_offset, VolatileMemory, VolatileSlice};
2323

2424
/// Error conditions that may arise when creating a new `MmapRegion` object.
@@ -90,6 +90,7 @@ pub struct MmapRegion {
9090
prot: i32,
9191
flags: i32,
9292
owned: bool,
93+
policy: PageSizePolicy,
9394
}
9495

9596
// Send and Sync aren't automatically inherited for the raw address pointer.
@@ -104,12 +105,13 @@ impl MmapRegion {
104105
///
105106
/// # Arguments
106107
/// * `size` - The size of the memory region in bytes.
107-
pub fn new(size: usize) -> Result<Self> {
108+
pub fn new(size: usize, policy: PageSizePolicy) -> Result<Self> {
108109
Self::build(
109110
None,
110111
size,
111112
libc::PROT_READ | libc::PROT_WRITE,
112113
libc::MAP_ANONYMOUS | libc::MAP_NORESERVE | libc::MAP_PRIVATE,
114+
policy,
113115
)
114116
}
115117

@@ -119,12 +121,13 @@ impl MmapRegion {
119121
/// * `file_offset` - The mapping will be created at offset `file_offset.start` in the file
120122
/// referred to by `file_offset.file`.
121123
/// * `size` - The size of the memory region in bytes.
122-
pub fn from_file(file_offset: FileOffset, size: usize) -> Result<Self> {
124+
pub fn from_file(file_offset: FileOffset, size: usize, policy: PageSizePolicy) -> Result<Self> {
123125
Self::build(
124126
Some(file_offset),
125127
size,
126128
libc::PROT_READ | libc::PROT_WRITE,
127129
libc::MAP_NORESERVE | libc::MAP_SHARED,
130+
policy,
128131
)
129132
}
130133

@@ -143,6 +146,7 @@ impl MmapRegion {
143146
size: usize,
144147
prot: i32,
145148
flags: i32,
149+
policy: PageSizePolicy,
146150
) -> Result<Self> {
147151
// Forbid MAP_FIXED, as it doesn't make sense in this context, and is pretty dangerous
148152
// in general.
@@ -157,6 +161,13 @@ impl MmapRegion {
157161
(-1, 0)
158162
};
159163

164+
// Support explicit (pre-reserved) hugepages if requested
165+
let flags = if policy == PageSizePolicy::ExplicitHugepages {
166+
flags | libc::MAP_HUGETLB
167+
} else {
168+
flags
169+
};
170+
160171
// This is safe because we're not allowing MAP_FIXED, and invalid parameters cannot break
161172
// Rust safety guarantees (things may change if we're mapping /dev/mem or some wacky file).
162173
let addr = unsafe { libc::mmap(null_mut(), size, prot, flags, fd, offset as libc::off_t) };
@@ -165,13 +176,21 @@ impl MmapRegion {
165176
return Err(Error::Mmap(io::Error::last_os_error()));
166177
}
167178

179+
// Support transparent hugepages if requested
180+
if policy == PageSizePolicy::TransparentHugepages {
181+
unsafe {
182+
libc::madvise(addr, size, libc::MADV_HUGEPAGE);
183+
};
184+
}
185+
168186
Ok(Self {
169187
addr: addr as *mut u8,
170188
size,
171189
file_offset,
172190
prot,
173191
flags,
174192
owned: true,
193+
policy,
175194
})
176195
}
177196

@@ -213,6 +232,7 @@ impl MmapRegion {
213232
prot,
214233
flags,
215234
owned: false,
235+
policy: PageSizePolicy::BasePages,
216236
})
217237
}
218238

@@ -248,6 +268,11 @@ impl MmapRegion {
248268
self.owned
249269
}
250270

271+
/// Returns information regarding the page size policy backing this region.
272+
pub fn policy(&self) -> PageSizePolicy {
273+
self.policy
274+
}
275+
251276
/// Checks whether this region and `other` are backed by overlapping
252277
/// [`FileOffset`](struct.FileOffset.html) objects.
253278
///

src/mmap_windows.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use libc::{c_void, size_t};
1313
use winapi::um::errhandlingapi::GetLastError;
1414

1515
use crate::guest_memory::FileOffset;
16-
use crate::mmap::AsSlice;
16+
use crate::mmap::{AsSlice, PageSizePolicy};
1717
use crate::volatile_memory::{self, compute_offset, VolatileMemory, VolatileSlice};
1818

1919
#[allow(non_snake_case)]
@@ -88,7 +88,8 @@ impl MmapRegion {
8888
///
8989
/// # Arguments
9090
/// * `size` - The size of the memory region in bytes.
91-
pub fn new(size: usize) -> io::Result<Self> {
91+
/// * `policy` - Unimplemented on Windows platforms.
92+
pub fn new(size: usize, _policy: PageSizePolicy) -> io::Result<Self> {
9293
if (size == 0) || (size > MM_HIGHEST_VAD_ADDRESS as usize) {
9394
return Err(io::Error::from_raw_os_error(libc::EINVAL));
9495
}
@@ -111,7 +112,12 @@ impl MmapRegion {
111112
/// * `file_offset` - The mapping will be created at offset `file_offset.start` in the file
112113
/// referred to by `file_offset.file`.
113114
/// * `size` - The size of the memory region in bytes.
114-
pub fn from_file(file_offset: FileOffset, size: usize) -> io::Result<Self> {
115+
/// * `policy` - Unimplemented on Windows platforms.
116+
pub fn from_file(
117+
file_offset: FileOffset,
118+
size: usize,
119+
_policy: PageSizePolicy,
120+
) -> io::Result<Self> {
115121
let handle = file_offset.file().as_raw_handle();
116122
if handle == INVALID_HANDLE_VALUE {
117123
return Err(io::Error::from_raw_os_error(libc::EBADF));

0 commit comments

Comments
 (0)