Skip to content

Commit 701c960

Browse files
authored
Merge pull request #72 from roypat/uffdio_continue
Add support for UFFDIO_CONTINUE and UFFDIO_REGISTER_MODE_MINOR
2 parents 6b9b777 + 6902c27 commit 701c960

File tree

11 files changed

+193
-224
lines changed

11 files changed

+193
-224
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ nix = { version = "0.27", features = ["poll", "mman", "feature"] }
2323
default = []
2424
linux4_14 = ["userfaultfd-sys/linux4_14", "nix/process"]
2525
linux5_7 = ["userfaultfd-sys/linux5_7"]
26+
linux5_13 = ["userfaultfd-sys/linux5_13"]

src/event.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ pub enum FaultKind {
2121
/// The fault was a write on a write-protected page.
2222
#[cfg(feature = "linux5_7")]
2323
WriteProtected,
24+
// The fault was a minor page fault, meaning the page was present in the page cache,
25+
// but the userspace page table entry was missing.
26+
#[cfg(feature = "linux5_13")]
27+
Minor,
2428
}
2529

2630
/// Events from the userfaultfd object that are read by `Uffd::read_event()`.
@@ -82,17 +86,21 @@ impl Event {
8286
match msg.event {
8387
raw::UFFD_EVENT_PAGEFAULT => {
8488
let pagefault = unsafe { msg.arg.pagefault };
85-
cfg_if::cfg_if!(
86-
if #[cfg(feature = "linux5_7")] {
87-
let kind = if pagefault.flags & raw::UFFD_PAGEFAULT_FLAG_WP != 0 {
88-
FaultKind::WriteProtected
89-
} else {
90-
FaultKind::Missing
91-
};
92-
} else {
93-
let kind = FaultKind::Missing;
94-
}
95-
);
89+
90+
#[allow(unused_mut)]
91+
let mut kind = FaultKind::Missing;
92+
93+
// The below two flags are mutually exclusive (it does not make sense
94+
// to have a minor fault that is a write-protect fault at the same time.
95+
#[cfg(feature = "linux5_7")]
96+
if pagefault.flags & raw::UFFD_PAGEFAULT_FLAG_WP != 0 {
97+
kind = FaultKind::WriteProtected;
98+
}
99+
100+
#[cfg(feature = "linux5_13")]
101+
if pagefault.flags & raw::UFFD_PAGEFAULT_FLAG_MINOR != 0 {
102+
kind = FaultKind::Minor
103+
}
96104

97105
let rw = if pagefault.flags & raw::UFFD_PAGEFAULT_FLAG_WRITE == 0 {
98106
ReadWrite::Read

src/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ bitflags! {
8787
/// Registers the range for write faults.
8888
#[cfg(feature = "linux5_7")]
8989
const WRITE_PROTECT = raw::UFFDIO_REGISTER_MODE_WP;
90+
// Registers the range for minor faults.
91+
#[cfg(feature = "linux5_13")]
92+
const MINOR = raw::UFFDIO_REGISTER_MODE_MINOR;
9093
}
9194
}
9295

@@ -269,6 +272,38 @@ impl Uffd {
269272
Ok(())
270273
}
271274

275+
/// Resolves minor faults for a range.
276+
///
277+
/// If `wake` is `true`, wake up the thread waiting for page fault resolution on the memory
278+
/// address range.
279+
///
280+
/// Returns the number of bytes actually mapped. If this differs from `len`, then the ioctl
281+
/// returned EAGAIN.
282+
#[cfg(feature = "linux5_13")]
283+
pub fn r#continue(&self, start: *mut c_void, len: usize, wake: bool) -> Result<u64> {
284+
let mut ioctl = raw::uffdio_continue {
285+
range: raw::uffdio_range {
286+
start: start as u64,
287+
len: len as u64,
288+
},
289+
mode: if wake {
290+
0
291+
} else {
292+
raw::UFFDIO_CONTINUE_MODE_DONTWAKE
293+
},
294+
mapped: 0,
295+
};
296+
297+
let r =
298+
unsafe { raw::r#continue(self.as_raw_fd(), &mut ioctl as *mut raw::uffdio_continue) };
299+
300+
match r {
301+
Err(Errno::EAGAIN) if ioctl.mapped > 0 => Ok(ioctl.mapped as u64),
302+
Err(err) => Err(err.into()),
303+
Ok(_) => Ok(ioctl.mapped as u64),
304+
}
305+
}
306+
272307
/// Read an `Event` from the userfaultfd object.
273308
///
274309
/// If the `Uffd` object was created with `non_blocking` set to `false`, this will block until

src/raw.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ nix::ioctl_readwrite!(
2323
_UFFDIO_WRITEPROTECT,
2424
uffdio_writeprotect
2525
);
26+
#[cfg(feature = "linux5_13")]
27+
nix::ioctl_readwrite!(r#continue, UFFDIO, _UFFDIO_CONTINUE, uffdio_continue);
2628

2729
// ioctls for /dev/userfaultfd
2830

userfaultfd-sys/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ cc = "1.0"
1919
[features]
2020
default = []
2121
linux4_14 = []
22-
linux5_7 = []
22+
linux5_7 = ["linux4_14"]
23+
linux5_13 = ["linux5_7"]

userfaultfd-sys/src/consts.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ const __u64 _const_UFFDIO_REGISTER_MODE_MISSING = UFFDIO_REGISTER_MODE_MISSING;
3030
const __u64 _const_UFFDIO_REGISTER_MODE_WP = UFFDIO_REGISTER_MODE_WP;
3131
#endif
3232

33+
#ifdef UFFDIO_REGISTER_MODE_MINOR
34+
const __u64 _const_UFFDIO_REGISTER_MODE_MINOR = UFFDIO_REGISTER_MODE_MINOR;
35+
#endif
36+
3337
#ifdef UFFDIO_COPY_MODE_DONTWAKE
3438
const __u64 _const_UFFDIO_COPY_MODE_DONTWAKE = UFFDIO_COPY_MODE_DONTWAKE;
3539
#endif
@@ -42,6 +46,18 @@ const __u64 _const_UFFDIO_COPY_MODE_WP = UFFDIO_COPY_MODE_WP;
4246
const __u64 _const_UFFDIO_ZEROPAGE_MODE_DONTWAKE = UFFDIO_ZEROPAGE_MODE_DONTWAKE;
4347
#endif
4448

49+
#ifdef UFFDIO_WRITEPROTECT_MODE_WP
50+
const __u64 _const_UFFDIO_WRITEPROTECT_MODE_WP = UFFDIO_WRITEPROTECT_MODE_WP;
51+
#endif
52+
53+
#ifdef UFFDIO_CONTINUE_MODE_DONTWAKE
54+
const __u64 _const_UFFDIO_CONTINUE_MODE_DONTWAKE = UFFDIO_CONTINUE_MODE_DONTWAKE;
55+
#endif
56+
57+
#ifdef UFFDIO_WRITEPROTECT_MODE_DONTWAKE
58+
const __u64 _const_UFFDIO_WRITEPROTECT_MODE_DONTWAKE = UFFDIO_WRITEPROTECT_MODE_DONTWAKE;
59+
#endif
60+
4561
#ifdef UFFDIO_API
4662
const __u32 _const_UFFDIO_API = UFFDIO_API;
4763
#endif
@@ -70,6 +86,10 @@ const __u32 _const_UFFDIO_ZEROPAGE = UFFDIO_ZEROPAGE;
7086
const __u32 _const_UFFDIO_WRITEPROTECT = UFFDIO_WRITEPROTECT;
7187
#endif
7288

89+
#ifdef UFFDIO_CONTINUE
90+
const __u32 _const_UFFDIO_CONTINUE = UFFDIO_CONTINUE;
91+
#endif
92+
7393
#ifdef USERFAULTFD_IOC
7494
const __u32 _const_USERFAULTFD_IOC = USERFAULTFD_IOC;
7595
#endif

userfaultfd-sys/src/lib.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,57 @@
99

1010
use cfg_if::cfg_if;
1111

12+
mod linux4_11;
13+
#[cfg(feature = "linux4_14")]
14+
mod linux4_14;
15+
#[cfg(feature = "linux5_7")]
16+
mod linux5_7;
17+
18+
#[cfg(feature = "linux5_13")]
19+
mod linux5_13;
20+
1221
cfg_if! {
13-
if #[cfg(feature = "linux5_7")] {
14-
mod linux5_7;
22+
if #[cfg(feature = "linux5_13")] {
23+
pub use crate::linux5_13::*;
24+
} else if #[cfg(feature = "linux5_7")] {
1525
pub use crate::linux5_7::*;
16-
}
17-
else if #[cfg(feature = "linux4_14")] {
18-
mod linux4_14;
26+
} else if #[cfg(feature = "linux4_14")] {
1927
pub use crate::linux4_14::*;
2028
} else {
21-
mod linux4_11;
2229
pub use crate::linux4_11::*;
2330
}
2431
}
2532

