Skip to content

Commit a792bd1

Browse files
committed
test: have uffd examples utilize page_size_kib information
Have the examples and tests utilize the page size information that Firecracker sends as part of the initial UFFD payload. This allows us to get rid of the separate uffd handler examples for the 4K and 2M test cases. Signed-off-by: Patrick Roy <[email protected]>
1 parent 6ce6bc3 commit a792bd1

File tree

10 files changed

+26
-91
lines changed

10 files changed

+26
-91
lines changed

docs/snapshotting/handling-page-faults-on-snapshot-resume.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ connect/send data.
162162
### Example
163163

164164
An example of a handler process can be found
165-
[here](../../src/firecracker/examples/uffd/valid_4k_handler.rs). The process is
165+
[here](../../src/firecracker/examples/uffd/valid_handler.rs). The process is
166166
designed to tackle faults on a certain address by loading into memory the entire
167167
region that the address belongs to, but users can choose any other behavior that
168168
suits their use case best.

src/firecracker/Cargo.toml

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,12 @@ serde_json = "1.0.113"
5050
tracing = ["log-instrument", "seccompiler/tracing", "utils/tracing", "vmm/tracing"]
5151

5252
[[example]]
53-
name = "uffd_malicious_4k_handler"
54-
path = "examples/uffd/malicious_4k_handler.rs"
53+
name = "uffd_malicious_handler"
54+
path = "examples/uffd/malicious_handler.rs"
5555

5656
[[example]]
57-
name = "uffd_valid_4k_handler"
58-
path = "examples/uffd/valid_4k_handler.rs"
59-
60-
[[example]]
61-
name = "uffd_valid_2m_handler"
62-
path = "examples/uffd/valid_2m_handler.rs"
57+
name = "uffd_valid_handler"
58+
path = "examples/uffd/valid_handler.rs"
6359

6460
[[example]]
6561
name = "uffd_fault_all_handler"

src/firecracker/examples/uffd/fault_all_handler.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use std::fs::File;
1111
use std::os::unix::net::UnixListener;
1212

1313
use uffd_utils::{Runtime, UffdHandler};
14-
use utils::get_page_size;
1514

