Skip to content
This repository was archived by the owner on Mar 24, 2022. It is now read-only.

Commit a6da170

Browse files
acfoltzertyler
authored andcommitted
add some uffd documentation and metadata, panickify a couple errors
Leaving the question of errors in the handler alone for this commit, since that'll be a more major change.
1 parent 34eca38 commit a6da170

File tree

4 files changed

+48
-34
lines changed

4 files changed

+48
-34
lines changed

lucet-runtime/Cargo.toml

+5-3
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ assets = [
4949
]
5050

5151
[features]
52-
default = []
53-
54-
concurrent_testpoints = []
52+
default-features = []
5553
uffd = ["lucet-runtime-internals/uffd"]
54+
concurrent_testpoints = []
55+
56+
[package.metadata.docs.rs]
57+
features = ["uffd"]

lucet-runtime/lucet-runtime-internals/Cargo.toml

+5-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ byteorder = "1.2"
3737
cc = "1.0"
3838

3939
[features]
40-
default = []
40+
default-features = []
4141

42-
concurrent_testpoints = []
4342
uffd = ["userfaultfd"]
43+
concurrent_testpoints = []
44+
45+
[package.metadata.docs.rs]
46+
features = ["uffd"]

lucet-runtime/lucet-runtime-internals/src/region/uffd.rs

+24-28
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
//! Region backend for `lucet-runtime` backed by
2-
//! [`userfaultfd(2)`](http://man7.org/linux/man-pages/man2/userfaultfd.2.html) via the
3-
//! `userfaultfd-rs` crate.
4-
51
use crate::alloc::{host_page_size, instance_heap_offset, AddrLocation, Alloc, Limits, Slot};
62
use crate::embed_ctx::CtxMap;
73
use crate::error::Error;
@@ -18,32 +14,32 @@ use std::sync::{Arc, Mutex, Weak};
1814
use std::thread::{self, JoinHandle};
1915
use userfaultfd::{IoctlFlags, Uffd, UffdBuilder};
2016