2633
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
34+
35+
#[cfg(test)]
36+
mod const_tests {
37+
use super::*;
38+
39+
extern "C" {
40+
static _const_UFFD_API_FEATURES: u64;
41+
static _const_UFFD_API_RANGE_IOCTLS: u64;
42+
static _const_UFFD_API_RANGE_IOCTLS_BASIC: u64;
43+
}
44+
45+
#[test]
46+
fn consts_correct() {
47+
unsafe {
48+
assert_eq!(
49+
UFFD_API_FEATURES & _const_UFFD_API_FEATURES,
50+
UFFD_API_FEATURES,
51+
"UFFD_API_FEATURES"
52+
);
53+
assert_eq!(
54+
UFFD_API_RANGE_IOCTLS & _const_UFFD_API_RANGE_IOCTLS,
55+
UFFD_API_RANGE_IOCTLS,
56+
"UFFD_API_RANGE_IOCTLS"
57+
);
58+
assert_eq!(
59+
UFFD_API_RANGE_IOCTLS_BASIC & _const_UFFD_API_RANGE_IOCTLS_BASIC,
60+
UFFD_API_RANGE_IOCTLS_BASIC,
61+
"UFFD_API_RANGE_IOCTLS_BASIC"
62+
);
63+
}
64+
}
65+
}

