1 // SPDX-License-Identifier: GPL-2.0 2 /* Test selecting other page sizes for mmap/shmget. */ 3 4 #define _GNU_SOURCE 5 #include <sys/mman.h> 6 #include <linux/mman.h> 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <sys/ipc.h> 10 #include <sys/shm.h> 11 #include <sys/stat.h> 12 #include <unistd.h> 13 #include <stdarg.h> 14 #include <string.h> 15 #include "vm_util.h" 16 #include "kselftest.h" 17 #include "hugepage_settings.h" 18 19 #if !defined(MAP_HUGETLB) 20 #define MAP_HUGETLB 0x40000 21 #endif 22 23 #define SHM_HUGETLB 04000 /* segment will use huge TLB pages */ 24 #ifndef SHM_HUGE_SHIFT 25 #define SHM_HUGE_SHIFT 26 26 #endif 27 28 #define NUM_PAGESIZES 5 29 #define NUM_PAGES 4 30 31 unsigned long page_sizes[NUM_PAGESIZES]; 32 int num_page_sizes; 33 34 int ilog2(unsigned long v) 35 { 36 int l = 0; 37 while ((1UL << l) < v) 38 l++; 39 return l; 40 } 41 42 void show(unsigned long ps) 43 { 44 if (ps == getpagesize()) 45 return; 46 47 ksft_print_msg("%luMB: %lu\n", ps >> 20, hugetlb_free_pages(ps)); 48 } 49 50 void test_mmap(unsigned long size, unsigned flags) 51 { 52 char *map; 53 unsigned long before, after; 54 55 before = hugetlb_free_pages(size); 56 map = mmap(NULL, size*NUM_PAGES, PROT_READ|PROT_WRITE, 57 MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|flags, -1, 0); 58 if (map == MAP_FAILED) 59 ksft_exit_fail_msg("mmap: %s\n", strerror(errno)); 60 61 memset(map, 0xff, size*NUM_PAGES); 62 after = hugetlb_free_pages(size); 63 64 show(size); 65 ksft_test_result(size == getpagesize() || (before - after) == NUM_PAGES, 66 "%s mmap %lu %x\n", __func__, size, flags); 67 68 if (munmap(map, size * NUM_PAGES)) 69 ksft_exit_fail_msg("%s: unmap %s\n", __func__, strerror(errno)); 70 } 71 72 void test_shmget(unsigned long size, unsigned flags) 73 { 74 int id; 75 unsigned long before, after; 76 struct shm_info i; 77 char *map; 78 79 before = hugetlb_free_pages(size); 80 id = shmget(IPC_PRIVATE, size * NUM_PAGES, IPC_CREAT|0600|flags); 81 if (id < 0) { 82 if (errno == EPERM) { 83 ksft_test_result_skip("shmget requires root privileges: %s\n", 84 strerror(errno)); 85 return; 86 } 87 ksft_exit_fail_msg("shmget: %s\n", strerror(errno)); 88 } 89 90 if (shmctl(id, SHM_INFO, (void *)&i) < 0) 91 ksft_exit_fail_msg("shmctl: %s\n", strerror(errno)); 92 93 map = shmat(id, NULL, 0600); 94 if (map == MAP_FAILED) 95 ksft_exit_fail_msg("shmat: %s\n", strerror(errno)); 96 97 shmctl(id, IPC_RMID, NULL); 98 99 memset(map, 0xff, size*NUM_PAGES); 100 after = hugetlb_free_pages(size); 101 102 show(size); 103 ksft_test_result(size == getpagesize() || (before - after) == NUM_PAGES, 104 "%s: mmap %lu %x\n", __func__, size, flags); 105 if (shmdt(map)) 106 ksft_exit_fail_msg("%s: shmdt: %s\n", __func__, strerror(errno)); 107 } 108 109 void find_pagesizes(void) 110 { 111 unsigned long largest = getpagesize(); 112 int i; 113 114 num_page_sizes = hugetlb_setup(NUM_PAGES, page_sizes, ARRAY_SIZE(page_sizes)); 115 116 for (i = 0; i < num_page_sizes; i++) 117 if (page_sizes[i] > largest) 118 largest = page_sizes[i]; 119 120 shm_limits_prepare(NUM_PAGES * largest); 121 } 122 123 int main(void) 124 { 125 unsigned default_hps = default_huge_page_size(); 126 int i; 127 128 ksft_print_header(); 129 130 find_pagesizes(); 131 132 if (!num_page_sizes) 133 ksft_finished(); 134 135 ksft_set_plan(2 * num_page_sizes + 3); 136 137 for (i = 0; i < num_page_sizes; i++) { 138 unsigned long ps = page_sizes[i]; 139 int arg = ilog2(ps) << MAP_HUGE_SHIFT; 140 141 ksft_print_msg("Testing %luMB mmap with shift %x\n", ps >> 20, arg); 142 test_mmap(ps, MAP_HUGETLB | arg); 143 } 144 145 ksft_print_msg("Testing default huge mmap\n"); 146 test_mmap(default_hps, MAP_HUGETLB); 147 148 ksft_print_msg("Testing non-huge shmget\n"); 149 test_shmget(getpagesize(), 0); 150 151 for (i = 0; i < num_page_sizes; i++) { 152 unsigned long ps = page_sizes[i]; 153 int arg = ilog2(ps) << SHM_HUGE_SHIFT; 154 ksft_print_msg("Testing %luMB shmget with shift %x\n", ps >> 20, arg); 155 test_shmget(ps, SHM_HUGETLB | arg); 156 } 157 158 ksft_print_msg("default huge shmget\n"); 159 test_shmget(default_hps, SHM_HUGETLB); 160 161 ksft_finished(); 162 } 163 164 SHM_LIMITS_RESTORE() 165