1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use super::*;
16 
17 use std::sync::LockResult;
18 use std::sync::MutexGuard;
19 
20 use mockall::predicate::*;
21 use mockall::Sequence;
22 
23 use crate::os::MockMeminfoApi;
24 use crate::os::MEMINFO_API_MTX;
25 use crate::zram::MockSysfsZramApi;
26 use crate::zram::ZRAM_API_MTX;
27 
28 const DEFAULT_TOTAL_ZRAM_SIZE: u64 = 4 << 30;
29 const DEFAULT_ZRAM_WRITEBACK_SIZE: u64 = 1 << 30;
30 const DEFAULT_PAGE_SIZE: u64 = 4096;
31 
32 struct MockContext<'a> {
33     read_backing_dev:
34         crate::zram::__mock_MockSysfsZramApi_SysfsZramApi::__read_backing_dev::Context,
35     writeback: crate::zram::__mock_MockSysfsZramApi_SysfsZramApi::__writeback::Context,
36     write_writeback_limit:
37         crate::zram::__mock_MockSysfsZramApi_SysfsZramApi::__write_writeback_limit::Context,
38     read_writeback_limit:
39         crate::zram::__mock_MockSysfsZramApi_SysfsZramApi::__read_writeback_limit::Context,
40     set_idle: crate::zram::__mock_MockSysfsZramApi_SysfsZramApi::__set_idle::Context,
41     read_meminfo: crate::os::__mock_MockMeminfoApi_MeminfoApi::__read_meminfo::Context,
42     // Lock will be released after mock contexts are dropped.
43     _meminfo_lock: LockResult<MutexGuard<'a, ()>>,
44     _zram_lock: LockResult<MutexGuard<'a, ()>>,
45 }
46 
47 impl<'a> MockContext<'a> {
new() -> Self48     fn new() -> Self {
49         let _zram_lock = ZRAM_API_MTX.lock();
50         let _meminfo_lock = MEMINFO_API_MTX.lock();
51         Self {
52             read_backing_dev: MockSysfsZramApi::read_backing_dev_context(),
53             writeback: MockSysfsZramApi::writeback_context(),
54             write_writeback_limit: MockSysfsZramApi::write_writeback_limit_context(),
55             read_writeback_limit: MockSysfsZramApi::read_writeback_limit_context(),
56             set_idle: MockSysfsZramApi::set_idle_context(),
57             read_meminfo: MockMeminfoApi::read_meminfo_context(),
58             _meminfo_lock,
59             _zram_lock,
60         }
61     }
62 
setup_default_meminfo(&self)63     fn setup_default_meminfo(&self) {
64         let meminfo = "MemTotal: 8144296 kB
65             MemAvailable: 346452 kB";
66         self.read_meminfo.expect().returning(|| Ok(meminfo.to_string()));
67     }
68 
setup_default_writeback_limit_read(&self)69     fn setup_default_writeback_limit_read(&self) {
70         self.read_writeback_limit.expect().returning(|| Ok("100\n".to_string()));
71     }
72 }
73 
74 #[test]
test_is_zram_writeback_activated()75 fn test_is_zram_writeback_activated() {
76     let mock = MockContext::new();
77     mock.read_backing_dev.expect().returning(|| Ok("/dev/dm-1".to_string()));
78 
79     assert!(is_zram_writeback_activated::<MockSysfsZramApi>().unwrap());
80 }
81 
82 #[test]
test_load_zram_writeback_disk_size_writeback_is_not_enabled()83 fn test_load_zram_writeback_disk_size_writeback_is_not_enabled() {
84     let mock = MockContext::new();
85     mock.read_backing_dev.expect().returning(|| Ok("none".to_string()));
86 
87     assert!(!is_zram_writeback_activated::<MockSysfsZramApi>().unwrap());
88 }
89 
90 #[test]
test_is_zram_writeback_activated_writeback_is_not_supported()91 fn test_is_zram_writeback_activated_writeback_is_not_supported() {
92     let mock = MockContext::new();
93     mock.read_backing_dev
94         .expect()
95         .returning(|| Err(std::io::Error::new(std::io::ErrorKind::NotFound, "not found")));
96 
97     assert!(!is_zram_writeback_activated::<MockSysfsZramApi>().unwrap());
98 }
99 
100 #[test]
test_is_zram_writeback_activated_failure()101 fn test_is_zram_writeback_activated_failure() {
102     let mock = MockContext::new();
103     mock.read_backing_dev.expect().returning(|| Err(std::io::Error::other("error")));
104 
105     assert!(is_zram_writeback_activated::<MockSysfsZramApi>().is_err());
106 }
107 
108 #[test]
mark_and_flush_pages()109 fn mark_and_flush_pages() {
110     let mock = MockContext::new();
111     let mut seq = Sequence::new();
112     mock.setup_default_meminfo();
113     mock.setup_default_writeback_limit_read();
114     let params = Params::default();
115     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
116     let mut zram_writeback =
117         ZramWriteback::new(DEFAULT_TOTAL_ZRAM_SIZE, DEFAULT_ZRAM_WRITEBACK_SIZE);
118 
119     mock.write_writeback_limit.expect().times(1).in_sequence(&mut seq).returning(|_| Ok(()));
120     mock.set_idle.expect().times(1).in_sequence(&mut seq).returning(|_| Ok(()));
121     mock.writeback.expect().times(1).in_sequence(&mut seq).returning(|_| Ok(()));
122     mock.set_idle.expect().times(1).in_sequence(&mut seq).returning(|_| Ok(()));
123     mock.writeback.expect().times(1).in_sequence(&mut seq).returning(|_| Ok(()));
124     mock.writeback.expect().times(1).in_sequence(&mut seq).returning(|_| Ok(()));
125 
126     assert!(zram_writeback
127         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, Instant::now())
128         .is_ok());
129 }
130 
131 #[test]
mark_and_flush_pages_before_backoff()132 fn mark_and_flush_pages_before_backoff() {
133     let mock = MockContext::new();
134     mock.writeback.expect().returning(|_| Ok(()));
135     mock.write_writeback_limit.expect().returning(|_| Ok(()));
136     mock.set_idle.expect().returning(|_| Ok(()));
137     mock.setup_default_meminfo();
138     mock.setup_default_writeback_limit_read();
139     let params = Params { backoff_duration: Duration::from_secs(100), ..Default::default() };
140     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
141     let base_time = Instant::now();
142     let mut zram_writeback =
143         ZramWriteback::new(DEFAULT_TOTAL_ZRAM_SIZE, DEFAULT_ZRAM_WRITEBACK_SIZE);
144     assert!(zram_writeback
145         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, base_time)
146         .is_ok());
147     mock.writeback.checkpoint();
148 
149     mock.writeback.expect().times(0);
150 
151     assert!(matches!(
152         zram_writeback.mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(
153             &params,
154             &stats,
155             base_time + Duration::from_secs(99)
156         ),
157         Err(Error::BackoffTime)
158     ));
159 }
160 
161 #[test]
mark_and_flush_pages_after_backoff()162 fn mark_and_flush_pages_after_backoff() {
163     let mock = MockContext::new();
164     mock.writeback.expect().returning(|_| Ok(()));
165     mock.write_writeback_limit.expect().returning(|_| Ok(()));
166     mock.set_idle.expect().returning(|_| Ok(()));
167     mock.setup_default_meminfo();
168     mock.setup_default_writeback_limit_read();
169     let params = Params { backoff_duration: Duration::from_secs(100), ..Default::default() };
170     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
171     let base_time = Instant::now();
172     let mut zram_writeback =
173         ZramWriteback::new(DEFAULT_TOTAL_ZRAM_SIZE, DEFAULT_ZRAM_WRITEBACK_SIZE);
174     assert!(zram_writeback
175         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, base_time)
176         .is_ok());
177     mock.writeback.checkpoint();
178     mock.write_writeback_limit.expect().returning(|_| Ok(()));
179     mock.set_idle.expect().returning(|_| Ok(()));
180     mock.setup_default_meminfo();
181     mock.setup_default_writeback_limit_read();
182 
183     mock.writeback.expect().times(3).returning(|_| Ok(()));
184 
185     assert!(zram_writeback
186         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(
187             &params,
188             &stats,
189             base_time + Duration::from_secs(100)
190         )
191         .is_ok());
192 }
193 
194 #[test]
mark_and_flush_pages_idle_time()195 fn mark_and_flush_pages_idle_time() {
196     let mock = MockContext::new();
197     mock.write_writeback_limit.expect().returning(|_| Ok(()));
198     mock.writeback.expect().returning(|_| Ok(()));
199     let meminfo = "MemTotal: 10000 kB
200         MemAvailable: 8000 kB";
201     mock.read_meminfo.expect().returning(|| Ok(meminfo.to_string()));
202     mock.setup_default_writeback_limit_read();
203     let params = Params {
204         min_idle: Duration::from_secs(3600),
205         max_idle: Duration::from_secs(4000),
206         ..Default::default()
207     };
208     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
209     let mut zram_writeback =
210         ZramWriteback::new(DEFAULT_TOTAL_ZRAM_SIZE, DEFAULT_ZRAM_WRITEBACK_SIZE);
211 
212     mock.set_idle.expect().with(eq("3747")).times(2).returning(|_| Ok(()));
213 
214     assert!(zram_writeback
215         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, Instant::now())
216         .is_ok());
217 }
218 
219 #[test]
mark_and_flush_pages_calculate_idle_failure()220 fn mark_and_flush_pages_calculate_idle_failure() {
221     let mock = MockContext::new();
222     mock.write_writeback_limit.expect().returning(|_| Ok(()));
223     mock.writeback.expect().returning(|_| Ok(()));
224     mock.setup_default_writeback_limit_read();
225     let params = Params {
226         min_idle: Duration::from_secs(4000),
227         max_idle: Duration::from_secs(3600),
228         ..Default::default()
229     };
230     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
231     let mut zram_writeback =
232         ZramWriteback::new(DEFAULT_TOTAL_ZRAM_SIZE, DEFAULT_ZRAM_WRITEBACK_SIZE);
233 
234     assert!(matches!(
235         zram_writeback.mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(
236             &params,
237             &stats,
238             Instant::now()
239         ),
240         Err(Error::CalculateIdle(_))
241     ));
242 }
243 
244 #[test]
mark_and_flush_pages_mark_idle_failure()245 fn mark_and_flush_pages_mark_idle_failure() {
246     let mock = MockContext::new();
247     mock.write_writeback_limit.expect().returning(|_| Ok(()));
248     mock.writeback.expect().returning(|_| Ok(()));
249     mock.setup_default_meminfo();
250     mock.setup_default_writeback_limit_read();
251     let params = Params::default();
252     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
253     let mut zram_writeback =
254         ZramWriteback::new(DEFAULT_TOTAL_ZRAM_SIZE, DEFAULT_ZRAM_WRITEBACK_SIZE);
255 
256     mock.set_idle.expect().returning(|_| Err(std::io::Error::other("error")));
257 
258     assert!(matches!(
259         zram_writeback.mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(
260             &params,
261             &stats,
262             Instant::now()
263         ),
264         Err(Error::MarkIdle(_))
265     ));
266 }
267 
268 #[test]
mark_and_flush_pages_skip_huge_idle()269 fn mark_and_flush_pages_skip_huge_idle() {
270     let mock = MockContext::new();
271     mock.write_writeback_limit.expect().returning(|_| Ok(()));
272     mock.set_idle.expect().returning(|_| Ok(()));
273     mock.setup_default_meminfo();
274     mock.setup_default_writeback_limit_read();
275     let params = Params { huge_idle: false, ..Default::default() };
276     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
277     let mut zram_writeback =
278         ZramWriteback::new(DEFAULT_TOTAL_ZRAM_SIZE, DEFAULT_ZRAM_WRITEBACK_SIZE);
279 
280     mock.writeback.expect().with(eq("huge_idle")).times(0).returning(|_| Ok(()));
281     mock.writeback.expect().with(eq("idle")).times(1).returning(|_| Ok(()));
282     mock.writeback.expect().with(eq("huge")).times(1).returning(|_| Ok(()));
283 
284     assert!(zram_writeback
285         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, Instant::now())
286         .is_ok());
287 }
288 
289 #[test]
mark_and_flush_pages_skip_idle()290 fn mark_and_flush_pages_skip_idle() {
291     let mock = MockContext::new();
292     mock.write_writeback_limit.expect().returning(|_| Ok(()));
293     mock.set_idle.expect().returning(|_| Ok(()));
294     mock.setup_default_meminfo();
295     mock.setup_default_writeback_limit_read();
296     let params = Params { idle: false, ..Default::default() };
297     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
298     let mut zram_writeback =
299         ZramWriteback::new(DEFAULT_TOTAL_ZRAM_SIZE, DEFAULT_ZRAM_WRITEBACK_SIZE);
300 
301     mock.writeback.expect().with(eq("huge_idle")).times(1).returning(|_| Ok(()));
302     mock.writeback.expect().with(eq("idle")).times(0).returning(|_| Ok(()));
303     mock.writeback.expect().with(eq("huge")).times(1).returning(|_| Ok(()));
304 
305     assert!(zram_writeback
306         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, Instant::now())
307         .is_ok());
308 }
309 
310 #[test]
mark_and_flush_pages_skip_huge()311 fn mark_and_flush_pages_skip_huge() {
312     let mock = MockContext::new();
313     mock.write_writeback_limit.expect().returning(|_| Ok(()));
314     mock.set_idle.expect().returning(|_| Ok(()));
315     mock.setup_default_meminfo();
316     mock.setup_default_writeback_limit_read();
317     let params = Params { huge: false, ..Default::default() };
318     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
319     let mut zram_writeback =
320         ZramWriteback::new(DEFAULT_TOTAL_ZRAM_SIZE, DEFAULT_ZRAM_WRITEBACK_SIZE);
321 
322     mock.writeback.expect().with(eq("huge_idle")).times(1).returning(|_| Ok(()));
323     mock.writeback.expect().with(eq("idle")).times(1).returning(|_| Ok(()));
324     mock.writeback.expect().with(eq("huge")).times(0).returning(|_| Ok(()));
325 
326     assert!(zram_writeback
327         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, Instant::now())
328         .is_ok());
329 }
330 
331 #[test]
mark_and_flush_pages_write_limit_from_orig_data_size()332 fn mark_and_flush_pages_write_limit_from_orig_data_size() {
333     let mock = MockContext::new();
334     mock.writeback.expect().returning(|_| Ok(()));
335     mock.set_idle.expect().returning(|_| Ok(()));
336     mock.setup_default_meminfo();
337     mock.setup_default_writeback_limit_read();
338     let params = Params {
339         max_bytes: 600 * DEFAULT_PAGE_SIZE,
340         min_bytes: 10 * DEFAULT_PAGE_SIZE,
341         ..Default::default()
342     };
343     // zram utilization is 25%
344     let stats = Stats { orig_data_size: 500 * DEFAULT_PAGE_SIZE, ..Default::default() };
345     let mut zram_writeback = ZramWriteback::new_with_page_size(
346         2000 * DEFAULT_PAGE_SIZE,
347         1000 * DEFAULT_PAGE_SIZE,
348         DEFAULT_PAGE_SIZE,
349     );
350 
351     // Writeback limit is 25% of max_bytes.
352     mock.write_writeback_limit.expect().with(eq("150")).times(1).returning(|_| Ok(()));
353 
354     assert!(zram_writeback
355         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, Instant::now())
356         .is_ok());
357 }
358 
359 #[test]
mark_and_flush_pages_write_limit_from_orig_data_size_with_big_page_size()360 fn mark_and_flush_pages_write_limit_from_orig_data_size_with_big_page_size() {
361     let mock = MockContext::new();
362     mock.writeback.expect().returning(|_| Ok(()));
363     mock.set_idle.expect().returning(|_| Ok(()));
364     mock.setup_default_meminfo();
365     mock.setup_default_writeback_limit_read();
366     let page_size = 2 * DEFAULT_PAGE_SIZE;
367     let params =
368         Params { max_bytes: 600 * page_size, min_bytes: 10 * page_size, ..Default::default() };
369     // zram utilization is 25%
370     let stats = Stats { orig_data_size: 500 * page_size, ..Default::default() };
371     let mut zram_writeback =
372         ZramWriteback::new_with_page_size(2000 * page_size, 1000 * page_size, page_size);
373 
374     // Writeback limit is 25% of maxPages.
375     mock.write_writeback_limit.expect().with(eq("150")).times(1).returning(|_| Ok(()));
376 
377     assert!(zram_writeback
378         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, Instant::now())
379         .is_ok());
380 }
381 
382 #[test]
mark_and_flush_pages_write_limit_capped_by_current_writeback_size()383 fn mark_and_flush_pages_write_limit_capped_by_current_writeback_size() {
384     let mock = MockContext::new();
385     mock.writeback.expect().returning(|_| Ok(()));
386     mock.set_idle.expect().returning(|_| Ok(()));
387     mock.setup_default_meminfo();
388     mock.setup_default_writeback_limit_read();
389     let params = Params {
390         max_bytes: 600 * DEFAULT_PAGE_SIZE,
391         min_bytes: 10 * DEFAULT_PAGE_SIZE,
392         ..Default::default()
393     };
394     // zram utilization is 25%
395     let stats =
396         Stats { orig_data_size: 500 * DEFAULT_PAGE_SIZE, current_writeback_pages: 1000 - 50 };
397     let mut zram_writeback = ZramWriteback::new_with_page_size(
398         2000 * DEFAULT_PAGE_SIZE,
399         1000 * DEFAULT_PAGE_SIZE,
400         DEFAULT_PAGE_SIZE,
401     );
402 
403     // Writeback disk only has 50 pages left.
404     mock.write_writeback_limit.expect().with(eq("50")).times(1).returning(|_| Ok(()));
405 
406     assert!(zram_writeback
407         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, Instant::now())
408         .is_ok());
409 }
410 
411 #[test]
mark_and_flush_pages_write_limit_capped_by_min_pages()412 fn mark_and_flush_pages_write_limit_capped_by_min_pages() {
413     let mock = MockContext::new();
414     mock.writeback.expect().returning(|_| Ok(()));
415     mock.set_idle.expect().returning(|_| Ok(()));
416     mock.setup_default_meminfo();
417     mock.setup_default_writeback_limit_read();
418     let params = Params {
419         max_bytes: 500 * DEFAULT_PAGE_SIZE,
420         min_bytes: 6 * DEFAULT_PAGE_SIZE,
421         ..Default::default()
422     };
423     // zram utilization is 1%
424     let stats = Stats { orig_data_size: 20 * DEFAULT_PAGE_SIZE, ..Default::default() };
425     let mut zram_writeback = ZramWriteback::new_with_page_size(
426         2000 * DEFAULT_PAGE_SIZE,
427         1000 * DEFAULT_PAGE_SIZE,
428         DEFAULT_PAGE_SIZE,
429     );
430 
431     // Writeback limit is 5 pages (= 1% of 500 pages). But it is lower than min pages.
432     mock.write_writeback_limit.expect().times(0);
433 
434     assert!(matches!(
435         zram_writeback.mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(
436             &params,
437             &stats,
438             Instant::now()
439         ),
440         Err(Error::Limit)
441     ));
442 }
443 
444 #[test]
mark_and_flush_pages_write_limit_capped_by_daily_limit_with_no_log()445 fn mark_and_flush_pages_write_limit_capped_by_daily_limit_with_no_log() {
446     let mock = MockContext::new();
447     mock.writeback.expect().returning(|_| Ok(()));
448     mock.set_idle.expect().returning(|_| Ok(()));
449     mock.setup_default_meminfo();
450     mock.setup_default_writeback_limit_read();
451     let params = Params {
452         max_bytes: 600 * DEFAULT_PAGE_SIZE,
453         min_bytes: 10 * DEFAULT_PAGE_SIZE,
454         max_bytes_per_day: 100 * DEFAULT_PAGE_SIZE,
455         ..Default::default()
456     };
457     // zram utilization is 25%
458     let stats = Stats { orig_data_size: 500 * DEFAULT_PAGE_SIZE, current_writeback_pages: 0 };
459     let mut zram_writeback = ZramWriteback::new_with_page_size(
460         2000 * DEFAULT_PAGE_SIZE,
461         1000 * DEFAULT_PAGE_SIZE,
462         DEFAULT_PAGE_SIZE,
463     );
464 
465     // Writeback limit is 25% of max_bytes. But use smaller maxPagesPerDay as the limit.
466     mock.write_writeback_limit.expect().with(eq("100")).times(1).returning(|_| Ok(()));
467 
468     assert!(zram_writeback
469         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, Instant::now())
470         .is_ok());
471 }
472 
473 #[test]
mark_and_flush_pages_write_limit_capped_by_daily_limit()474 fn mark_and_flush_pages_write_limit_capped_by_daily_limit() {
475     let mock = MockContext::new();
476     mock.writeback.expect().returning(|_| Ok(()));
477     mock.set_idle.expect().returning(|_| Ok(()));
478     mock.setup_default_meminfo();
479     let params = Params {
480         max_bytes: 600 * DEFAULT_PAGE_SIZE,
481         min_bytes: 10 * DEFAULT_PAGE_SIZE,
482         max_bytes_per_day: 100 * DEFAULT_PAGE_SIZE,
483         ..Default::default()
484     };
485     let stats = Stats { orig_data_size: 500 * DEFAULT_PAGE_SIZE, current_writeback_pages: 0 };
486     let mut zram_writeback = ZramWriteback::new_with_page_size(
487         2000 * DEFAULT_PAGE_SIZE,
488         1000 * DEFAULT_PAGE_SIZE,
489         DEFAULT_PAGE_SIZE,
490     );
491     let base_point = Instant::now();
492 
493     // Sets 100 as the daily limit for the first time.
494     mock.write_writeback_limit.expect().with(eq("100")).times(1).returning(|_| Ok(()));
495     // Load updated writeback_limit as the initial value.
496     mock.read_writeback_limit.expect().times(1).returning(|| Ok("100".to_string()));
497     // On first writeback, 40 pages are written back.
498     mock.read_writeback_limit.expect().returning(|| Ok("60".to_string()));
499 
500     assert!(zram_writeback
501         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, base_point)
502         .is_ok());
503 
504     // Daily limit with the history is applied on second markAndFlushPages.
505     mock.write_writeback_limit.expect().with(eq("60")).times(1).returning(|_| Ok(()));
506 
507     assert!(zram_writeback
508         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(
509             &params,
510             &stats,
511             base_point + Duration::from_secs(3600)
512         )
513         .is_ok());
514 }
515 
516 #[test]
mark_and_flush_pages_write_limit_capped_by_daily_limit_expired()517 fn mark_and_flush_pages_write_limit_capped_by_daily_limit_expired() {
518     let mock = MockContext::new();
519     mock.writeback.expect().returning(|_| Ok(()));
520     mock.set_idle.expect().returning(|_| Ok(()));
521     mock.setup_default_meminfo();
522     let params = Params {
523         max_bytes: 600 * DEFAULT_PAGE_SIZE,
524         min_bytes: 10 * DEFAULT_PAGE_SIZE,
525         max_bytes_per_day: 100 * DEFAULT_PAGE_SIZE,
526         ..Default::default()
527     };
528     let stats = Stats { orig_data_size: 500 * DEFAULT_PAGE_SIZE, current_writeback_pages: 0 };
529     let mut zram_writeback = ZramWriteback::new_with_page_size(
530         2000 * DEFAULT_PAGE_SIZE,
531         1000 * DEFAULT_PAGE_SIZE,
532         DEFAULT_PAGE_SIZE,
533     );
534     let base_point = Instant::now();
535 
536     // Sets 100 as the daily limit for the first time.
537     mock.write_writeback_limit.expect().with(eq("100")).times(1).returning(|_| Ok(()));
538     // Load updated writeback_limit as the initial value.
539     mock.read_writeback_limit.expect().times(1).returning(|| Ok("100\n".to_string()));
540     // On first writeback, 40 pages are written back.
541     mock.read_writeback_limit.expect().returning(|| Ok("60\n".to_string()));
542 
543     assert!(zram_writeback
544         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, base_point)
545         .is_ok());
546 
547     // On second time, the history is expired after 24 hours.
548     mock.write_writeback_limit.expect().with(eq("100")).times(1).returning(|_| Ok(()));
549     assert!(zram_writeback
550         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(
551             &params,
552             &stats,
553             base_point + Duration::from_secs(24 * 3600)
554         )
555         .is_ok());
556 }
557 
558 #[test]
mark_and_flush_pages_skip_on_write_limit()559 fn mark_and_flush_pages_skip_on_write_limit() {
560     let mock = MockContext::new();
561     mock.write_writeback_limit.expect().returning(|_| Ok(()));
562     mock.set_idle.expect().returning(|_| Ok(()));
563     mock.setup_default_meminfo();
564     let params = Params::default();
565     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
566     let mut zram_writeback = ZramWriteback::new_with_page_size(
567         DEFAULT_TOTAL_ZRAM_SIZE,
568         DEFAULT_ZRAM_WRITEBACK_SIZE,
569         DEFAULT_PAGE_SIZE,
570     );
571 
572     // Load updated writeback_limit as the initial value.
573     mock.read_writeback_limit.expect().times(1).returning(|| Ok("100\n".to_string()));
574     // On first writeback, writeback limit becomes zero and skip following writeback.
575     mock.read_writeback_limit.expect().returning(|| Ok("0\n".to_string()));
576     mock.writeback.expect().with(eq("huge_idle")).times(1).returning(|_| Ok(()));
577     mock.writeback.expect().with(eq("idle")).times(0);
578     mock.writeback.expect().with(eq("huge")).times(0);
579 
580     assert!(zram_writeback
581         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, Instant::now())
582         .is_ok());
583 }
584 
585 #[test]
mark_and_flush_pages_skip_next_by_daily_limit()586 fn mark_and_flush_pages_skip_next_by_daily_limit() {
587     let mock = MockContext::new();
588     mock.writeback.expect().returning(|_| Ok(()));
589     mock.write_writeback_limit.expect().returning(|_| Ok(()));
590     mock.set_idle.expect().returning(|_| Ok(()));
591     mock.setup_default_meminfo();
592     let params = Params { max_bytes_per_day: 100 * DEFAULT_PAGE_SIZE, ..Default::default() };
593     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
594     let mut zram_writeback = ZramWriteback::new_with_page_size(
595         DEFAULT_TOTAL_ZRAM_SIZE,
596         DEFAULT_ZRAM_WRITEBACK_SIZE,
597         DEFAULT_PAGE_SIZE,
598     );
599     let base_point = Instant::now();
600 
601     // Load updated writeback_limit as the initial value.
602     mock.read_writeback_limit.expect().times(1).returning(|| Ok("100\n".to_string()));
603     // On first writeback, writeback limit becomes zero and skip following writeback.
604     mock.read_writeback_limit.expect().returning(|| Ok("0\n".to_string()));
605     assert!(zram_writeback
606         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, base_point)
607         .is_ok());
608 
609     mock.write_writeback_limit.checkpoint();
610     mock.write_writeback_limit.expect().times(0);
611     assert!(matches!(
612         zram_writeback.mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(
613             &params,
614             &stats,
615             base_point + params.backoff_duration
616         ),
617         Err(Error::Limit)
618     ));
619 
620     mock.write_writeback_limit.checkpoint();
621     mock.writeback.expect().returning(|_| Ok(()));
622     mock.set_idle.expect().returning(|_| Ok(()));
623     mock.setup_default_meminfo();
624     mock.setup_default_writeback_limit_read();
625     mock.write_writeback_limit.expect().returning(|_| Ok(()));
626     // writeback succeeds 24 hours after.
627     assert!(zram_writeback
628         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(
629             &params,
630             &stats,
631             base_point + Duration::from_secs(24 * 3600)
632         )
633         .is_ok());
634 }
635 
636 #[test]
mark_and_flush_pages_fails_to_record_history_by_writeback_error()637 fn mark_and_flush_pages_fails_to_record_history_by_writeback_error() {
638     let mock = MockContext::new();
639     mock.write_writeback_limit.expect().returning(|_| Ok(()));
640     mock.set_idle.expect().returning(|_| Ok(()));
641     mock.setup_default_meminfo();
642     let params = Params { max_bytes_per_day: 100 * DEFAULT_PAGE_SIZE, ..Default::default() };
643     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
644     let mut zram_writeback = ZramWriteback::new_with_page_size(
645         DEFAULT_TOTAL_ZRAM_SIZE,
646         DEFAULT_ZRAM_WRITEBACK_SIZE,
647         DEFAULT_PAGE_SIZE,
648     );
649     let base_point = Instant::now();
650 
651     // Load updated writeback_limit as the initial value.
652     mock.read_writeback_limit.expect().times(1).returning(|| Ok("100\n".to_string()));
653     mock.writeback.expect().returning(|_| Err(std::io::Error::other("error")));
654     assert!(zram_writeback
655         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, base_point)
656         .is_err());
657 
658     mock.write_writeback_limit.checkpoint();
659     mock.write_writeback_limit.expect().times(0);
660     assert!(matches!(
661         zram_writeback.mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(
662             &params,
663             &stats,
664             base_point + params.backoff_duration
665         ),
666         Err(Error::Limit)
667     ));
668 }
669 
670 #[test]
mark_and_flush_pages_fails_to_record_history_by_limit_load_error()671 fn mark_and_flush_pages_fails_to_record_history_by_limit_load_error() {
672     let mock = MockContext::new();
673     mock.writeback.expect().returning(|_| Ok(()));
674     mock.write_writeback_limit.expect().returning(|_| Ok(()));
675     mock.set_idle.expect().returning(|_| Ok(()));
676     mock.setup_default_meminfo();
677     let params = Params { max_bytes_per_day: 100 * DEFAULT_PAGE_SIZE, ..Default::default() };
678     let stats = Stats { orig_data_size: params.max_bytes, ..Default::default() };
679     let mut zram_writeback = ZramWriteback::new_with_page_size(
680         DEFAULT_TOTAL_ZRAM_SIZE,
681         DEFAULT_ZRAM_WRITEBACK_SIZE,
682         DEFAULT_PAGE_SIZE,
683     );
684     let base_point = Instant::now();
685 
686     mock.read_writeback_limit.expect().times(1).returning(|| Ok("100\n".to_string()));
687     // read writeback_limit fails just after writeback.
688     mock.read_writeback_limit.expect().returning(|| Err(std::io::Error::other("error")));
689     assert!(zram_writeback
690         .mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(&params, &stats, base_point)
691         .is_ok());
692 
693     mock.write_writeback_limit.checkpoint();
694     mock.write_writeback_limit.expect().times(0);
695     assert!(matches!(
696         zram_writeback.mark_and_flush_pages::<MockSysfsZramApi, MockMeminfoApi>(
697             &params,
698             &stats,
699             base_point + params.backoff_duration
700         ),
701         Err(Error::Limit)
702     ));
703 }
704