userfaultfd-sys/src/linux4_11.rs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub const UFFD_API_FEATURES: u64 = UFFD_FEATURE_EVENT_FORK
1414
pub const UFFD_API_IOCTLS: u64 = 1 << _UFFDIO_REGISTER | 1 << _UFFDIO_UNREGISTER | 1 << _UFFDIO_API;
1515
pub const UFFD_API_RANGE_IOCTLS: u64 =
1616
1 << _UFFDIO_WAKE | 1 << _UFFDIO_COPY | 1 << _UFFDIO_ZEROPAGE;
17+
pub const UFFD_API_RANGE_IOCTLS_BASIC: u64 = 0;
1718

1819
pub const UFFDIO_REGISTER_MODE_MISSING: u64 = 1 << 0;
1920
pub const UFFDIO_REGISTER_MODE_WP: u64 = 1 << 1;
@@ -29,15 +30,13 @@ pub const UFFDIO_UNREGISTER: u32 = 0x8010aa01;
2930
pub const UFFDIO_WAKE: u32 = 0x8010aa02;
3031
pub const UFFDIO_COPY: u32 = 0xc028aa03;
3132
pub const UFFDIO_ZEROPAGE: u32 = 0xc020aa04;
32-
pub const UFFDIO_WRITEPROTECT: u32 = 0xc018aa06;
3333

3434
#[cfg(test)]
3535
mod const_tests {
3636
use super::*;
3737

3838
extern "C" {
3939
static _const_UFFD_API: u64;
40-
static _const_UFFD_API_FEATURES: u64;
4140
static _const_UFFD_API_IOCTLS: u64;
4241
static _const_UFFD_API_RANGE_IOCTLS: u64;
4342
static _const_UFFDIO_REGISTER_MODE_MISSING: u64;
@@ -51,22 +50,13 @@ mod const_tests {
5150
static _const_UFFDIO_WAKE: u32;
5251
static _const_UFFDIO_COPY: u32;
5352
static _const_UFFDIO_ZEROPAGE: u32;
54-
static _const_UFFDIO_WRITEPROTECT: u32;
5553
}
5654

5755
#[test]
5856
fn consts_correct() {
5957
unsafe {
6058
assert_eq!(UFFD_API, _const_UFFD_API, "UFFD_API");
61-
assert_eq!(
62-
UFFD_API_FEATURES, _const_UFFD_API_FEATURES,
63-
"UFFD_API_FEATURES"
64-
);
6559
assert_eq!(UFFD_API_IOCTLS, _const_UFFD_API_IOCTLS, "UFFD_API_IOCTLS");
66-
assert_eq!(
67-
UFFD_API_RANGE_IOCTLS, _const_UFFD_API_RANGE_IOCTLS,
68-
"UFFD_API_RANGE_IOCTLS"
69-
);
7060
assert_eq!(
7161
UFFDIO_REGISTER_MODE_MISSING, _const_UFFDIO_REGISTER_MODE_MISSING,
7262
"UFFDIO_REGISTER_MODE_MISSING"
@@ -96,10 +86,6 @@ mod const_tests {
9686
assert_eq!(UFFDIO_WAKE, _const_UFFDIO_WAKE, "UFFDIO_WAKE");
9787
assert_eq!(UFFDIO_COPY, _const_UFFDIO_COPY, "UFFDIO_COPY");
9888
assert_eq!(UFFDIO_ZEROPAGE, _const_UFFDIO_ZEROPAGE, "UFFDIO_ZEROPAGE");
99-
assert_eq!(
100-
UFFDIO_WRITEPROTECT, _const_UFFDIO_WRITEPROTECT,
101-
"UFFDIO_WRITEPROTECT"
102-
);
10389
}
10490
}
10591
}

0 commit comments

Comments
 (0)