Skip to content

Commit bea12f4

Browse files
committed
fix(examples/uffd): unregister range on UFFD Remove event
If the handler receives a UFFD remove event, it currently stores the PFN and will reply with a zero page whenever it receives a pagefault event for that page. This works well with 4k pages, but zeropage is not supported on hugepages. In order to support hugepages, let's just unregister from UFFD whenever we get a remove event. By doing so, the handler won't receive a notification for the removed page, and the VM will get a new zero page from the kernel. Signed-off-by: Riccardo Mancini <[email protected]>
1 parent 19d2e6c commit bea12f4

File tree

2 files changed

+8
-24
lines changed

2 files changed

+8
-24
lines changed

src/firecracker/examples/uffd/on_demand_handler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ fn main() {
8787
}
8888
}
8989
userfaultfd::Event::Remove { start, end } => {
90-
uffd_handler.mark_range_removed(start as u64, end as u64)
90+
uffd_handler.unregister_range(start, end)
9191
}
9292
_ => panic!("Unexpected event on userfaultfd"),
9393
}

src/firecracker/examples/uffd/uffd_utils.rs

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
dead_code
1010
)]
1111

12-
use std::collections::{HashMap, HashSet};
12+
use std::collections::HashMap;
1313
use std::ffi::c_void;
1414
use std::fs::File;
1515
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
@@ -54,7 +54,6 @@ pub struct UffdHandler {
5454
pub page_size: usize,
5555
backing_buffer: *const u8,
5656
uffd: Uffd,
57-
removed_pages: HashSet<u64>,
5857
}
5958

6059
impl UffdHandler {
@@ -125,32 +124,25 @@ impl UffdHandler {
125124
page_size,
126125
backing_buffer,
127126
uffd,
128-
removed_pages: HashSet::new(),
129127
}
130128
}
131129

132130
pub fn read_event(&mut self) -> Result<Option<Event>, Error> {
133131
self.uffd.read_event()
134132
}
135133

136-
pub fn mark_range_removed(&mut self, start: u64, end: u64) {
137-
let pfn_start = start / self.page_size as u64;
138-
let pfn_end = end / self.page_size as u64;
139-
140-
for pfn in pfn_start..pfn_end {
141-
self.removed_pages.insert(pfn);
142-
}
134+
pub fn unregister_range(&mut self, start: *mut c_void, end: *mut c_void) {
135+
// SAFETY: start and end are valid and provided by UFFD
136+
let len = unsafe { end.offset_from_unsigned(start) };
137+
self.uffd
138+
.unregister(start, len)
139+
.expect("range should be valid");
143140
}
144141

145142
pub fn serve_pf(&mut self, addr: *mut u8, len: usize) -> bool {
146143
// Find the start of the page that the current faulting address belongs to.
147144
let dst = (addr as usize & !(self.page_size - 1)) as *mut libc::c_void;
148145
let fault_page_addr = dst as u64;
149-
let fault_pfn = fault_page_addr / self.page_size as u64;
150-
151-
if self.removed_pages.contains(&fault_pfn) {
152-
return self.zero_out(fault_page_addr);
153-
}
154146

155147
for region in self.mem_regions.iter() {
156148
if region.contains(fault_page_addr) {
@@ -193,14 +185,6 @@ impl UffdHandler {
193185

194186
true
195187
}
196-
197-
fn zero_out(&mut self, addr: u64) -> bool {
198-
match unsafe { self.uffd.zeropage(addr as *mut _, self.page_size, true) } {
199-
Ok(_) => true,
200-
Err(Error::ZeropageFailed(error)) if error as i32 == libc::EAGAIN => false,
201-
r => panic!("Unexpected zeropage result: {:?}", r),
202-
}
203-
}
204188
}
205189

206190
#[derive(Debug)]

0 commit comments

Comments
 (0)