1 /* IBM Corporation */
2 /* 01/02/2003 Port to LTP avenkat@us.ibm.com */
3 /* 06/30/2001 Port to Linux nsharoff@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
main(void)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
do_test(void * brk_max,long pagesize)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
ok_exit(void)204 void ok_exit(void)
205 {
206 tst_resm(TPASS, "Test passed");
207 tst_exit();
208 }
209
anyfail(void)210 int anyfail(void)
211 {
212 tst_brkm(TFAIL, NULL, "Test failed");
213 }
214