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("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("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