21-
/// A [`Region`](../trait.Region.html) backed by `mmap` and managed by `userfaultfd`.
17+
/// A [`Region`](trait.Region.html) backed by `mmap` and managed by `userfaultfd`.
2218
///
23-
/// Much like [`MmapRegion`](../mmap/struct.MmapRegion.html) `UffdRegion` lays out virtual memory
24-
/// in a contiguous block. See [`MmapRegion`](../mmap/struct.MmapRegion.html) for details of the
25-
/// memory layout.
19+
/// Much like [`MmapRegion`](struct.MmapRegion.html) `UffdRegion` lays out virtual memory in a
20+
/// contiguous block. See [`MmapRegion`](struct.MmapRegion.html) for details of the memory layout.
2621
///
27-
/// The difference is that `UffdRegion` is lazy. Only the minimum required physical memory is set
28-
/// up to back that virtual memory before an `Instance` begins running. The stack and the heap
29-
/// are both lazily allocated at runtime.
22+
/// The difference is that `UffdRegion` is lazy. Only the minimum required physical memory is set up
23+
/// to back that virtual memory before an `Instance` begins running. The stack and the heap are both
24+
/// lazily allocated at runtime.
3025
///
31-
/// That lazy allocation is handled by the [`userfaultfd`](http://man7.org/linux/man-pages/man2/userfaultfd.2.html)
32-
/// system in recent Linux kernels. The entire Region is registered with `userfaultfd` handle.
33-
/// When page faults occur due to attempts by the `Guest` to access the lazy memory, the `Guest`
34-
/// thread is paused and a message is sent over the `userfaultfd` handle.
26+
/// That lazy allocation is handled by the [`userfaultfd`][userfaultfd] system, using extensions
27+
/// available in Linux version 4.11 or newer. The entire `Region` is registered with `userfaultfd`
28+
/// handle. When page faults occur due to attempts by the guest to access the lazy memory, the
29+
/// guest thread is paused and a message is sent over the `userfaultfd` handle.
3530
///
36-
/// That message is picked up a separate thread which has the job of handling page faults. How
37-
/// it is handled is dependent on where the page fault occurred. In the case where it occurs in
38-
/// the stack, we just zero out the page. In the case it occurs in the heap, it is handled
39-
/// differently depending on whether the page should contain data defined in the WebAssembly
40-
/// module. In the case it should be blank we again just zero it out. In the case that it should
41-
/// contain data, we copy the data into the page. In any case we finish by reawakening the `Guest`
42-
/// thread.
31+
/// That message is picked up a separate thread which has the job of handling page faults. How it is
32+
/// handled is dependent on where the page fault occurred. In the case where it occurs in the stack,
33+
/// we just zero out the page. In the case it occurs in the heap, it is handled differently
34+
/// depending on whether the page should contain data defined in the WebAssembly module. In the case
35+
/// it should be blank we again just zero it out. In the case that it should contain data, we copy
36+
/// the data into the page. In any case we finish by reawakening the guest thread.
4337
///
4438
/// If the fault occurs in a guard page, we do nothing, and reawaken the thread without allocating
45-
/// the backing physical memory. This ends up causing the `Guest` thread to throw a SIGBUS. Which
46-
/// is caught and handled as normal.
39+
/// the backing physical memory. This ends up causing the guest thread to raise a SIGBUS, which is
40+
/// treated as a fatal error by the Lucet signal handler.
41+
///
42+
/// [userfaultfd]: http://man7.org/linux/man-pages/man2/userfaultfd.2.html
4743
pub struct UffdRegion {
4844
uffd: Arc<Uffd>,
4945
start: *mut c_void,
@@ -380,7 +376,7 @@ impl UffdRegion {
380376
/// Create a new `UffdRegion` that can support a given number of instances, each subject to the
381377
/// same runtime limits.
382378
///
383-
/// The region is turned in an `Arc`, because any instances created from it carry a reference
379+
/// The region is returned in an `Arc`, because any instances created from it carry a reference
384380
/// back to the region.
385381
///
386382
/// This also creates and starts a separate thread that is responsible for handling page faults
@@ -406,7 +402,7 @@ impl UffdRegion {
406402
if let Some(sz) = instance_capacity.checked_mul(limits.total_memory_size()) {
407403
sz
408404
} else {
409-
lucet_bail!("region size overflowed");
405+
return Err(Error::InvalidArgument("requested region size too large"));
410406
};
411407
let start = unsafe {
412408
mmap(
@@ -424,7 +420,7 @@ impl UffdRegion {
424420
.register(start, total_region_size)
425421
.map_err(|e| Error::InternalError(e.into()))?;
426422
if !ioctls.contains(IoctlFlags::WAKE | IoctlFlags::COPY | IoctlFlags::ZEROPAGE) {
427-
lucet_bail!("required uffd ioctls not supported; found: {:?}", ioctls);
423+
panic!("required uffd ioctls not supported; found: {:?}", ioctls);
428424
}
429425

430426
let (handler_pipe_recv, handler_pipe) = nix::unistd::pipe()?;
@@ -464,7 +460,7 @@ impl UffdRegion {
464460
}
465461
res
466462
})
467-
.map_err(|e| lucet_format_err!("error spawning uffd region handler: {}", e))?;
463+
.expect("error spawning uffd region handler");
468464

469465
let region = Arc::new(UffdRegion {
470466
uffd,

lucet-runtime/src/lib.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
//! [`InstanceHandle`](struct.InstanceHandle.html) smart pointer.
2424
//!
2525
//! - [`Region`](trait.Region.html): the memory from which instances are created. This crate
26-
//! includes [`MmapRegion`](struct.MmapRegion.html), an implementation backed by `mmap`.
26+
//! includes [`MmapRegion`](struct.MmapRegion.html), an implementation backed by `mmap`, and
27+
//! optionally [`UffdRegion`](struct.UffdRegion.html), which is backed by the
28+
//! [`userfaultfd`](http://man7.org/linux/man-pages/man2/userfaultfd.2.html) feature available on
29+
//! newer Linux kernels ([see below](index.html#userfaultfd-backed-region)).
2730
//!
2831
//! - [`Limits`](struct.Limits.html): upper bounds for the resources a Lucet instance may
2932
//! consume. These may be larger or smaller than the limits described in the WebAssembly module
@@ -374,6 +377,16 @@
374377
//! this number could change between Lucet releases or even Rust compiler versions.
375378
//!
376379
//! [default-sigstack-size]: constant.DEFAULT_SIGNAL_STACK_SIZE.html
380+
//!
381+
//! ## `userfaultfd`-Backed Region
382+
//!
383+
//! [`UffdRegion`](struct.UffdRegion.html) is a [`Region`](trait.Region.html) backed by the
384+
//! [`userfaultfd`](http://man7.org/linux/man-pages/man2/userfaultfd.2.html) feature available in
385+
//! newer Linux kernels. It allows Lucet instances to lazily copy in the initial heap contents of an
386+
//! `Instance`, reducing startup time. Instance stack pages can also be lazily initialized, reducing
387+
//! the memory footprint of instances that only use a small portion of their available stack space.
388+
//!
389+
//! To use `UffdRegion`, enable the `uffd` Cargo feature, which is off by default.
377390
378391
#![deny(bare_trait_objects)]
379392

0 commit comments

Comments
 (0)