1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <pthread.h> |
3 | #include <stdio.h> |
4 | #include <stdlib.h> |
5 | #include <sys/mman.h> |
6 | #include <sys/types.h> |
7 | #include <unistd.h> |
8 | |
9 | #include "vm_util.h" |
10 | #include "../kselftest.h" |
11 | |
12 | #define MMAP_SIZE (1 << 21) |
13 | #define INLOOP_ITER 100 |
14 | |
15 | char *huge_ptr; |
16 | |
17 | /* Touch the memory while it is being madvised() */ |
18 | void *touch(void *unused) |
19 | { |
20 | char *ptr = (char *)huge_ptr; |
21 | |
22 | for (int i = 0; i < INLOOP_ITER; i++) |
23 | ptr[0] = '.'; |
24 | |
25 | return NULL; |
26 | } |
27 | |
28 | void *madv(void *unused) |
29 | { |
30 | usleep(rand() % 10); |
31 | |
32 | for (int i = 0; i < INLOOP_ITER; i++) |
33 | madvise(huge_ptr, MMAP_SIZE, MADV_DONTNEED); |
34 | |
35 | return NULL; |
36 | } |
37 | |
38 | int main(void) |
39 | { |
40 | unsigned long free_hugepages; |
41 | pthread_t thread1, thread2; |
42 | /* |
43 | * On kernel 6.4, we are able to reproduce the problem with ~1000 |
44 | * interactions |
45 | */ |
46 | int max = 10000; |
47 | |
48 | srand(getpid()); |
49 | |
50 | free_hugepages = get_free_hugepages(); |
51 | if (free_hugepages != 1) { |
52 | ksft_exit_skip(msg: "This test needs one and only one page to execute. Got %lu\n" , |
53 | free_hugepages); |
54 | } |
55 | |
56 | while (max--) { |
57 | huge_ptr = mmap(NULL, MMAP_SIZE, PROT_READ | PROT_WRITE, |
58 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, |
59 | -1, 0); |
60 | |
61 | if ((unsigned long)huge_ptr == -1) |
62 | ksft_exit_skip(msg: "Failed to allocated huge page\n" ); |
63 | |
64 | pthread_create(&thread1, NULL, madv, NULL); |
65 | pthread_create(&thread2, NULL, touch, NULL); |
66 | |
67 | pthread_join(thread1, NULL); |
68 | pthread_join(thread2, NULL); |
69 | munmap(huge_ptr, MMAP_SIZE); |
70 | } |
71 | |
72 | return KSFT_PASS; |
73 | } |
74 | |