1615
fn main() {
1716
let mut args = std::env::args();
@@ -24,13 +23,8 @@ fn main() {
2423
let listener = UnixListener::bind(uffd_sock_path).expect("Cannot bind to socket path");
2524
let (stream, _) = listener.accept().expect("Cannot listen on UDS socket");
2625

27-
// Populate a single page from backing memory file.
28-
// This is just an example, probably, with the worst-case latency scenario,
29-
// of how memory can be loaded in guest RAM.
30-
let len = get_page_size().unwrap(); // page size does not matter, we fault in everything on the first fault
31-
3226
let mut runtime = Runtime::new(stream, file);
33-
runtime.run(len, |uffd_handler: &mut UffdHandler| {
27+
runtime.run(|uffd_handler: &mut UffdHandler| {
3428
// Read an event from the userfaultfd.
3529
let event = uffd_handler
3630
.read_event()

src/firecracker/examples/uffd/malicious_4k_handler.rs renamed to src/firecracker/examples/uffd/malicious_handler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ fn main() {
2323
let (stream, _) = listener.accept().expect("Cannot listen on UDS socket");
2424

2525
let mut runtime = Runtime::new(stream, file);
26-
runtime.run(4096, |uffd_handler: &mut UffdHandler| {
26+
runtime.run(|uffd_handler: &mut UffdHandler| {
2727
// Read an event from the userfaultfd.
2828
let event = uffd_handler
2929
.read_event()

src/firecracker/examples/uffd/uffd_utils.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub struct GuestRegionUffdMapping {
3030
pub size: usize,
3131
/// Offset in the backend file/buffer where the region contents are.
3232
pub offset: u64,
33+
/// The configured page size for this memory region.
34+
pub page_size_kib: usize,
3335
}
3436

3537
#[derive(Debug, Clone, Copy)]
@@ -49,18 +51,13 @@ pub struct MemRegion {
4951
#[derive(Debug)]
5052
pub struct UffdHandler {
5153
pub mem_regions: Vec<MemRegion>,
52-
page_size: usize,
54+
pub page_size: usize,
5355
backing_buffer: *const u8,
5456
uffd: Uffd,
5557
}
5658

5759
impl UffdHandler {
58-
pub fn from_unix_stream(
59-
stream: &UnixStream,
60-
page_size: usize,
61-
backing_buffer: *const u8,
62-
size: usize,
63-
) -> Self {
60+
pub fn from_unix_stream(stream: &UnixStream, backing_buffer: *const u8, size: usize) -> Self {
6461
let mut message_buf = vec![0u8; 1024];
6562
let (bytes_read, file) = stream
6663
.recv_with_fd(&mut message_buf[..])
@@ -73,6 +70,8 @@ impl UffdHandler {
7370
let mappings = serde_json::from_str::<Vec<GuestRegionUffdMapping>>(&body)
7471
.expect("Cannot deserialize memory mappings.");
7572
let memsize: usize = mappings.iter().map(|r| r.size).sum();
73+
// Page size is the same for all memory regions, so just grab the first one
74+
let page_size = mappings.first().unwrap().page_size_kib;
7675

7776
// Make sure memory size matches backing data size.
7877
assert_eq!(memsize, size);
@@ -214,7 +213,7 @@ impl Runtime {
214213
/// When uffd is polled, page fault is handled by
215214
/// calling `pf_event_dispatch` with corresponding
216215
/// uffd object passed in.
217-
pub fn run(&mut self, page_size: usize, pf_event_dispatch: impl Fn(&mut UffdHandler)) {
216+
pub fn run(&mut self, pf_event_dispatch: impl Fn(&mut UffdHandler)) {
218217
let mut pollfds = vec![];
219218

220219
// Poll the stream for incoming uffds
@@ -249,7 +248,6 @@ impl Runtime {
249248
// Handle new uffd from stream
250249
let handler = UffdHandler::from_unix_stream(
251250
&self.stream,
252-
page_size,
253251
self.backing_memory,
254252
self.backing_memory_size,
255253
);
@@ -330,7 +328,7 @@ mod tests {
330328
let (stream, _) = listener.accept().expect("Cannot listen on UDS socket");
331329
// Update runtime with actual runtime
332330
let runtime = uninit_runtime.write(Runtime::new(stream, file));
333-
runtime.run(4096, |_: &mut UffdHandler| {});
331+
runtime.run(|_: &mut UffdHandler| {});
334332
});
335333

336334
// wait for runtime thread to initialize itself
@@ -343,6 +341,7 @@ mod tests {
343341
base_host_virt_addr: 0,
344342
size: 0x1000,
345343
offset: 0,
344+
page_size_kib: 4096,
346345
}];
347346
let dummy_memory_region_json = serde_json::to_string(&dummy_memory_region).unwrap();
348347

@@ -375,6 +374,7 @@ mod tests {
375374
base_host_virt_addr: 0,
376375
size: 0,
377376
offset: 0,
377+
page_size_kib: 4096,
378378
}];
379379
let error_memory_region_json = serde_json::to_string(&error_memory_region).unwrap();
380380
stream

src/firecracker/examples/uffd/valid_2m_handler.rs

Lines changed: 0 additions & 51 deletions
This file was deleted.

src/firecracker/examples/uffd/valid_4k_handler.rs renamed to src/firecracker/examples/uffd/valid_handler.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use std::fs::File;
1111
use std::os::unix::net::UnixListener;
1212

1313
use uffd_utils::{MemPageState, Runtime, UffdHandler};
14-
use utils::get_page_size;
1514

1615
fn main() {
1716
let mut args = std::env::args();
@@ -24,13 +23,8 @@ fn main() {
2423
let listener = UnixListener::bind(uffd_sock_path).expect("Cannot bind to socket path");
2524
let (stream, _) = listener.accept().expect("Cannot listen on UDS socket");
2625

27-
// Populate a single page from backing memory file.
28-
// This is just an example, probably, with the worst-case latency scenario,
29-
// of how memory can be loaded in guest RAM.
30-
let len = get_page_size().unwrap();
31-
3226
let mut runtime = Runtime::new(stream, file);
33-
runtime.run(len, |uffd_handler: &mut UffdHandler| {
27+
runtime.run(|uffd_handler: &mut UffdHandler| {
3428
// Read an event from the userfaultfd.
3529
let event = uffd_handler
3630
.read_event()
@@ -40,7 +34,9 @@ fn main() {
4034
// We expect to receive either a Page Fault or Removed
4135
// event (if the balloon device is enabled).
4236
match event {
43-
userfaultfd::Event::Pagefault { addr, .. } => uffd_handler.serve_pf(addr.cast(), len),
37+
userfaultfd::Event::Pagefault { addr, .. } => {
38+
uffd_handler.serve_pf(addr.cast(), uffd_handler.page_size)
39+
}
4440
userfaultfd::Event::Remove { start, end } => uffd_handler.update_mem_state_mappings(
4541
start as u64,
4642
end as u64,

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ def uffd_handler_paths():
229229
"""Build UFFD handler binaries."""
230230
handlers = {
231231
f"{handler}_handler": build_tools.get_example(f"uffd_{handler}_handler")
232-
for handler in ["malicious_4k", "valid_4k", "valid_2m", "fault_all"]
232+
for handler in ["malicious", "valid", "fault_all"]
233233
}
234234
yield handlers
235235

tests/integration_tests/functional/test_uffd.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def test_valid_handler(uvm_plain, snapshot, uffd_handler_paths):
110110

111111
# Spawn page fault handler process.
112112
_pf_handler = spawn_pf_handler(
113-
vm, uffd_handler_paths["valid_4k_handler"], snapshot.mem
113+
vm, uffd_handler_paths["valid_handler"], snapshot.mem
114114
)
115115

116116
vm.restore_from_snapshot(snapshot, resume=True, uffd_path=SOCKET_PATH)
@@ -144,7 +144,7 @@ def test_malicious_handler(uvm_plain, snapshot, uffd_handler_paths):
144144

145145
# Spawn page fault handler process.
146146
_pf_handler = spawn_pf_handler(
147-
vm, uffd_handler_paths["malicious_4k_handler"], snapshot.mem
147+
vm, uffd_handler_paths["malicious_handler"], snapshot.mem
148148
)
149149

150150
# We expect Firecracker to freeze while resuming from a snapshot

tests/integration_tests/performance/test_huge_pages.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def test_hugetlbfs_snapshot(
109109

110110
# Spawn page fault handler process.
111111
_pf_handler = spawn_pf_handler(
112-
vm, uffd_handler_paths["valid_2m_handler"], snapshot.mem
112+
vm, uffd_handler_paths["valid_handler"], snapshot.mem
113113
)
114114

115115
vm.restore_from_snapshot(snapshot, resume=True, uffd_path=SOCKET_PATH)
@@ -164,7 +164,7 @@ def test_hugetlbfs_diff_snapshot(microvm_factory, uvm_plain, uffd_handler_paths)
164164

165165
# Spawn page fault handler process.
166166
_pf_handler = spawn_pf_handler(
167-
vm, uffd_handler_paths["valid_2m_handler"], snapshot_merged.mem
167+
vm, uffd_handler_paths["valid_handler"], snapshot_merged.mem
168168
)
169169

170170
vm.restore_from_snapshot(snapshot_merged, resume=True, uffd_path=SOCKET_PATH)

0 commit comments

Comments
 (0)