xref: /linux/tools/testing/selftests/mm/droppable.c (revision c16ce856e422e73a54c41131e0332de1afe09b8b)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2024 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4  */
5 
6 #include <assert.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <signal.h>
13 #include <sys/mman.h>
14 #include <linux/mman.h>
15 
16 #include "kselftest.h"
17 
18 int main(int argc, char *argv[])
19 {
20 	const size_t alloc_size = 2 * 1024 * 1024;
21 	int retry_count = 10;
22 	bool dropped;
23 	void *alloc;
24 
25 	ksft_print_header();
26 	ksft_set_plan(1);
27 
28 	alloc = mmap(0, alloc_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_DROPPABLE, -1, 0);
29 	if (alloc == MAP_FAILED) {
30 		if ((errno == EOPNOTSUPP) || (errno == EINVAL)) {
31 			ksft_test_result_skip("MAP_DROPPABLE not supported\n");
32 			exit(KSFT_SKIP);
33 		}
34 		ksft_test_result_fail("mmap error: %s\n", strerror(errno));
35 		exit(KSFT_FAIL);
36 	}
37 	memset(alloc, 'A', alloc_size);
38 
39 	while (retry_count--) {
40 		if (madvise(alloc, alloc_size, MADV_PAGEOUT)) {
41 			if (errno == EINVAL) {
42 				ksft_test_result_skip("madvise(MADV_PAGEOUT) not supported\n");
43 				exit(KSFT_SKIP);
44 			}
45 			ksft_test_result_fail("madvise(MADV_PAGEOUT) error: %s\n", strerror(errno));
46 			exit(KSFT_FAIL);
47 		}
48 
49 		dropped = memchr(alloc, 'A', alloc_size) == NULL;
50 
51 		/*
52 		 * Speculative reference can temporarily prevent some
53 		 * pages from getting dropped. So sleep and retry.
54 		 *
55 		 * If a page is not droppable for 10s, something
56 		 * is seriously messed up and we want to fail.
57 		 */
58 		if (dropped)
59 			break;
60 		sleep(1);
61 	}
62 
63 	ksft_test_result(dropped, "madvise(MADV_PAGEOUT) behavior\n");
64 
65 	ksft_finished();
66 }
67