| 1108 | /// `UFFDIO_COPY` to resolve the fault and wake the faulting thread. |
| 1109 | #[allow(clippy::needless_pass_by_value)] |
| 1110 | fn uffd_handler_loop( |
| 1111 | uffd_fd: OwnedFd, |
| 1112 | stop_event: EventFd, |
| 1113 | mut snapshot_file: File, |
| 1114 | ranges: &[UffdRange], |
| 1115 | page_size: u64, |
| 1116 | ready_tx: &SyncSender<()>, |
| 1117 | ) -> Result<(), io::Error> { |
| 1118 | let uffd_raw_fd = uffd_fd.as_raw_fd(); |
| 1119 | let mut page_buf = vec![0u8; page_size as usize]; |
| 1120 | |
| 1121 | let total_pages: u64 = ranges.iter().map(|r| r.length.div_ceil(r.page_size)).sum(); |
| 1122 | let mut pages_served: u64 = 0; |
| 1123 | |
| 1124 | const EVENT_STOP: u64 = 0; |
| 1125 | const EVENT_UFFD: u64 = 1; |
| 1126 | |
| 1127 | let epoll_fd = epoll::create(true).map_err(io::Error::other)?; |
| 1128 | // SAFETY: epoll_fd is valid and owned by this scope. |
| 1129 | let _epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; |
| 1130 | |
| 1131 | epoll::ctl( |
| 1132 | epoll_fd, |
| 1133 | epoll::ControlOptions::EPOLL_CTL_ADD, |
| 1134 | stop_event.as_raw_fd(), |
| 1135 | epoll::Event::new(epoll::Events::EPOLLIN, EVENT_STOP), |
| 1136 | ) |
| 1137 | .map_err(io::Error::other)?; |
| 1138 | |
| 1139 | epoll::ctl( |
| 1140 | epoll_fd, |
| 1141 | epoll::ControlOptions::EPOLL_CTL_ADD, |
| 1142 | uffd_raw_fd, |
| 1143 | epoll::Event::new(epoll::Events::EPOLLIN | epoll::Events::EPOLLHUP, EVENT_UFFD), |
| 1144 | ) |
| 1145 | .map_err(io::Error::other)?; |
| 1146 | |
| 1147 | ready_tx.send(()).ok(); |
| 1148 | |
| 1149 | let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); 2]; |
| 1150 | loop { |
| 1151 | let num_events = match epoll::wait(epoll_fd, -1, &mut events) { |
| 1152 | Ok(n) => n, |
| 1153 | Err(e) if e.kind() == io::ErrorKind::Interrupted => continue, |
| 1154 | Err(e) => return Err(e), |
| 1155 | }; |
| 1156 | |
| 1157 | let mut got_uffd_data = false; |
| 1158 | for event in events.iter().take(num_events) { |
| 1159 | let token = event.data; |
| 1160 | let evt_flags = event.events; |
| 1161 | |
| 1162 | if token == EVENT_STOP { |
| 1163 | stop_event.read().ok(); |
| 1164 | info!("UFFD handler: received stop event, exiting"); |
| 1165 | return Ok(()); |
| 1166 | } |
| 1167 | |