1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker //! Integration tests for [PageHandler]. these are more than unit tests since [PageHandler] rely on
6*bb4ee6a4SAndroid Build Coastguard Worker //! the userfaultfd(2) kernel feature.
7*bb4ee6a4SAndroid Build Coastguard Worker
8*bb4ee6a4SAndroid Build Coastguard Worker #![cfg(all(unix, feature = "enable"))]
9*bb4ee6a4SAndroid Build Coastguard Worker
10*bb4ee6a4SAndroid Build Coastguard Worker mod common;
11*bb4ee6a4SAndroid Build Coastguard Worker
12*bb4ee6a4SAndroid Build Coastguard Worker use std::array;
13*bb4ee6a4SAndroid Build Coastguard Worker use std::ops::Range;
14*bb4ee6a4SAndroid Build Coastguard Worker use std::thread;
15*bb4ee6a4SAndroid Build Coastguard Worker use std::time;
16*bb4ee6a4SAndroid Build Coastguard Worker
17*bb4ee6a4SAndroid Build Coastguard Worker use base::pagesize;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::test_utils::call_test_with_sudo;
19*bb4ee6a4SAndroid Build Coastguard Worker use base::MappedRegion;
20*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMappingBuilder;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::SharedMemory;
22*bb4ee6a4SAndroid Build Coastguard Worker use common::*;
23*bb4ee6a4SAndroid Build Coastguard Worker use swap::page_handler::Error;
24*bb4ee6a4SAndroid Build Coastguard Worker use swap::page_handler::PageHandler;
25*bb4ee6a4SAndroid Build Coastguard Worker use swap::userfaultfd::register_regions;
26*bb4ee6a4SAndroid Build Coastguard Worker use swap::userfaultfd::unregister_regions;
27*bb4ee6a4SAndroid Build Coastguard Worker use swap::worker::Worker;
28*bb4ee6a4SAndroid Build Coastguard Worker
29*bb4ee6a4SAndroid Build Coastguard Worker const HUGEPAGE_SIZE: usize = 2 * 1024 * 1024; // 2MB
30*bb4ee6a4SAndroid Build Coastguard Worker
31*bb4ee6a4SAndroid Build Coastguard Worker #[test]
create_success()32*bb4ee6a4SAndroid Build Coastguard Worker fn create_success() {
33*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("create_success_impl")
34*bb4ee6a4SAndroid Build Coastguard Worker }
35*bb4ee6a4SAndroid Build Coastguard Worker
36*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by create_success"]
37*bb4ee6a4SAndroid Build Coastguard Worker #[test]
create_success_impl()38*bb4ee6a4SAndroid Build Coastguard Worker fn create_success_impl() {
39*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
40*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
41*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 6 * pagesize() as u64).unwrap();
42*bb4ee6a4SAndroid Build Coastguard Worker let shm = create_shared_memory("shm", 6 * pagesize());
43*bb4ee6a4SAndroid Build Coastguard Worker let base_addr = shm.base_addr();
44*bb4ee6a4SAndroid Build Coastguard Worker
45*bb4ee6a4SAndroid Build Coastguard Worker let result = PageHandler::create(
46*bb4ee6a4SAndroid Build Coastguard Worker &file,
47*bb4ee6a4SAndroid Build Coastguard Worker &staging_shmem,
48*bb4ee6a4SAndroid Build Coastguard Worker &[
49*bb4ee6a4SAndroid Build Coastguard Worker base_addr..(base_addr + 3 * pagesize()),
50*bb4ee6a4SAndroid Build Coastguard Worker (base_addr + 3 * pagesize())..(base_addr + 6 * pagesize()),
51*bb4ee6a4SAndroid Build Coastguard Worker ],
52*bb4ee6a4SAndroid Build Coastguard Worker worker.channel.clone(),
53*bb4ee6a4SAndroid Build Coastguard Worker );
54*bb4ee6a4SAndroid Build Coastguard Worker
55*bb4ee6a4SAndroid Build Coastguard Worker assert!(result.is_ok());
56*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
57*bb4ee6a4SAndroid Build Coastguard Worker }
58*bb4ee6a4SAndroid Build Coastguard Worker
59*bb4ee6a4SAndroid Build Coastguard Worker #[test]
create_partially_overlap()60*bb4ee6a4SAndroid Build Coastguard Worker fn create_partially_overlap() {
61*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("create_partially_overlap_impl")
62*bb4ee6a4SAndroid Build Coastguard Worker }
63*bb4ee6a4SAndroid Build Coastguard Worker
64*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by create_partially_overlap"]
65*bb4ee6a4SAndroid Build Coastguard Worker #[test]
create_partially_overlap_impl()66*bb4ee6a4SAndroid Build Coastguard Worker fn create_partially_overlap_impl() {
67*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
68*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
69*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 3 * pagesize() as u64).unwrap();
70*bb4ee6a4SAndroid Build Coastguard Worker let shm = create_shared_memory("shm", 3 * pagesize());
71*bb4ee6a4SAndroid Build Coastguard Worker let base_addr = shm.base_addr();
72*bb4ee6a4SAndroid Build Coastguard Worker
73*bb4ee6a4SAndroid Build Coastguard Worker for range in [
74*bb4ee6a4SAndroid Build Coastguard Worker // the same address range
75*bb4ee6a4SAndroid Build Coastguard Worker base_addr..(base_addr + 3 * pagesize()),
76*bb4ee6a4SAndroid Build Coastguard Worker // left of the existing region overlaps
77*bb4ee6a4SAndroid Build Coastguard Worker (base_addr - pagesize())..(base_addr + pagesize()),
78*bb4ee6a4SAndroid Build Coastguard Worker // new region is inside
79*bb4ee6a4SAndroid Build Coastguard Worker (base_addr + pagesize())..(base_addr + 2 * pagesize()),
80*bb4ee6a4SAndroid Build Coastguard Worker // right of the existing region overlaps
81*bb4ee6a4SAndroid Build Coastguard Worker (base_addr + 2 * pagesize())..(base_addr + 4 * pagesize()),
82*bb4ee6a4SAndroid Build Coastguard Worker // new region covers whole the existing region
83*bb4ee6a4SAndroid Build Coastguard Worker (base_addr - pagesize())..(base_addr + 4 * pagesize()),
84*bb4ee6a4SAndroid Build Coastguard Worker ] {
85*bb4ee6a4SAndroid Build Coastguard Worker let result = PageHandler::create(
86*bb4ee6a4SAndroid Build Coastguard Worker &file,
87*bb4ee6a4SAndroid Build Coastguard Worker &staging_shmem,
88*bb4ee6a4SAndroid Build Coastguard Worker &[base_addr..(base_addr + 3 * pagesize()), range],
89*bb4ee6a4SAndroid Build Coastguard Worker worker.channel.clone(),
90*bb4ee6a4SAndroid Build Coastguard Worker );
91*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result.is_err(), true);
92*bb4ee6a4SAndroid Build Coastguard Worker match result {
93*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::RegionOverlap(_, _)) => {}
94*bb4ee6a4SAndroid Build Coastguard Worker _ => {
95*bb4ee6a4SAndroid Build Coastguard Worker unreachable!("not overlap")
96*bb4ee6a4SAndroid Build Coastguard Worker }
97*bb4ee6a4SAndroid Build Coastguard Worker }
98*bb4ee6a4SAndroid Build Coastguard Worker }
99*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
100*bb4ee6a4SAndroid Build Coastguard Worker }
101*bb4ee6a4SAndroid Build Coastguard Worker
102*bb4ee6a4SAndroid Build Coastguard Worker #[test]
create_invalid_range()103*bb4ee6a4SAndroid Build Coastguard Worker fn create_invalid_range() {
104*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("create_invalid_range_impl")
105*bb4ee6a4SAndroid Build Coastguard Worker }
106*bb4ee6a4SAndroid Build Coastguard Worker
107*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by create_invalid_range"]
108*bb4ee6a4SAndroid Build Coastguard Worker #[test]
create_invalid_range_impl()109*bb4ee6a4SAndroid Build Coastguard Worker fn create_invalid_range_impl() {
110*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
111*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
112*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 6 * pagesize() as u64).unwrap();
113*bb4ee6a4SAndroid Build Coastguard Worker let shm = create_shared_memory("shm", 6 * pagesize());
114*bb4ee6a4SAndroid Build Coastguard Worker let base_addr = shm.base_addr();
115*bb4ee6a4SAndroid Build Coastguard Worker let region = base_addr..(base_addr - pagesize());
116*bb4ee6a4SAndroid Build Coastguard Worker
117*bb4ee6a4SAndroid Build Coastguard Worker let result = PageHandler::create(&file, &staging_shmem, &[region], worker.channel.clone());
118*bb4ee6a4SAndroid Build Coastguard Worker
119*bb4ee6a4SAndroid Build Coastguard Worker assert!(result.is_err());
120*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
121*bb4ee6a4SAndroid Build Coastguard Worker }
122*bb4ee6a4SAndroid Build Coastguard Worker
wait_thread_with_timeout<T>(join_handle: thread::JoinHandle<T>, timeout_millis: u64) -> T123*bb4ee6a4SAndroid Build Coastguard Worker fn wait_thread_with_timeout<T>(join_handle: thread::JoinHandle<T>, timeout_millis: u64) -> T {
124*bb4ee6a4SAndroid Build Coastguard Worker for _ in 0..timeout_millis {
125*bb4ee6a4SAndroid Build Coastguard Worker if join_handle.is_finished() {
126*bb4ee6a4SAndroid Build Coastguard Worker return join_handle.join().unwrap();
127*bb4ee6a4SAndroid Build Coastguard Worker }
128*bb4ee6a4SAndroid Build Coastguard Worker thread::sleep(time::Duration::from_millis(1));
129*bb4ee6a4SAndroid Build Coastguard Worker }
130*bb4ee6a4SAndroid Build Coastguard Worker panic!("thread join timeout");
131*bb4ee6a4SAndroid Build Coastguard Worker }
132*bb4ee6a4SAndroid Build Coastguard Worker
133*bb4ee6a4SAndroid Build Coastguard Worker #[test]
handle_page_fault_zero_success()134*bb4ee6a4SAndroid Build Coastguard Worker fn handle_page_fault_zero_success() {
135*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("handle_page_fault_zero_success_impl")
136*bb4ee6a4SAndroid Build Coastguard Worker }
137*bb4ee6a4SAndroid Build Coastguard Worker
138*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by handle_page_fault_zero_success"]
139*bb4ee6a4SAndroid Build Coastguard Worker #[test]
handle_page_fault_zero_success_impl()140*bb4ee6a4SAndroid Build Coastguard Worker fn handle_page_fault_zero_success_impl() {
141*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
142*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
143*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 3 * pagesize() as u64).unwrap();
144*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
145*bb4ee6a4SAndroid Build Coastguard Worker let shm = create_shared_memory("shm", 3 * pagesize());
146*bb4ee6a4SAndroid Build Coastguard Worker let base_addr = shm.base_addr();
147*bb4ee6a4SAndroid Build Coastguard Worker let region = base_addr..(base_addr + 3 * pagesize());
148*bb4ee6a4SAndroid Build Coastguard Worker let regions = [region];
149*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
150*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
151*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
152*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
153*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
154*bb4ee6a4SAndroid Build Coastguard Worker
155*bb4ee6a4SAndroid Build Coastguard Worker page_handler.handle_page_fault(&uffd, base_addr).unwrap();
156*bb4ee6a4SAndroid Build Coastguard Worker page_handler
157*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr + pagesize() + 1)
158*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
159*bb4ee6a4SAndroid Build Coastguard Worker page_handler
160*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr + 3 * pagesize() - 1)
161*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
162*bb4ee6a4SAndroid Build Coastguard Worker
163*bb4ee6a4SAndroid Build Coastguard Worker // read values on another thread to avoid blocking forever
164*bb4ee6a4SAndroid Build Coastguard Worker let join_handle = thread::spawn(move || {
165*bb4ee6a4SAndroid Build Coastguard Worker let mut result = Vec::new();
166*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..(3 * pagesize()) {
167*bb4ee6a4SAndroid Build Coastguard Worker let ptr = shm.mmap.as_ptr() as usize + i;
168*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
169*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
170*bb4ee6a4SAndroid Build Coastguard Worker result.push(*(ptr as *mut u8));
171*bb4ee6a4SAndroid Build Coastguard Worker }
172*bb4ee6a4SAndroid Build Coastguard Worker }
173*bb4ee6a4SAndroid Build Coastguard Worker result
174*bb4ee6a4SAndroid Build Coastguard Worker });
175*bb4ee6a4SAndroid Build Coastguard Worker
176*bb4ee6a4SAndroid Build Coastguard Worker let result = wait_thread_with_timeout(join_handle, 100);
177*bb4ee6a4SAndroid Build Coastguard Worker
178*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result, vec![0; 3 * pagesize()]);
179*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
180*bb4ee6a4SAndroid Build Coastguard Worker }
181*bb4ee6a4SAndroid Build Coastguard Worker
182*bb4ee6a4SAndroid Build Coastguard Worker #[test]
handle_page_fault_invalid_address()183*bb4ee6a4SAndroid Build Coastguard Worker fn handle_page_fault_invalid_address() {
184*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("handle_page_fault_invalid_address_impl")
185*bb4ee6a4SAndroid Build Coastguard Worker }
186*bb4ee6a4SAndroid Build Coastguard Worker
187*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by handle_page_fault_invalid_address"]
188*bb4ee6a4SAndroid Build Coastguard Worker #[test]
handle_page_fault_invalid_address_impl()189*bb4ee6a4SAndroid Build Coastguard Worker fn handle_page_fault_invalid_address_impl() {
190*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
191*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
192*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 3 * pagesize() as u64).unwrap();
193*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
194*bb4ee6a4SAndroid Build Coastguard Worker let shm = create_shared_memory("shm", 3 * pagesize());
195*bb4ee6a4SAndroid Build Coastguard Worker let base_addr = shm.base_addr();
196*bb4ee6a4SAndroid Build Coastguard Worker let region = base_addr..(base_addr + 3 * pagesize());
197*bb4ee6a4SAndroid Build Coastguard Worker let regions = [region];
198*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
199*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
200*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
201*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
202*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
203*bb4ee6a4SAndroid Build Coastguard Worker
204*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
205*bb4ee6a4SAndroid Build Coastguard Worker page_handler
206*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr - 1)
207*bb4ee6a4SAndroid Build Coastguard Worker .is_err(),
208*bb4ee6a4SAndroid Build Coastguard Worker true
209*bb4ee6a4SAndroid Build Coastguard Worker );
210*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
211*bb4ee6a4SAndroid Build Coastguard Worker page_handler
212*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr + 3 * pagesize())
213*bb4ee6a4SAndroid Build Coastguard Worker .is_err(),
214*bb4ee6a4SAndroid Build Coastguard Worker true
215*bb4ee6a4SAndroid Build Coastguard Worker );
216*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
217*bb4ee6a4SAndroid Build Coastguard Worker }
218*bb4ee6a4SAndroid Build Coastguard Worker
219*bb4ee6a4SAndroid Build Coastguard Worker #[test]
handle_page_fault_duplicated_page_fault()220*bb4ee6a4SAndroid Build Coastguard Worker fn handle_page_fault_duplicated_page_fault() {
221*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("handle_page_fault_duplicated_page_fault_impl")
222*bb4ee6a4SAndroid Build Coastguard Worker }
223*bb4ee6a4SAndroid Build Coastguard Worker
224*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by handle_page_fault_duplicated_page_fault"]
225*bb4ee6a4SAndroid Build Coastguard Worker #[test]
handle_page_fault_duplicated_page_fault_impl()226*bb4ee6a4SAndroid Build Coastguard Worker fn handle_page_fault_duplicated_page_fault_impl() {
227*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
228*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
229*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 3 * pagesize() as u64).unwrap();
230*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
231*bb4ee6a4SAndroid Build Coastguard Worker let shm = create_shared_memory("shm", 3 * pagesize());
232*bb4ee6a4SAndroid Build Coastguard Worker let base_addr = shm.base_addr();
233*bb4ee6a4SAndroid Build Coastguard Worker let region = base_addr..(base_addr + 3 * pagesize());
234*bb4ee6a4SAndroid Build Coastguard Worker let regions = [region];
235*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
236*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
237*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
238*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
239*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
240*bb4ee6a4SAndroid Build Coastguard Worker
241*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
242*bb4ee6a4SAndroid Build Coastguard Worker page_handler.handle_page_fault(&uffd, base_addr).is_ok(),
243*bb4ee6a4SAndroid Build Coastguard Worker true
244*bb4ee6a4SAndroid Build Coastguard Worker );
245*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
246*bb4ee6a4SAndroid Build Coastguard Worker page_handler.handle_page_fault(&uffd, base_addr + 1).is_ok(),
247*bb4ee6a4SAndroid Build Coastguard Worker true
248*bb4ee6a4SAndroid Build Coastguard Worker );
249*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
250*bb4ee6a4SAndroid Build Coastguard Worker }
251*bb4ee6a4SAndroid Build Coastguard Worker
252*bb4ee6a4SAndroid Build Coastguard Worker #[test]
handle_page_remove_success()253*bb4ee6a4SAndroid Build Coastguard Worker fn handle_page_remove_success() {
254*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("handle_page_remove_success_impl")
255*bb4ee6a4SAndroid Build Coastguard Worker }
256*bb4ee6a4SAndroid Build Coastguard Worker
257*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by handle_page_remove_success"]
258*bb4ee6a4SAndroid Build Coastguard Worker #[test]
handle_page_remove_success_impl()259*bb4ee6a4SAndroid Build Coastguard Worker fn handle_page_remove_success_impl() {
260*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
261*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
262*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 3 * pagesize() as u64).unwrap();
263*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
264*bb4ee6a4SAndroid Build Coastguard Worker let shm = create_shared_memory("shm", 3 * pagesize());
265*bb4ee6a4SAndroid Build Coastguard Worker let base_addr = shm.base_addr();
266*bb4ee6a4SAndroid Build Coastguard Worker let region = base_addr..(base_addr + 3 * pagesize());
267*bb4ee6a4SAndroid Build Coastguard Worker let regions = [region];
268*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
269*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
270*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
271*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
272*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
273*bb4ee6a4SAndroid Build Coastguard Worker
274*bb4ee6a4SAndroid Build Coastguard Worker // fill the first page with zero
275*bb4ee6a4SAndroid Build Coastguard Worker page_handler.handle_page_fault(&uffd, base_addr).unwrap();
276*bb4ee6a4SAndroid Build Coastguard Worker // write value on another thread to avoid blocking forever
277*bb4ee6a4SAndroid Build Coastguard Worker let join_handle = thread::spawn(move || {
278*bb4ee6a4SAndroid Build Coastguard Worker let ptr = base_addr as *mut u8;
279*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
280*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
281*bb4ee6a4SAndroid Build Coastguard Worker *ptr = 1;
282*bb4ee6a4SAndroid Build Coastguard Worker }
283*bb4ee6a4SAndroid Build Coastguard Worker });
284*bb4ee6a4SAndroid Build Coastguard Worker wait_thread_with_timeout(join_handle, 100);
285*bb4ee6a4SAndroid Build Coastguard Worker let second_page_addr = base_addr + pagesize();
286*bb4ee6a4SAndroid Build Coastguard Worker page_handler
287*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_remove(base_addr, second_page_addr)
288*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
289*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
290*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
291*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
292*bb4ee6a4SAndroid Build Coastguard Worker libc::madvise(
293*bb4ee6a4SAndroid Build Coastguard Worker base_addr as *mut libc::c_void,
294*bb4ee6a4SAndroid Build Coastguard Worker pagesize(),
295*bb4ee6a4SAndroid Build Coastguard Worker libc::MADV_REMOVE,
296*bb4ee6a4SAndroid Build Coastguard Worker );
297*bb4ee6a4SAndroid Build Coastguard Worker }
298*bb4ee6a4SAndroid Build Coastguard Worker // fill the first page with zero again
299*bb4ee6a4SAndroid Build Coastguard Worker page_handler.handle_page_fault(&uffd, base_addr).unwrap();
300*bb4ee6a4SAndroid Build Coastguard Worker // read value on another thread to avoid blocking forever
301*bb4ee6a4SAndroid Build Coastguard Worker let join_handle = thread::spawn(move || {
302*bb4ee6a4SAndroid Build Coastguard Worker let ptr = base_addr as *mut u8;
303*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
304*bb4ee6a4SAndroid Build Coastguard Worker unsafe { *ptr }
305*bb4ee6a4SAndroid Build Coastguard Worker });
306*bb4ee6a4SAndroid Build Coastguard Worker
307*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(wait_thread_with_timeout(join_handle, 100), 0);
308*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
309*bb4ee6a4SAndroid Build Coastguard Worker }
310*bb4ee6a4SAndroid Build Coastguard Worker
311*bb4ee6a4SAndroid Build Coastguard Worker #[test]
handle_page_remove_invalid_address()312*bb4ee6a4SAndroid Build Coastguard Worker fn handle_page_remove_invalid_address() {
313*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("handle_page_remove_invalid_address_impl")
314*bb4ee6a4SAndroid Build Coastguard Worker }
315*bb4ee6a4SAndroid Build Coastguard Worker
316*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by handle_page_remove_invalid_address"]
317*bb4ee6a4SAndroid Build Coastguard Worker #[test]
handle_page_remove_invalid_address_impl()318*bb4ee6a4SAndroid Build Coastguard Worker fn handle_page_remove_invalid_address_impl() {
319*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
320*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
321*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 3 * pagesize() as u64).unwrap();
322*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
323*bb4ee6a4SAndroid Build Coastguard Worker let shm = create_shared_memory("shm", 3 * pagesize());
324*bb4ee6a4SAndroid Build Coastguard Worker let base_addr = shm.base_addr();
325*bb4ee6a4SAndroid Build Coastguard Worker let region = base_addr..(base_addr + 3 * pagesize());
326*bb4ee6a4SAndroid Build Coastguard Worker let regions = [region];
327*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
328*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
329*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
330*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
331*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
332*bb4ee6a4SAndroid Build Coastguard Worker
333*bb4ee6a4SAndroid Build Coastguard Worker page_handler.handle_page_fault(&uffd, base_addr).unwrap();
334*bb4ee6a4SAndroid Build Coastguard Worker page_handler
335*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr + pagesize())
336*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
337*bb4ee6a4SAndroid Build Coastguard Worker page_handler
338*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr + 2 * pagesize())
339*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
340*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
341*bb4ee6a4SAndroid Build Coastguard Worker page_handler
342*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_remove(base_addr - 1, base_addr + 3 * pagesize())
343*bb4ee6a4SAndroid Build Coastguard Worker .is_err(),
344*bb4ee6a4SAndroid Build Coastguard Worker true
345*bb4ee6a4SAndroid Build Coastguard Worker );
346*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
347*bb4ee6a4SAndroid Build Coastguard Worker page_handler
348*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_remove(base_addr, base_addr + 3 * pagesize() + 1)
349*bb4ee6a4SAndroid Build Coastguard Worker .is_err(),
350*bb4ee6a4SAndroid Build Coastguard Worker true
351*bb4ee6a4SAndroid Build Coastguard Worker );
352*bb4ee6a4SAndroid Build Coastguard Worker // remove for whole region should succeed.
353*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
354*bb4ee6a4SAndroid Build Coastguard Worker page_handler
355*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_remove(base_addr, base_addr + 3 * pagesize())
356*bb4ee6a4SAndroid Build Coastguard Worker .is_ok(),
357*bb4ee6a4SAndroid Build Coastguard Worker true
358*bb4ee6a4SAndroid Build Coastguard Worker );
359*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
360*bb4ee6a4SAndroid Build Coastguard Worker }
361*bb4ee6a4SAndroid Build Coastguard Worker
362*bb4ee6a4SAndroid Build Coastguard Worker #[test]
move_to_staging_data_written_before_enabling()363*bb4ee6a4SAndroid Build Coastguard Worker fn move_to_staging_data_written_before_enabling() {
364*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("move_to_staging_data_written_before_enabling_impl")
365*bb4ee6a4SAndroid Build Coastguard Worker }
366*bb4ee6a4SAndroid Build Coastguard Worker
367*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by move_to_staging_data_written_before_enabling"]
368*bb4ee6a4SAndroid Build Coastguard Worker #[test]
move_to_staging_data_written_before_enabling_impl()369*bb4ee6a4SAndroid Build Coastguard Worker fn move_to_staging_data_written_before_enabling_impl() {
370*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
371*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
372*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
373*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 6 * pagesize() as u64).unwrap();
374*bb4ee6a4SAndroid Build Coastguard Worker let shm = SharedMemory::new("shm", 6 * pagesize() as u64).unwrap();
375*bb4ee6a4SAndroid Build Coastguard Worker let mmap1 = MemoryMappingBuilder::new(3 * pagesize())
376*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
377*bb4ee6a4SAndroid Build Coastguard Worker .build()
378*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
379*bb4ee6a4SAndroid Build Coastguard Worker let mmap2 = MemoryMappingBuilder::new(3 * pagesize())
380*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
381*bb4ee6a4SAndroid Build Coastguard Worker .offset(3 * pagesize() as u64)
382*bb4ee6a4SAndroid Build Coastguard Worker .build()
383*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
384*bb4ee6a4SAndroid Build Coastguard Worker let base_addr1 = mmap1.as_ptr() as usize;
385*bb4ee6a4SAndroid Build Coastguard Worker let base_addr2 = mmap2.as_ptr() as usize;
386*bb4ee6a4SAndroid Build Coastguard Worker
387*bb4ee6a4SAndroid Build Coastguard Worker let regions = [
388*bb4ee6a4SAndroid Build Coastguard Worker base_addr1..(base_addr1 + 3 * pagesize()),
389*bb4ee6a4SAndroid Build Coastguard Worker base_addr2..(base_addr2 + 3 * pagesize()),
390*bb4ee6a4SAndroid Build Coastguard Worker ];
391*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
392*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
393*bb4ee6a4SAndroid Build Coastguard Worker // write data before registering to userfaultfd
394*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
395*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
396*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
397*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr1 + pagesize()..base_addr1 + 2 * pagesize() {
398*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 1;
399*bb4ee6a4SAndroid Build Coastguard Worker }
400*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr2 + pagesize()..base_addr2 + 2 * pagesize() {
401*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 2;
402*bb4ee6a4SAndroid Build Coastguard Worker }
403*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr2 + 2 * pagesize()..base_addr2 + 3 * pagesize() {
404*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 3;
405*bb4ee6a4SAndroid Build Coastguard Worker }
406*bb4ee6a4SAndroid Build Coastguard Worker }
407*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
408*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
409*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
410*bb4ee6a4SAndroid Build Coastguard Worker
411*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
412*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
413*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
414*bb4ee6a4SAndroid Build Coastguard Worker page_handler.move_to_staging(base_addr1, &shm, 0).unwrap();
415*bb4ee6a4SAndroid Build Coastguard Worker page_handler
416*bb4ee6a4SAndroid Build Coastguard Worker .move_to_staging(base_addr2, &shm, 3 * pagesize() as u64)
417*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
418*bb4ee6a4SAndroid Build Coastguard Worker }
419*bb4ee6a4SAndroid Build Coastguard Worker worker.channel.wait_complete();
420*bb4ee6a4SAndroid Build Coastguard Worker // page faults on all pages.
421*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
422*bb4ee6a4SAndroid Build Coastguard Worker page_handler
423*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr1 + i * pagesize())
424*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
425*bb4ee6a4SAndroid Build Coastguard Worker page_handler
426*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr2 + i * pagesize())
427*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
428*bb4ee6a4SAndroid Build Coastguard Worker }
429*bb4ee6a4SAndroid Build Coastguard Worker
430*bb4ee6a4SAndroid Build Coastguard Worker // read values on another thread to avoid blocking forever
431*bb4ee6a4SAndroid Build Coastguard Worker let join_handle = thread::spawn(move || {
432*bb4ee6a4SAndroid Build Coastguard Worker let mut result = Vec::new();
433*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
434*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
435*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr1 + i * pagesize() + j) as *mut u8;
436*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
437*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
438*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
439*bb4ee6a4SAndroid Build Coastguard Worker }
440*bb4ee6a4SAndroid Build Coastguard Worker }
441*bb4ee6a4SAndroid Build Coastguard Worker }
442*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
443*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
444*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr2 + i * pagesize() + j) as *mut u8;
445*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
446*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
447*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
448*bb4ee6a4SAndroid Build Coastguard Worker }
449*bb4ee6a4SAndroid Build Coastguard Worker }
450*bb4ee6a4SAndroid Build Coastguard Worker }
451*bb4ee6a4SAndroid Build Coastguard Worker result
452*bb4ee6a4SAndroid Build Coastguard Worker });
453*bb4ee6a4SAndroid Build Coastguard Worker let result = wait_thread_with_timeout(join_handle, 100);
454*bb4ee6a4SAndroid Build Coastguard Worker let values: Vec<u8> = vec![0, 1, 0, 0, 2, 3];
455*bb4ee6a4SAndroid Build Coastguard Worker for (i, v) in values.iter().enumerate() {
456*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
457*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&result[i * pagesize() + j], v);
458*bb4ee6a4SAndroid Build Coastguard Worker }
459*bb4ee6a4SAndroid Build Coastguard Worker }
460*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
461*bb4ee6a4SAndroid Build Coastguard Worker }
462*bb4ee6a4SAndroid Build Coastguard Worker
page_idx_range(start_addr: usize, end_addr: usize) -> Range<usize>463*bb4ee6a4SAndroid Build Coastguard Worker fn page_idx_range(start_addr: usize, end_addr: usize) -> Range<usize> {
464*bb4ee6a4SAndroid Build Coastguard Worker (start_addr / pagesize())..(end_addr / pagesize())
465*bb4ee6a4SAndroid Build Coastguard Worker }
466*bb4ee6a4SAndroid Build Coastguard Worker
page_idx_to_addr(page_idx: usize) -> usize467*bb4ee6a4SAndroid Build Coastguard Worker fn page_idx_to_addr(page_idx: usize) -> usize {
468*bb4ee6a4SAndroid Build Coastguard Worker page_idx * pagesize()
469*bb4ee6a4SAndroid Build Coastguard Worker }
470*bb4ee6a4SAndroid Build Coastguard Worker
471*bb4ee6a4SAndroid Build Coastguard Worker #[test]
move_to_staging_hugepage_chunks()472*bb4ee6a4SAndroid Build Coastguard Worker fn move_to_staging_hugepage_chunks() {
473*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("move_to_staging_hugepage_chunks_impl")
474*bb4ee6a4SAndroid Build Coastguard Worker }
475*bb4ee6a4SAndroid Build Coastguard Worker
476*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by move_to_staging_hugepage_chunks"]
477*bb4ee6a4SAndroid Build Coastguard Worker #[test]
move_to_staging_hugepage_chunks_impl()478*bb4ee6a4SAndroid Build Coastguard Worker fn move_to_staging_hugepage_chunks_impl() {
479*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
480*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
481*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
482*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem =
483*bb4ee6a4SAndroid Build Coastguard Worker SharedMemory::new("test staging memory", 10 * HUGEPAGE_SIZE as u64).unwrap();
484*bb4ee6a4SAndroid Build Coastguard Worker let shm = SharedMemory::new("shm", 10 * HUGEPAGE_SIZE as u64).unwrap();
485*bb4ee6a4SAndroid Build Coastguard Worker let mmap1 = MemoryMappingBuilder::new(5 * HUGEPAGE_SIZE)
486*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
487*bb4ee6a4SAndroid Build Coastguard Worker .build()
488*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
489*bb4ee6a4SAndroid Build Coastguard Worker let mmap2 = MemoryMappingBuilder::new(5 * HUGEPAGE_SIZE)
490*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
491*bb4ee6a4SAndroid Build Coastguard Worker .offset(5 * HUGEPAGE_SIZE as u64)
492*bb4ee6a4SAndroid Build Coastguard Worker .build()
493*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
494*bb4ee6a4SAndroid Build Coastguard Worker let base_addr1 = mmap1.as_ptr() as usize;
495*bb4ee6a4SAndroid Build Coastguard Worker let base_addr2 = mmap2.as_ptr() as usize;
496*bb4ee6a4SAndroid Build Coastguard Worker
497*bb4ee6a4SAndroid Build Coastguard Worker let regions = [
498*bb4ee6a4SAndroid Build Coastguard Worker base_addr1..(base_addr1 + 5 * HUGEPAGE_SIZE),
499*bb4ee6a4SAndroid Build Coastguard Worker base_addr2..(base_addr2 + 5 * HUGEPAGE_SIZE),
500*bb4ee6a4SAndroid Build Coastguard Worker ];
501*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
502*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
503*bb4ee6a4SAndroid Build Coastguard Worker // write data before registering to userfaultfd
504*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
505*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
506*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
507*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(base_addr1 + pagesize(), base_addr1 + 3 * pagesize()) {
508*bb4ee6a4SAndroid Build Coastguard Worker *(page_idx_to_addr(i) as *mut u8) = 1;
509*bb4ee6a4SAndroid Build Coastguard Worker }
510*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(
511*bb4ee6a4SAndroid Build Coastguard Worker base_addr1 + HUGEPAGE_SIZE - pagesize(),
512*bb4ee6a4SAndroid Build Coastguard Worker base_addr1 + HUGEPAGE_SIZE + pagesize(),
513*bb4ee6a4SAndroid Build Coastguard Worker ) {
514*bb4ee6a4SAndroid Build Coastguard Worker *(page_idx_to_addr(i) as *mut u8) = 2;
515*bb4ee6a4SAndroid Build Coastguard Worker }
516*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(
517*bb4ee6a4SAndroid Build Coastguard Worker base_addr1 + 2 * HUGEPAGE_SIZE + pagesize(),
518*bb4ee6a4SAndroid Build Coastguard Worker base_addr1 + 3 * HUGEPAGE_SIZE + pagesize(),
519*bb4ee6a4SAndroid Build Coastguard Worker ) {
520*bb4ee6a4SAndroid Build Coastguard Worker *(page_idx_to_addr(i) as *mut u8) = 3;
521*bb4ee6a4SAndroid Build Coastguard Worker }
522*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(base_addr2 + HUGEPAGE_SIZE, base_addr2 + 2 * HUGEPAGE_SIZE) {
523*bb4ee6a4SAndroid Build Coastguard Worker *(page_idx_to_addr(i) as *mut u8) = 4;
524*bb4ee6a4SAndroid Build Coastguard Worker }
525*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(
526*bb4ee6a4SAndroid Build Coastguard Worker base_addr2 + 2 * HUGEPAGE_SIZE + pagesize(),
527*bb4ee6a4SAndroid Build Coastguard Worker base_addr2 + 5 * HUGEPAGE_SIZE - pagesize(),
528*bb4ee6a4SAndroid Build Coastguard Worker ) {
529*bb4ee6a4SAndroid Build Coastguard Worker *(page_idx_to_addr(i) as *mut u8) = 5;
530*bb4ee6a4SAndroid Build Coastguard Worker }
531*bb4ee6a4SAndroid Build Coastguard Worker }
532*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
533*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
534*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
535*bb4ee6a4SAndroid Build Coastguard Worker
536*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
537*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
538*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
539*bb4ee6a4SAndroid Build Coastguard Worker page_handler.move_to_staging(base_addr1, &shm, 0).unwrap();
540*bb4ee6a4SAndroid Build Coastguard Worker page_handler
541*bb4ee6a4SAndroid Build Coastguard Worker .move_to_staging(base_addr2, &shm, 5 * HUGEPAGE_SIZE as u64)
542*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
543*bb4ee6a4SAndroid Build Coastguard Worker }
544*bb4ee6a4SAndroid Build Coastguard Worker worker.channel.wait_complete();
545*bb4ee6a4SAndroid Build Coastguard Worker // page faults on all pages.
546*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..5 * HUGEPAGE_SIZE / pagesize() {
547*bb4ee6a4SAndroid Build Coastguard Worker page_handler
548*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr1 + i * pagesize())
549*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
550*bb4ee6a4SAndroid Build Coastguard Worker page_handler
551*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr2 + i * pagesize())
552*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
553*bb4ee6a4SAndroid Build Coastguard Worker }
554*bb4ee6a4SAndroid Build Coastguard Worker
555*bb4ee6a4SAndroid Build Coastguard Worker // read values on another thread to avoid blocking forever
556*bb4ee6a4SAndroid Build Coastguard Worker let join_handle = thread::spawn(move || {
557*bb4ee6a4SAndroid Build Coastguard Worker let mut result = Vec::new();
558*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(base_addr1, base_addr1 + 5 * HUGEPAGE_SIZE) {
559*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (page_idx_to_addr(i)) as *mut u8;
560*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
561*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
562*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
563*bb4ee6a4SAndroid Build Coastguard Worker }
564*bb4ee6a4SAndroid Build Coastguard Worker }
565*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(base_addr2, base_addr2 + 5 * HUGEPAGE_SIZE) {
566*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (page_idx_to_addr(i)) as *mut u8;
567*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
568*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
569*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
570*bb4ee6a4SAndroid Build Coastguard Worker }
571*bb4ee6a4SAndroid Build Coastguard Worker }
572*bb4ee6a4SAndroid Build Coastguard Worker result
573*bb4ee6a4SAndroid Build Coastguard Worker });
574*bb4ee6a4SAndroid Build Coastguard Worker let result = wait_thread_with_timeout(join_handle, 100);
575*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result[0], 0);
576*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result[1], 1);
577*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result[2], 1);
578*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(3 * pagesize(), HUGEPAGE_SIZE - pagesize()) {
579*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result[i], 0);
580*bb4ee6a4SAndroid Build Coastguard Worker }
581*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(HUGEPAGE_SIZE - pagesize(), HUGEPAGE_SIZE + pagesize()) {
582*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result[i], 2);
583*bb4ee6a4SAndroid Build Coastguard Worker }
584*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(HUGEPAGE_SIZE + pagesize(), 2 * HUGEPAGE_SIZE + pagesize()) {
585*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result[i], 0);
586*bb4ee6a4SAndroid Build Coastguard Worker }
587*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(
588*bb4ee6a4SAndroid Build Coastguard Worker 2 * HUGEPAGE_SIZE + pagesize(),
589*bb4ee6a4SAndroid Build Coastguard Worker 3 * HUGEPAGE_SIZE + pagesize(),
590*bb4ee6a4SAndroid Build Coastguard Worker ) {
591*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result[i], 3);
592*bb4ee6a4SAndroid Build Coastguard Worker }
593*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(3 * HUGEPAGE_SIZE + pagesize(), 6 * HUGEPAGE_SIZE) {
594*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result[i], 0);
595*bb4ee6a4SAndroid Build Coastguard Worker }
596*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(6 * HUGEPAGE_SIZE, 7 * HUGEPAGE_SIZE) {
597*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result[i], 4);
598*bb4ee6a4SAndroid Build Coastguard Worker }
599*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(7 * HUGEPAGE_SIZE, 7 * HUGEPAGE_SIZE + pagesize()) {
600*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result[i], 0);
601*bb4ee6a4SAndroid Build Coastguard Worker }
602*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(
603*bb4ee6a4SAndroid Build Coastguard Worker 7 * HUGEPAGE_SIZE + pagesize(),
604*bb4ee6a4SAndroid Build Coastguard Worker 10 * HUGEPAGE_SIZE - pagesize(),
605*bb4ee6a4SAndroid Build Coastguard Worker ) {
606*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result[i], 5);
607*bb4ee6a4SAndroid Build Coastguard Worker }
608*bb4ee6a4SAndroid Build Coastguard Worker for i in page_idx_range(10 * HUGEPAGE_SIZE - pagesize(), 10 * HUGEPAGE_SIZE) {
609*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result[i], 0);
610*bb4ee6a4SAndroid Build Coastguard Worker }
611*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
612*bb4ee6a4SAndroid Build Coastguard Worker }
613*bb4ee6a4SAndroid Build Coastguard Worker
614*bb4ee6a4SAndroid Build Coastguard Worker #[test]
move_to_staging_invalid_base_addr()615*bb4ee6a4SAndroid Build Coastguard Worker fn move_to_staging_invalid_base_addr() {
616*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("move_to_staging_invalid_base_addr_impl")
617*bb4ee6a4SAndroid Build Coastguard Worker }
618*bb4ee6a4SAndroid Build Coastguard Worker
619*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by move_to_staging_invalid_base_addr"]
620*bb4ee6a4SAndroid Build Coastguard Worker #[test]
move_to_staging_invalid_base_addr_impl()621*bb4ee6a4SAndroid Build Coastguard Worker fn move_to_staging_invalid_base_addr_impl() {
622*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
623*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
624*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
625*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 3 * pagesize() as u64).unwrap();
626*bb4ee6a4SAndroid Build Coastguard Worker let shm = create_shared_memory("shm1", 3 * pagesize());
627*bb4ee6a4SAndroid Build Coastguard Worker let base_addr = shm.base_addr();
628*bb4ee6a4SAndroid Build Coastguard Worker let region = base_addr..(base_addr + 3 * pagesize());
629*bb4ee6a4SAndroid Build Coastguard Worker let regions = [region];
630*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
631*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
632*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
633*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
634*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
635*bb4ee6a4SAndroid Build Coastguard Worker
636*bb4ee6a4SAndroid Build Coastguard Worker // the base_addr is within the region
637*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
638*bb4ee6a4SAndroid Build Coastguard Worker {
639*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
640*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
641*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
642*bb4ee6a4SAndroid Build Coastguard Worker page_handler
643*bb4ee6a4SAndroid Build Coastguard Worker .move_to_staging(base_addr + pagesize(), &shm.shm, 0)
644*bb4ee6a4SAndroid Build Coastguard Worker .is_err()
645*bb4ee6a4SAndroid Build Coastguard Worker }
646*bb4ee6a4SAndroid Build Coastguard Worker },
647*bb4ee6a4SAndroid Build Coastguard Worker true
648*bb4ee6a4SAndroid Build Coastguard Worker );
649*bb4ee6a4SAndroid Build Coastguard Worker // the base_addr is outside of the region
650*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
651*bb4ee6a4SAndroid Build Coastguard Worker {
652*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
653*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
654*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
655*bb4ee6a4SAndroid Build Coastguard Worker page_handler
656*bb4ee6a4SAndroid Build Coastguard Worker .move_to_staging(base_addr - pagesize(), &shm.shm, 0)
657*bb4ee6a4SAndroid Build Coastguard Worker .is_err()
658*bb4ee6a4SAndroid Build Coastguard Worker }
659*bb4ee6a4SAndroid Build Coastguard Worker },
660*bb4ee6a4SAndroid Build Coastguard Worker true
661*bb4ee6a4SAndroid Build Coastguard Worker );
662*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
663*bb4ee6a4SAndroid Build Coastguard Worker }
664*bb4ee6a4SAndroid Build Coastguard Worker
swap_out_all(page_handler: &PageHandler)665*bb4ee6a4SAndroid Build Coastguard Worker fn swap_out_all(page_handler: &PageHandler) {
666*bb4ee6a4SAndroid Build Coastguard Worker while page_handler.swap_out(1024 * 1024).unwrap() != 0 {}
667*bb4ee6a4SAndroid Build Coastguard Worker }
668*bb4ee6a4SAndroid Build Coastguard Worker
669*bb4ee6a4SAndroid Build Coastguard Worker #[test]
swap_out_success()670*bb4ee6a4SAndroid Build Coastguard Worker fn swap_out_success() {
671*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("swap_out_success_impl")
672*bb4ee6a4SAndroid Build Coastguard Worker }
673*bb4ee6a4SAndroid Build Coastguard Worker
674*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by swap_out_success"]
675*bb4ee6a4SAndroid Build Coastguard Worker #[test]
swap_out_success_impl()676*bb4ee6a4SAndroid Build Coastguard Worker fn swap_out_success_impl() {
677*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
678*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
679*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
680*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 6 * pagesize() as u64).unwrap();
681*bb4ee6a4SAndroid Build Coastguard Worker let shm = SharedMemory::new("shm", 6 * pagesize() as u64).unwrap();
682*bb4ee6a4SAndroid Build Coastguard Worker let mmap1 = MemoryMappingBuilder::new(3 * pagesize())
683*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
684*bb4ee6a4SAndroid Build Coastguard Worker .build()
685*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
686*bb4ee6a4SAndroid Build Coastguard Worker let mmap2 = MemoryMappingBuilder::new(3 * pagesize())
687*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
688*bb4ee6a4SAndroid Build Coastguard Worker .offset(3 * pagesize() as u64)
689*bb4ee6a4SAndroid Build Coastguard Worker .build()
690*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
691*bb4ee6a4SAndroid Build Coastguard Worker let base_addr1 = mmap1.as_ptr() as usize;
692*bb4ee6a4SAndroid Build Coastguard Worker let base_addr2 = mmap2.as_ptr() as usize;
693*bb4ee6a4SAndroid Build Coastguard Worker let regions = [
694*bb4ee6a4SAndroid Build Coastguard Worker base_addr1..(base_addr1 + 3 * pagesize()),
695*bb4ee6a4SAndroid Build Coastguard Worker base_addr2..(base_addr2 + 3 * pagesize()),
696*bb4ee6a4SAndroid Build Coastguard Worker ];
697*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
698*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
699*bb4ee6a4SAndroid Build Coastguard Worker // write data before registering to userfaultfd
700*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
701*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
702*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
703*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr1 + pagesize()..base_addr1 + 2 * pagesize() {
704*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 1;
705*bb4ee6a4SAndroid Build Coastguard Worker }
706*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr2 + pagesize()..base_addr2 + 2 * pagesize() {
707*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 2;
708*bb4ee6a4SAndroid Build Coastguard Worker }
709*bb4ee6a4SAndroid Build Coastguard Worker }
710*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
711*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
712*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
713*bb4ee6a4SAndroid Build Coastguard Worker
714*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
715*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
716*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
717*bb4ee6a4SAndroid Build Coastguard Worker page_handler.move_to_staging(base_addr1, &shm, 0).unwrap();
718*bb4ee6a4SAndroid Build Coastguard Worker page_handler
719*bb4ee6a4SAndroid Build Coastguard Worker .move_to_staging(base_addr2, &shm, 3 * pagesize() as u64)
720*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
721*bb4ee6a4SAndroid Build Coastguard Worker }
722*bb4ee6a4SAndroid Build Coastguard Worker worker.channel.wait_complete();
723*bb4ee6a4SAndroid Build Coastguard Worker swap_out_all(&page_handler);
724*bb4ee6a4SAndroid Build Coastguard Worker // page faults on all pages. page 0 and page 2 will be swapped in from the file. page 1 will
725*bb4ee6a4SAndroid Build Coastguard Worker // be filled with zero.
726*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
727*bb4ee6a4SAndroid Build Coastguard Worker page_handler
728*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr1 + i * pagesize())
729*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
730*bb4ee6a4SAndroid Build Coastguard Worker page_handler
731*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr2 + i * pagesize())
732*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
733*bb4ee6a4SAndroid Build Coastguard Worker }
734*bb4ee6a4SAndroid Build Coastguard Worker
735*bb4ee6a4SAndroid Build Coastguard Worker // read values on another thread to avoid blocking forever
736*bb4ee6a4SAndroid Build Coastguard Worker let join_handle = thread::spawn(move || {
737*bb4ee6a4SAndroid Build Coastguard Worker let mut result = Vec::new();
738*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
739*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
740*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr1 + i * pagesize() + j) as *mut u8;
741*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
742*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
743*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
744*bb4ee6a4SAndroid Build Coastguard Worker }
745*bb4ee6a4SAndroid Build Coastguard Worker }
746*bb4ee6a4SAndroid Build Coastguard Worker }
747*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
748*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
749*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr2 + i * pagesize() + j) as *mut u8;
750*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
751*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
752*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
753*bb4ee6a4SAndroid Build Coastguard Worker }
754*bb4ee6a4SAndroid Build Coastguard Worker }
755*bb4ee6a4SAndroid Build Coastguard Worker }
756*bb4ee6a4SAndroid Build Coastguard Worker result
757*bb4ee6a4SAndroid Build Coastguard Worker });
758*bb4ee6a4SAndroid Build Coastguard Worker let result = wait_thread_with_timeout(join_handle, 100);
759*bb4ee6a4SAndroid Build Coastguard Worker let values: Vec<u8> = vec![0, 1, 0, 0, 2, 0];
760*bb4ee6a4SAndroid Build Coastguard Worker for (i, v) in values.iter().enumerate() {
761*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
762*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&result[i * pagesize() + j], v);
763*bb4ee6a4SAndroid Build Coastguard Worker }
764*bb4ee6a4SAndroid Build Coastguard Worker }
765*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
766*bb4ee6a4SAndroid Build Coastguard Worker }
767*bb4ee6a4SAndroid Build Coastguard Worker
768*bb4ee6a4SAndroid Build Coastguard Worker #[test]
swap_out_handled_page()769*bb4ee6a4SAndroid Build Coastguard Worker fn swap_out_handled_page() {
770*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("swap_out_handled_page_impl")
771*bb4ee6a4SAndroid Build Coastguard Worker }
772*bb4ee6a4SAndroid Build Coastguard Worker
773*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by swap_out_handled_page"]
774*bb4ee6a4SAndroid Build Coastguard Worker #[test]
swap_out_handled_page_impl()775*bb4ee6a4SAndroid Build Coastguard Worker fn swap_out_handled_page_impl() {
776*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
777*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
778*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
779*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 6 * pagesize() as u64).unwrap();
780*bb4ee6a4SAndroid Build Coastguard Worker let shm = SharedMemory::new("shm", 6 * pagesize() as u64).unwrap();
781*bb4ee6a4SAndroid Build Coastguard Worker let mmap1 = MemoryMappingBuilder::new(3 * pagesize())
782*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
783*bb4ee6a4SAndroid Build Coastguard Worker .build()
784*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
785*bb4ee6a4SAndroid Build Coastguard Worker let base_addr1 = mmap1.as_ptr() as usize;
786*bb4ee6a4SAndroid Build Coastguard Worker
787*bb4ee6a4SAndroid Build Coastguard Worker let region = base_addr1..(base_addr1 + 3 * pagesize());
788*bb4ee6a4SAndroid Build Coastguard Worker let regions = [region];
789*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
790*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
791*bb4ee6a4SAndroid Build Coastguard Worker // write data before registering to userfaultfd
792*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
793*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
794*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
795*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr1 + pagesize()..base_addr1 + 2 * pagesize() {
796*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 1;
797*bb4ee6a4SAndroid Build Coastguard Worker }
798*bb4ee6a4SAndroid Build Coastguard Worker }
799*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
800*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
801*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
802*bb4ee6a4SAndroid Build Coastguard Worker
803*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
804*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
805*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
806*bb4ee6a4SAndroid Build Coastguard Worker page_handler.move_to_staging(base_addr1, &shm, 0).unwrap();
807*bb4ee6a4SAndroid Build Coastguard Worker }
808*bb4ee6a4SAndroid Build Coastguard Worker worker.channel.wait_complete();
809*bb4ee6a4SAndroid Build Coastguard Worker // page in before swap_out()
810*bb4ee6a4SAndroid Build Coastguard Worker page_handler
811*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr1 + pagesize())
812*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
813*bb4ee6a4SAndroid Build Coastguard Worker swap_out_all(&page_handler);
814*bb4ee6a4SAndroid Build Coastguard Worker
815*bb4ee6a4SAndroid Build Coastguard Worker // read values on another thread to avoid blocking forever
816*bb4ee6a4SAndroid Build Coastguard Worker let join_handle = thread::spawn(move || {
817*bb4ee6a4SAndroid Build Coastguard Worker let mut result = Vec::new();
818*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..pagesize() {
819*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr1 + pagesize() + i) as *mut u8;
820*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
821*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
822*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
823*bb4ee6a4SAndroid Build Coastguard Worker }
824*bb4ee6a4SAndroid Build Coastguard Worker }
825*bb4ee6a4SAndroid Build Coastguard Worker result
826*bb4ee6a4SAndroid Build Coastguard Worker });
827*bb4ee6a4SAndroid Build Coastguard Worker // reading the page is not blocked.s
828*bb4ee6a4SAndroid Build Coastguard Worker let result = wait_thread_with_timeout(join_handle, 100);
829*bb4ee6a4SAndroid Build Coastguard Worker for v in result {
830*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(v, 1);
831*bb4ee6a4SAndroid Build Coastguard Worker }
832*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
833*bb4ee6a4SAndroid Build Coastguard Worker }
834*bb4ee6a4SAndroid Build Coastguard Worker
835*bb4ee6a4SAndroid Build Coastguard Worker #[test]
swap_out_twice()836*bb4ee6a4SAndroid Build Coastguard Worker fn swap_out_twice() {
837*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("swap_out_twice_impl")
838*bb4ee6a4SAndroid Build Coastguard Worker }
839*bb4ee6a4SAndroid Build Coastguard Worker
840*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by swap_out_twice"]
841*bb4ee6a4SAndroid Build Coastguard Worker #[test]
swap_out_twice_impl()842*bb4ee6a4SAndroid Build Coastguard Worker fn swap_out_twice_impl() {
843*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
844*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
845*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
846*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 6 * pagesize() as u64).unwrap();
847*bb4ee6a4SAndroid Build Coastguard Worker let shm = SharedMemory::new("shm", 6 * pagesize() as u64).unwrap();
848*bb4ee6a4SAndroid Build Coastguard Worker let mmap1 = MemoryMappingBuilder::new(3 * pagesize())
849*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
850*bb4ee6a4SAndroid Build Coastguard Worker .build()
851*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
852*bb4ee6a4SAndroid Build Coastguard Worker let mmap2 = MemoryMappingBuilder::new(3 * pagesize())
853*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
854*bb4ee6a4SAndroid Build Coastguard Worker .offset(3 * pagesize() as u64)
855*bb4ee6a4SAndroid Build Coastguard Worker .build()
856*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
857*bb4ee6a4SAndroid Build Coastguard Worker let base_addr1 = mmap1.as_ptr() as usize;
858*bb4ee6a4SAndroid Build Coastguard Worker let base_addr2 = mmap2.as_ptr() as usize;
859*bb4ee6a4SAndroid Build Coastguard Worker let regions = [
860*bb4ee6a4SAndroid Build Coastguard Worker base_addr1..(base_addr1 + 3 * pagesize()),
861*bb4ee6a4SAndroid Build Coastguard Worker base_addr2..(base_addr2 + 3 * pagesize()),
862*bb4ee6a4SAndroid Build Coastguard Worker ];
863*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
864*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
865*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
866*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
867*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
868*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..pagesize() {
869*bb4ee6a4SAndroid Build Coastguard Worker *((base_addr1 + i) as *mut u8) = 1;
870*bb4ee6a4SAndroid Build Coastguard Worker *((base_addr1 + 2 * pagesize() + i) as *mut u8) = 2;
871*bb4ee6a4SAndroid Build Coastguard Worker *((base_addr2 + i) as *mut u8) = 3;
872*bb4ee6a4SAndroid Build Coastguard Worker *((base_addr2 + 2 * pagesize() + i) as *mut u8) = 4;
873*bb4ee6a4SAndroid Build Coastguard Worker }
874*bb4ee6a4SAndroid Build Coastguard Worker }
875*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
876*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
877*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
878*bb4ee6a4SAndroid Build Coastguard Worker
879*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
880*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
881*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
882*bb4ee6a4SAndroid Build Coastguard Worker page_handler.move_to_staging(base_addr1, &shm, 0).unwrap();
883*bb4ee6a4SAndroid Build Coastguard Worker page_handler
884*bb4ee6a4SAndroid Build Coastguard Worker .move_to_staging(base_addr2, &shm, 3 * pagesize() as u64)
885*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
886*bb4ee6a4SAndroid Build Coastguard Worker }
887*bb4ee6a4SAndroid Build Coastguard Worker worker.channel.wait_complete();
888*bb4ee6a4SAndroid Build Coastguard Worker swap_out_all(&page_handler);
889*bb4ee6a4SAndroid Build Coastguard Worker // page faults on all pages in mmap1.
890*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
891*bb4ee6a4SAndroid Build Coastguard Worker page_handler
892*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, (base_addr1) + i * pagesize())
893*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
894*bb4ee6a4SAndroid Build Coastguard Worker }
895*bb4ee6a4SAndroid Build Coastguard Worker // write values on another thread to avoid blocking forever
896*bb4ee6a4SAndroid Build Coastguard Worker let join_handle = thread::spawn(move || {
897*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..pagesize() {
898*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr1 + pagesize() + i) as *mut u8;
899*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
900*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
901*bb4ee6a4SAndroid Build Coastguard Worker *ptr = 5;
902*bb4ee6a4SAndroid Build Coastguard Worker }
903*bb4ee6a4SAndroid Build Coastguard Worker }
904*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..pagesize() {
905*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr1 + 2 * pagesize() + i) as *mut u8;
906*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
907*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
908*bb4ee6a4SAndroid Build Coastguard Worker *ptr = 6;
909*bb4ee6a4SAndroid Build Coastguard Worker }
910*bb4ee6a4SAndroid Build Coastguard Worker }
911*bb4ee6a4SAndroid Build Coastguard Worker });
912*bb4ee6a4SAndroid Build Coastguard Worker wait_thread_with_timeout(join_handle, 100);
913*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
914*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
915*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
916*bb4ee6a4SAndroid Build Coastguard Worker page_handler.move_to_staging(base_addr1, &shm, 0).unwrap();
917*bb4ee6a4SAndroid Build Coastguard Worker page_handler
918*bb4ee6a4SAndroid Build Coastguard Worker .move_to_staging(base_addr2, &shm, 3 * pagesize() as u64)
919*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
920*bb4ee6a4SAndroid Build Coastguard Worker }
921*bb4ee6a4SAndroid Build Coastguard Worker worker.channel.wait_complete();
922*bb4ee6a4SAndroid Build Coastguard Worker swap_out_all(&page_handler);
923*bb4ee6a4SAndroid Build Coastguard Worker
924*bb4ee6a4SAndroid Build Coastguard Worker // page faults on all pages.
925*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
926*bb4ee6a4SAndroid Build Coastguard Worker page_handler
927*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr1 + i * pagesize())
928*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
929*bb4ee6a4SAndroid Build Coastguard Worker page_handler
930*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr2 + i * pagesize())
931*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
932*bb4ee6a4SAndroid Build Coastguard Worker }
933*bb4ee6a4SAndroid Build Coastguard Worker // read values on another thread to avoid blocking forever
934*bb4ee6a4SAndroid Build Coastguard Worker let join_handle = thread::spawn(move || {
935*bb4ee6a4SAndroid Build Coastguard Worker let mut result = Vec::new();
936*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
937*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
938*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr1 + i * pagesize() + j) as *mut u8;
939*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
940*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
941*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
942*bb4ee6a4SAndroid Build Coastguard Worker }
943*bb4ee6a4SAndroid Build Coastguard Worker }
944*bb4ee6a4SAndroid Build Coastguard Worker }
945*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
946*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
947*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr2 + i * pagesize() + j) as *mut u8;
948*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
949*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
950*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
951*bb4ee6a4SAndroid Build Coastguard Worker }
952*bb4ee6a4SAndroid Build Coastguard Worker }
953*bb4ee6a4SAndroid Build Coastguard Worker }
954*bb4ee6a4SAndroid Build Coastguard Worker result
955*bb4ee6a4SAndroid Build Coastguard Worker });
956*bb4ee6a4SAndroid Build Coastguard Worker let result = wait_thread_with_timeout(join_handle, 100);
957*bb4ee6a4SAndroid Build Coastguard Worker let values: Vec<u8> = vec![1, 5, 6, 3, 0, 4];
958*bb4ee6a4SAndroid Build Coastguard Worker for (i, v) in values.iter().enumerate() {
959*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
960*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&result[i * pagesize() + j], v);
961*bb4ee6a4SAndroid Build Coastguard Worker }
962*bb4ee6a4SAndroid Build Coastguard Worker }
963*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
964*bb4ee6a4SAndroid Build Coastguard Worker }
965*bb4ee6a4SAndroid Build Coastguard Worker
966*bb4ee6a4SAndroid Build Coastguard Worker #[test]
swap_in_success()967*bb4ee6a4SAndroid Build Coastguard Worker fn swap_in_success() {
968*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("swap_in_success_impl")
969*bb4ee6a4SAndroid Build Coastguard Worker }
970*bb4ee6a4SAndroid Build Coastguard Worker
971*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by swap_in_success"]
972*bb4ee6a4SAndroid Build Coastguard Worker #[test]
swap_in_success_impl()973*bb4ee6a4SAndroid Build Coastguard Worker fn swap_in_success_impl() {
974*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
975*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
976*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
977*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 6 * pagesize() as u64).unwrap();
978*bb4ee6a4SAndroid Build Coastguard Worker let shm = SharedMemory::new("shm", 6 * pagesize() as u64).unwrap();
979*bb4ee6a4SAndroid Build Coastguard Worker let mmap1 = MemoryMappingBuilder::new(3 * pagesize())
980*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
981*bb4ee6a4SAndroid Build Coastguard Worker .build()
982*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
983*bb4ee6a4SAndroid Build Coastguard Worker let mmap2 = MemoryMappingBuilder::new(3 * pagesize())
984*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
985*bb4ee6a4SAndroid Build Coastguard Worker .offset(3 * pagesize() as u64)
986*bb4ee6a4SAndroid Build Coastguard Worker .build()
987*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
988*bb4ee6a4SAndroid Build Coastguard Worker let base_addr1 = mmap1.as_ptr() as usize;
989*bb4ee6a4SAndroid Build Coastguard Worker let base_addr2 = mmap2.as_ptr() as usize;
990*bb4ee6a4SAndroid Build Coastguard Worker let regions = [
991*bb4ee6a4SAndroid Build Coastguard Worker base_addr1..(base_addr1 + 3 * pagesize()),
992*bb4ee6a4SAndroid Build Coastguard Worker base_addr2..(base_addr2 + 3 * pagesize()),
993*bb4ee6a4SAndroid Build Coastguard Worker ];
994*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
995*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
996*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
997*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
998*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
999*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr1 + pagesize()..base_addr1 + 2 * pagesize() {
1000*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 1;
1001*bb4ee6a4SAndroid Build Coastguard Worker }
1002*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr2 + pagesize()..base_addr2 + 2 * pagesize() {
1003*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 2;
1004*bb4ee6a4SAndroid Build Coastguard Worker }
1005*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr2 + 2 * pagesize()..base_addr2 + 3 * pagesize() {
1006*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 3;
1007*bb4ee6a4SAndroid Build Coastguard Worker }
1008*bb4ee6a4SAndroid Build Coastguard Worker }
1009*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
1010*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
1011*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
1012*bb4ee6a4SAndroid Build Coastguard Worker
1013*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
1014*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
1015*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1016*bb4ee6a4SAndroid Build Coastguard Worker page_handler.move_to_staging(base_addr1, &shm, 0).unwrap();
1017*bb4ee6a4SAndroid Build Coastguard Worker page_handler
1018*bb4ee6a4SAndroid Build Coastguard Worker .move_to_staging(base_addr2, &shm, 3 * pagesize() as u64)
1019*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
1020*bb4ee6a4SAndroid Build Coastguard Worker }
1021*bb4ee6a4SAndroid Build Coastguard Worker worker.channel.wait_complete();
1022*bb4ee6a4SAndroid Build Coastguard Worker swap_out_all(&page_handler);
1023*bb4ee6a4SAndroid Build Coastguard Worker page_handler
1024*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr1 + pagesize())
1025*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
1026*bb4ee6a4SAndroid Build Coastguard Worker page_handler
1027*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr2 + pagesize())
1028*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
1029*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
1030*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
1031*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1032*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr2 + pagesize()..base_addr2 + 2 * pagesize() {
1033*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 4;
1034*bb4ee6a4SAndroid Build Coastguard Worker }
1035*bb4ee6a4SAndroid Build Coastguard Worker }
1036*bb4ee6a4SAndroid Build Coastguard Worker // move to staging memory.
1037*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
1038*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
1039*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1040*bb4ee6a4SAndroid Build Coastguard Worker page_handler
1041*bb4ee6a4SAndroid Build Coastguard Worker .move_to_staging(base_addr2, &shm, 3 * pagesize() as u64)
1042*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
1043*bb4ee6a4SAndroid Build Coastguard Worker }
1044*bb4ee6a4SAndroid Build Coastguard Worker worker.channel.wait_complete();
1045*bb4ee6a4SAndroid Build Coastguard Worker let mut swap_in_ctx = page_handler.start_swap_in();
1046*bb4ee6a4SAndroid Build Coastguard Worker while swap_in_ctx.swap_in(&uffd, 1024 * 1024).unwrap() != 0 {}
1047*bb4ee6a4SAndroid Build Coastguard Worker unregister_regions(®ions, array::from_ref(&uffd)).unwrap();
1048*bb4ee6a4SAndroid Build Coastguard Worker
1049*bb4ee6a4SAndroid Build Coastguard Worker // read values on another thread to avoid blocking forever
1050*bb4ee6a4SAndroid Build Coastguard Worker let join_handle = thread::spawn(move || {
1051*bb4ee6a4SAndroid Build Coastguard Worker let mut result = Vec::new();
1052*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
1053*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
1054*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr1 + i * pagesize() + j) as *mut u8;
1055*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
1056*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1057*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
1058*bb4ee6a4SAndroid Build Coastguard Worker }
1059*bb4ee6a4SAndroid Build Coastguard Worker }
1060*bb4ee6a4SAndroid Build Coastguard Worker }
1061*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
1062*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
1063*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr2 + i * pagesize() + j) as *mut u8;
1064*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
1065*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1066*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
1067*bb4ee6a4SAndroid Build Coastguard Worker }
1068*bb4ee6a4SAndroid Build Coastguard Worker }
1069*bb4ee6a4SAndroid Build Coastguard Worker }
1070*bb4ee6a4SAndroid Build Coastguard Worker result
1071*bb4ee6a4SAndroid Build Coastguard Worker });
1072*bb4ee6a4SAndroid Build Coastguard Worker let result = wait_thread_with_timeout(join_handle, 100);
1073*bb4ee6a4SAndroid Build Coastguard Worker let values: Vec<u8> = vec![0, 1, 0, 0, 4, 3];
1074*bb4ee6a4SAndroid Build Coastguard Worker for (i, v) in values.iter().enumerate() {
1075*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
1076*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&result[i * pagesize() + j], v);
1077*bb4ee6a4SAndroid Build Coastguard Worker }
1078*bb4ee6a4SAndroid Build Coastguard Worker }
1079*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
1080*bb4ee6a4SAndroid Build Coastguard Worker }
1081*bb4ee6a4SAndroid Build Coastguard Worker
1082*bb4ee6a4SAndroid Build Coastguard Worker #[test]
trim_success()1083*bb4ee6a4SAndroid Build Coastguard Worker fn trim_success() {
1084*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("trim_success_impl")
1085*bb4ee6a4SAndroid Build Coastguard Worker }
1086*bb4ee6a4SAndroid Build Coastguard Worker
1087*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by trim_success"]
1088*bb4ee6a4SAndroid Build Coastguard Worker #[test]
trim_success_impl()1089*bb4ee6a4SAndroid Build Coastguard Worker fn trim_success_impl() {
1090*bb4ee6a4SAndroid Build Coastguard Worker let worker = Worker::new(2, 2);
1091*bb4ee6a4SAndroid Build Coastguard Worker let uffd = create_uffd_for_test();
1092*bb4ee6a4SAndroid Build Coastguard Worker let file = tempfile::tempfile().unwrap();
1093*bb4ee6a4SAndroid Build Coastguard Worker let staging_shmem = SharedMemory::new("test staging memory", 6 * pagesize() as u64).unwrap();
1094*bb4ee6a4SAndroid Build Coastguard Worker let shm = SharedMemory::new("shm", 6 * pagesize() as u64).unwrap();
1095*bb4ee6a4SAndroid Build Coastguard Worker let mmap1 = MemoryMappingBuilder::new(3 * pagesize())
1096*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
1097*bb4ee6a4SAndroid Build Coastguard Worker .build()
1098*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
1099*bb4ee6a4SAndroid Build Coastguard Worker let mmap2 = MemoryMappingBuilder::new(3 * pagesize())
1100*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&shm)
1101*bb4ee6a4SAndroid Build Coastguard Worker .offset(3 * pagesize() as u64)
1102*bb4ee6a4SAndroid Build Coastguard Worker .build()
1103*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
1104*bb4ee6a4SAndroid Build Coastguard Worker let base_addr1 = mmap1.as_ptr() as usize;
1105*bb4ee6a4SAndroid Build Coastguard Worker let base_addr2 = mmap2.as_ptr() as usize;
1106*bb4ee6a4SAndroid Build Coastguard Worker let regions = [
1107*bb4ee6a4SAndroid Build Coastguard Worker base_addr1..(base_addr1 + 3 * pagesize()),
1108*bb4ee6a4SAndroid Build Coastguard Worker base_addr2..(base_addr2 + 3 * pagesize()),
1109*bb4ee6a4SAndroid Build Coastguard Worker ];
1110*bb4ee6a4SAndroid Build Coastguard Worker let page_handler =
1111*bb4ee6a4SAndroid Build Coastguard Worker PageHandler::create(&file, &staging_shmem, ®ions, worker.channel.clone()).unwrap();
1112*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
1113*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
1114*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1115*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr1..base_addr1 + pagesize() {
1116*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 0;
1117*bb4ee6a4SAndroid Build Coastguard Worker }
1118*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr1 + pagesize()..base_addr1 + 2 * pagesize() {
1119*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 1;
1120*bb4ee6a4SAndroid Build Coastguard Worker }
1121*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr2..base_addr2 + pagesize() {
1122*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 0;
1123*bb4ee6a4SAndroid Build Coastguard Worker }
1124*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr2 + pagesize()..base_addr2 + 2 * pagesize() {
1125*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 2;
1126*bb4ee6a4SAndroid Build Coastguard Worker }
1127*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr2 + 2 * pagesize()..base_addr2 + 3 * pagesize() {
1128*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 3;
1129*bb4ee6a4SAndroid Build Coastguard Worker }
1130*bb4ee6a4SAndroid Build Coastguard Worker }
1131*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
1132*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
1133*bb4ee6a4SAndroid Build Coastguard Worker unsafe { register_regions(®ions, array::from_ref(&uffd)) }.unwrap();
1134*bb4ee6a4SAndroid Build Coastguard Worker
1135*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
1136*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
1137*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1138*bb4ee6a4SAndroid Build Coastguard Worker page_handler.move_to_staging(base_addr1, &shm, 0).unwrap();
1139*bb4ee6a4SAndroid Build Coastguard Worker page_handler
1140*bb4ee6a4SAndroid Build Coastguard Worker .move_to_staging(base_addr2, &shm, 3 * pagesize() as u64)
1141*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
1142*bb4ee6a4SAndroid Build Coastguard Worker }
1143*bb4ee6a4SAndroid Build Coastguard Worker worker.channel.wait_complete();
1144*bb4ee6a4SAndroid Build Coastguard Worker
1145*bb4ee6a4SAndroid Build Coastguard Worker let mut trim_ctx = page_handler.start_trim();
1146*bb4ee6a4SAndroid Build Coastguard Worker
1147*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(trim_ctx.trim_pages(6 * pagesize()).unwrap().unwrap(), 1);
1148*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(trim_ctx.trimmed_clean_pages(), 0);
1149*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(trim_ctx.trimmed_zero_pages(), 1);
1150*bb4ee6a4SAndroid Build Coastguard Worker // 1 zero page
1151*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(trim_ctx.trim_pages(6 * pagesize()).unwrap().unwrap(), 1);
1152*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(trim_ctx.trimmed_clean_pages(), 0);
1153*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(trim_ctx.trimmed_zero_pages(), 2);
1154*bb4ee6a4SAndroid Build Coastguard Worker
1155*bb4ee6a4SAndroid Build Coastguard Worker swap_out_all(&page_handler);
1156*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
1157*bb4ee6a4SAndroid Build Coastguard Worker page_handler
1158*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr1 + i * pagesize())
1159*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
1160*bb4ee6a4SAndroid Build Coastguard Worker page_handler
1161*bb4ee6a4SAndroid Build Coastguard Worker .handle_page_fault(&uffd, base_addr2 + i * pagesize())
1162*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
1163*bb4ee6a4SAndroid Build Coastguard Worker }
1164*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
1165*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
1166*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1167*bb4ee6a4SAndroid Build Coastguard Worker for i in base_addr2 + pagesize()..base_addr2 + 2 * pagesize() {
1168*bb4ee6a4SAndroid Build Coastguard Worker *(i as *mut u8) = 4;
1169*bb4ee6a4SAndroid Build Coastguard Worker }
1170*bb4ee6a4SAndroid Build Coastguard Worker }
1171*bb4ee6a4SAndroid Build Coastguard Worker
1172*bb4ee6a4SAndroid Build Coastguard Worker // move to staging memory.
1173*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
1174*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
1175*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1176*bb4ee6a4SAndroid Build Coastguard Worker page_handler.move_to_staging(base_addr1, &shm, 0).unwrap();
1177*bb4ee6a4SAndroid Build Coastguard Worker page_handler
1178*bb4ee6a4SAndroid Build Coastguard Worker .move_to_staging(base_addr2, &shm, 3 * pagesize() as u64)
1179*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
1180*bb4ee6a4SAndroid Build Coastguard Worker }
1181*bb4ee6a4SAndroid Build Coastguard Worker worker.channel.wait_complete();
1182*bb4ee6a4SAndroid Build Coastguard Worker
1183*bb4ee6a4SAndroid Build Coastguard Worker let mut trim_ctx = page_handler.start_trim();
1184*bb4ee6a4SAndroid Build Coastguard Worker // 2 zero pages and 1 clean page
1185*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(trim_ctx.trim_pages(6 * pagesize()).unwrap().unwrap(), 3);
1186*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(trim_ctx.trimmed_clean_pages(), 1);
1187*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(trim_ctx.trimmed_zero_pages(), 2);
1188*bb4ee6a4SAndroid Build Coastguard Worker // 1 zero page and 1 clean pages
1189*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(trim_ctx.trim_pages(6 * pagesize()).unwrap().unwrap(), 2);
1190*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(trim_ctx.trimmed_clean_pages(), 2);
1191*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(trim_ctx.trimmed_zero_pages(), 3);
1192*bb4ee6a4SAndroid Build Coastguard Worker assert!(trim_ctx.trim_pages(pagesize()).unwrap().is_none());
1193*bb4ee6a4SAndroid Build Coastguard Worker
1194*bb4ee6a4SAndroid Build Coastguard Worker let mut swap_in_ctx = page_handler.start_swap_in();
1195*bb4ee6a4SAndroid Build Coastguard Worker while swap_in_ctx.swap_in(&uffd, 1024 * 1024).unwrap() != 0 {}
1196*bb4ee6a4SAndroid Build Coastguard Worker unregister_regions(®ions, array::from_ref(&uffd)).unwrap();
1197*bb4ee6a4SAndroid Build Coastguard Worker
1198*bb4ee6a4SAndroid Build Coastguard Worker // read values on another thread to avoid blocking forever
1199*bb4ee6a4SAndroid Build Coastguard Worker let join_handle = thread::spawn(move || {
1200*bb4ee6a4SAndroid Build Coastguard Worker let mut result = Vec::new();
1201*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
1202*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
1203*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr1 + i * pagesize() + j) as *mut u8;
1204*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
1205*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1206*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
1207*bb4ee6a4SAndroid Build Coastguard Worker }
1208*bb4ee6a4SAndroid Build Coastguard Worker }
1209*bb4ee6a4SAndroid Build Coastguard Worker }
1210*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..3 {
1211*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
1212*bb4ee6a4SAndroid Build Coastguard Worker let ptr = (base_addr2 + i * pagesize() + j) as *mut u8;
1213*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
1214*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1215*bb4ee6a4SAndroid Build Coastguard Worker result.push(*ptr);
1216*bb4ee6a4SAndroid Build Coastguard Worker }
1217*bb4ee6a4SAndroid Build Coastguard Worker }
1218*bb4ee6a4SAndroid Build Coastguard Worker }
1219*bb4ee6a4SAndroid Build Coastguard Worker result
1220*bb4ee6a4SAndroid Build Coastguard Worker });
1221*bb4ee6a4SAndroid Build Coastguard Worker let result = wait_thread_with_timeout(join_handle, 100);
1222*bb4ee6a4SAndroid Build Coastguard Worker let values: Vec<u8> = vec![0, 1, 0, 0, 4, 3];
1223*bb4ee6a4SAndroid Build Coastguard Worker for (i, v) in values.iter().enumerate() {
1224*bb4ee6a4SAndroid Build Coastguard Worker for j in 0..pagesize() {
1225*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&result[i * pagesize() + j], v);
1226*bb4ee6a4SAndroid Build Coastguard Worker }
1227*bb4ee6a4SAndroid Build Coastguard Worker }
1228*bb4ee6a4SAndroid Build Coastguard Worker worker.close();
1229*bb4ee6a4SAndroid Build Coastguard Worker }
1230