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 INLOOP_ITER 100 13 14 static char *huge_ptr; 15 static size_t huge_page_size; 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, huge_page_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 huge_page_size = default_huge_page_size(); 51 if (!huge_page_size) 52 ksft_exit_skip("Could not detect default hugetlb page size."); 53 54 free_hugepages = get_free_hugepages(); 55 if (free_hugepages != 1) { 56 ksft_exit_skip("This test needs one and only one page to execute. Got %lu\n", 57 free_hugepages); 58 } 59 60 while (max--) { 61 huge_ptr = mmap(NULL, huge_page_size, PROT_READ | PROT_WRITE, 62 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, 63 -1, 0); 64 65 if ((unsigned long)huge_ptr == -1) 66 ksft_exit_skip("Failed to allocated huge page\n"); 67 68 pthread_create(&thread1, NULL, madv, NULL); 69 pthread_create(&thread2, NULL, touch, NULL); 70 71 pthread_join(thread1, NULL); 72 pthread_join(thread2, NULL); 73 munmap(huge_ptr, huge_page_size); 74 } 75 76 return KSFT_PASS; 77 } 78