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 #include <setjmp.h> 9 #include <signal.h> 10 11 #include "vm_util.h" 12 #include "../kselftest.h" 13 14 #define INLOOP_ITER 100 15 16 static char *huge_ptr; 17 static size_t huge_page_size; 18 19 static sigjmp_buf sigbuf; 20 static bool sigbus_triggered; 21 22 static void signal_handler(int signal) 23 { 24 if (signal == SIGBUS) { 25 sigbus_triggered = true; 26 siglongjmp(sigbuf, 1); 27 } 28 } 29 30 /* Touch the memory while it is being madvised() */ 31 void *touch(void *unused) 32 { 33 char *ptr = (char *)huge_ptr; 34 35 if (sigsetjmp(sigbuf, 1)) 36 return NULL; 37 38 for (int i = 0; i < INLOOP_ITER; i++) 39 ptr[0] = '.'; 40 41 return NULL; 42 } 43 44 void *madv(void *unused) 45 { 46 usleep(rand() % 10); 47 48 for (int i = 0; i < INLOOP_ITER; i++) 49 madvise(huge_ptr, huge_page_size, MADV_DONTNEED); 50 51 return NULL; 52 } 53 54 int main(void) 55 { 56 unsigned long free_hugepages; 57 pthread_t thread1, thread2; 58 /* 59 * On kernel 6.4, we are able to reproduce the problem with ~1000 60 * interactions 61 */ 62 int max = 10000; 63 int err; 64 65 ksft_print_header(); 66 ksft_set_plan(1); 67 68 srand(getpid()); 69 70 if (signal(SIGBUS, signal_handler) == SIG_ERR) 71 ksft_exit_skip("Could not register signal handler."); 72 73 huge_page_size = default_huge_page_size(); 74 if (!huge_page_size) 75 ksft_exit_skip("Could not detect default hugetlb page size."); 76 77 ksft_print_msg("[INFO] detected default hugetlb page size: %zu KiB\n", 78 huge_page_size / 1024); 79 80 free_hugepages = get_free_hugepages(); 81 if (free_hugepages != 1) { 82 ksft_exit_skip("This test needs one and only one page to execute. Got %lu\n", 83 free_hugepages); 84 } 85 86 while (max--) { 87 huge_ptr = mmap(NULL, huge_page_size, PROT_READ | PROT_WRITE, 88 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, 89 -1, 0); 90 91 if ((unsigned long)huge_ptr == -1) 92 ksft_exit_skip("Failed to allocated huge page\n"); 93 94 pthread_create(&thread1, NULL, madv, NULL); 95 pthread_create(&thread2, NULL, touch, NULL); 96 97 pthread_join(thread1, NULL); 98 pthread_join(thread2, NULL); 99 munmap(huge_ptr, huge_page_size); 100 } 101 102 ksft_test_result(!sigbus_triggered, "SIGBUS behavior\n"); 103 104 err = ksft_get_fail_cnt(); 105 if (err) 106 ksft_exit_fail_msg("%d out of %d tests failed\n", 107 err, ksft_test_num()); 108 ksft_exit_pass(); 109 } 110