1 use crate::error::{Error, Result}; 2 use crate::raw; 3 use crate::Uffd; 4 use libc::c_void; 5 #[cfg(feature = "linux4_14")] 6 use nix::unistd::Pid; 7 use 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)] 11 pub enum ReadWrite { 12 Read, 13 Write, 14 } 15 16 /// The kind of fault for a page fault event. 17 #[derive(Clone, Copy, Debug, PartialEq)] 18 pub 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)] 28 pub 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 80 impl Event { from_uffd_msg(msg: &raw::uffd_msg) -> Result<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 } 149