1 /* IBM Corporation */ 2 /* 01/02/2003 Port to LTP avenkat (at) us.ibm.com */ 3 /* 06/30/2001 Port to Linux nsharoff (at) us.ibm.com */ 4 /* 5 * Copyright (c) International Business Machines Corp., 2003 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 15 * the GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22 /* 23 * This test mmaps over the tail of the brk segment, growing and 24 * shrinking brk over holes, while changing from small to large and 25 * large to small virtual memory representations. After mmaping over the 26 * end of the brk segment, it increases the brk which should split 27 * it into two segments (i.e. |---brk---|-mmap-|--more brk--|). Next it 28 * decreases the brk segment to the end of the map, and finally decreases 29 * it some more. Then more vmsegments are created by punching holes in 30 * the brk segments with munmap. This should cause the vm system to use a 31 * large virtual address space object to keep track of this process. The 32 * above test is then repeated using the large process object. After 33 * this, the brk is shrunk to less than 1 page before exiting in order to 34 * test the code which compacts large address space objects. It also asks 35 * for a huge mmap which is refused. 36 */ 37 38 #define _KMEMUSER 39 #include <sys/types.h> 40 #include <stdio.h> 41 #include <sys/mman.h> 42 #include <errno.h> 43 #include <unistd.h> 44 #include <limits.h> 45 #include <stdlib.h> 46 #include <stdint.h> 47 48 #include "test.h" 49 #include "tst_kernel.h" 50 51 char *TCID = "mmapstress03"; 52 FILE *temp; 53 int TST_TOTAL = 1; 54 55 int anyfail(); 56 void ok_exit(); 57 58 #define AS_SVSM_VSEG_MAX 48UL 59 #define AS_SVSM_MMAP_MAX 16UL 60 61 #define EXTRA_VSEGS 2L 62 #define NUM_SEGS (AS_SVSM_VSEG_MAX + EXTRA_VSEGS) 63 #define ERROR(M) (void)fprintf(stderr, "%s: errno = %d: " M "\n", TCID, \ 64 errno) 65 #define NEG1 (char *)-1 66 67 static void do_test(void* brk_max, long pagesize); 68 69 int main(void) 70 { 71 char *brk_max_addr, *hole_addr, *brk_start, *hole_start; 72 size_t pagesize = (size_t) sysconf(_SC_PAGE_SIZE); 73 int kernel_bits = tst_kernel_bits(); 74 75 if ((brk_start = sbrk(0)) == NEG1) { 76 ERROR("initial sbrk failed"); 77 anyfail(); 78 } 79 if ((u_long) brk_start % (u_long) pagesize) { 80 if (sbrk(pagesize - ((u_long) brk_start % (u_long) pagesize)) 81 == NEG1) { 82 ERROR("couldn't round up brk to a page boundary"); 83 anyfail(); 84 } 85 } 86 /* The brk is now at the beginning of a page. */ 87 88 if ((hole_addr = hole_start = sbrk(NUM_SEGS * 2 * pagesize)) == NEG1) { 89 ERROR("couldn't brk large space for segments"); 90 anyfail(); 91 } 92 if ((brk_max_addr = sbrk(0)) == NEG1) { 93 ERROR("couldn't find top of brk"); 94 anyfail(); 95 } 96 do_test((void*) brk_max_addr, pagesize); 97 98 /* now make holes and repeat test */ 99 while (hole_addr + pagesize < brk_max_addr) { 100 if (munmap(hole_addr, pagesize) == -1) { 101 ERROR("failed to munmap odd hole in brk segment"); 102 anyfail(); 103 } 104 hole_addr += 2 * pagesize; 105 } 106 107 if (brk_max_addr != sbrk(0)) { 108 ERROR("do_test should leave the top of brk where it began"); 109 anyfail(); 110 } 111 do_test((void*) brk_max_addr, pagesize); 112 113 /* Shrink brk */ 114 if (sbrk(-NUM_SEGS * pagesize) == NEG1) { 115 ERROR("couldn't brk back over holes"); 116 anyfail(); 117 } 118 if ((brk_max_addr = sbrk(0)) == NEG1) { 119 ERROR("couldn't find top of break again"); 120 anyfail(); 121 } 122 /* sbrked over about half the holes */ 123 124 hole_addr = hole_start + pagesize; /* munmap the other pages */ 125 while (hole_addr + pagesize < brk_max_addr) { 126 if (munmap(hole_addr, pagesize) == -1) { 127 ERROR("failed to munmap even hole in brk segment"); 128 anyfail(); 129 } 130 hole_addr += 2 * pagesize; 131 } 132 /* munmaped the rest of the brk except a little at the beginning */ 133 134 if (brk(brk_start) == -1) { 135 ERROR("failed to completely remove brk"); 136 anyfail(); 137 } 138 if (sbrk(pagesize) == NEG1 || sbrk(-pagesize) == NEG1) { 139 ERROR("failed to fiddle with brk at the end"); 140 anyfail(); 141 } 142 143 /* Ask for a ridiculously large mmap region at a high address */ 144 if (mmap((void*) (((uintptr_t)1) << ((sizeof(void*)<<3) - 1)) - pagesize, 145 (size_t) ((1ULL << (kernel_bits - 1)) - pagesize), 146 PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_FIXED | MAP_SHARED, 147 0, 0) 148 != (void*) - 1) { 149 ERROR("really large mmap didn't fail"); 150 anyfail(); 151 } 152 if (errno != ENOMEM && errno != EINVAL) { 153 ERROR("really large mmap didn't set errno = ENOMEM nor EINVAL"); 154 anyfail(); 155 } 156 157 ok_exit(); 158 tst_exit(); 159 } 160 161 /* 162 * do_test assumes that brk_max is a multiple of pagesize 163 */ 164 165 static void do_test(void* brk_max, long pagesize) 166 { 167 if (mmap((void*) ((long)brk_max - 3 * pagesize), (2 * pagesize), 168 PROT_READ | PROT_WRITE, 169 MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0) 170 == (void*) - 1) { 171 ERROR("mmap failed"); 172 anyfail(); 173 } 174 /* extend mmap */ 175 if (mmap((void*) ((long)brk_max - 2 * pagesize), (2 * pagesize), 176 PROT_READ | PROT_WRITE, 177 MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0) 178 == (void*) - 1) { 179 ERROR("mmap failed"); 180 anyfail(); 181 } 182 if (sbrk(pagesize) == NEG1) { 183 ERROR("sbrk failed to grow over mmaped region"); 184 anyfail(); 185 } 186 if (sbrk(-pagesize) == NEG1) { 187 ERROR("sbrk failed to shrink back to mmaped region"); 188 anyfail(); 189 } 190 if (sbrk(-pagesize) == NEG1) { 191 ERROR("sbrk failed to shrink over mmaped region more"); 192 anyfail(); 193 } 194 if (sbrk(-pagesize) == NEG1) { 195 ERROR("sbrk failed to shrink some more"); 196 anyfail(); 197 } 198 if (sbrk(2 * pagesize) == NEG1) { 199 ERROR("sbrk failed to change brk segment to original size"); 200 anyfail(); 201 } 202 } 203 204 void ok_exit(void) 205 { 206 tst_resm(TPASS, "Test passed"); 207 tst_exit(); 208 } 209 210 int anyfail(void) 211 { 212 tst_brkm(TFAIL, NULL, "Test failed"); 213 } 214