ureeves_userfaultfd/event.rs
1use crate::error::{Error, Result};
2use crate::raw;
3use crate::Uffd;
4use libc::c_void;
5#[cfg(feature = "linux4_14")]
6use nix::unistd::Pid;
7use std::os::unix::io::{FromRawFd, RawFd};
8
9/// Whether a page fault event was for a read or write.
10#[derive(Clone, Copy, Debug, PartialEq)]
11pub enum ReadWrite {
12 Read,
13 Write,
14}
15
16/// The kind of fault for a page fault event.
17#[derive(Clone, Copy, Debug, PartialEq)]
18pub enum FaultKind {
19 /// The fault was a read or write on a missing page.
20 Missing,
21 /// The fault was a write on a write-protected page.
22 #[cfg(feature = "linux5_7")]
23 WriteProtected,
24}
25
26/// Events from the userfaultfd object that are read by `Uffd::read_event()`.
27#[derive(Debug)]
28pub enum Event {
29 /// A pagefault event.
30 Pagefault {
31 /// The kind of fault.
32 kind: FaultKind,
33 /// Whether the fault is on a read or a write.
34 rw: ReadWrite,
35 /// The address that triggered the fault.
36 addr: *mut c_void,
37 /// The thread that triggered the fault, if [`FeatureFlags::THREAD_ID`] is enabled.
38 ///
39 /// If the thread ID feature is not enabled, the value of this field is undefined. It would
40 /// not be undefined behavior to use it, strictly speaking, but the [`Pid`] will not
41 /// necessarily point to a real thread.
42 ///
43 /// This requires this crate to be compiled with the `linux4_14` feature.
44 #[cfg(feature = "linux4_14")]
45 thread_id: Pid,
46 },
47 /// Generated when the faulting process invokes `fork(2)` (or `clone(2)` without the `CLONE_VM`
48 /// flag).
49 Fork {
50 /// The `Uffd` object created for the child by `fork(2)`
51 uffd: Uffd,
52 },
53 /// Generated when the faulting process invokes `mremap(2)`.
54 Remap {
55 /// The original address of the memory range that was remapped.
56 from: *mut c_void,
57 /// The new address of the memory range that was remapped.
58 to: *mut c_void,
59 /// The original length of the memory range that was remapped.
60 len: usize,
61 },
62 /// Generated when the faulting process invokes `madvise(2)` with `MADV_DONTNEED` or
63 /// `MADV_REMOVE` advice.
64 Remove {
65 /// The start address of the memory range that was freed.
66 start: *mut c_void,
67 /// The end address of the memory range that was freed.
68 end: *mut c_void,
69 },
70 /// Generated when the faulting process unmaps a meomry range, either explicitly using
71 /// `munmap(2)` or implicitly during `mmap(2)` or `mremap(2)`.
72 Unmap {
73 /// The start address of the memory range that was unmapped.
74 start: *mut c_void,
75 /// The end address of the memory range that was unmapped.
76 end: *mut c_void,
77 },
78}
79
80impl Event {
81 pub(crate) fn from_uffd_msg(msg: &raw::uffd_msg) -> Result<Event> {
82 match msg.event {
83 raw::UFFD_EVENT_PAGEFAULT => {
84 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 );
96
97 let rw = if pagefault.flags & raw::UFFD_PAGEFAULT_FLAG_WRITE == 0 {
98 ReadWrite::Read
99 } else {
100 ReadWrite::Write
101 };
102 // Converting the ptid to i32 is safe because the maximum pid in
103 // Linux is 2^22, which is about 4 million.
104 //
105 // Reference:
106 // https://github.com/torvalds/linux/blob/2d338201d5311bcd79d42f66df4cecbcbc5f4f2c/include/linux/threads.h
107 #[cfg(feature = "linux4_14")]
108 let thread_id = Pid::from_raw(unsafe { pagefault.feat.ptid } as i32);
109 Ok(Event::Pagefault {
110 kind,
111 rw,
112 addr: pagefault.address as *mut c_void,
113 #[cfg(feature = "linux4_14")]
114 thread_id,
115 })
116 }
117 raw::UFFD_EVENT_FORK => {
118 let fork = unsafe { msg.arg.fork };
119 Ok(Event::Fork {
120 uffd: unsafe { Uffd::from_raw_fd(fork.ufd as RawFd) },
121 })
122 }
123 raw::UFFD_EVENT_REMAP => {
124 let remap = unsafe { msg.arg.remap };
125 Ok(Event::Remap {
126 from: remap.from as *mut c_void,
127 to: remap.to as *mut c_void,
128 len: remap.len as usize,
129 })
130 }
131 raw::UFFD_EVENT_REMOVE => {
132 let remove = unsafe { msg.arg.remove };
133 Ok(Event::Remove {
134 start: remove.start as *mut c_void,
135 end: remove.end as *mut c_void,
136 })
137 }
138 raw::UFFD_EVENT_UNMAP => {
139 let remove = unsafe { msg.arg.remove };
140 Ok(Event::Unmap {
141 start: remove.start as *mut c_void,
142 end: remove.end as *mut c_void,
143 })
144 }
145 _ => Err(Error::UnrecognizedEvent(msg.event)),
146 }
147 }
148}