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}