• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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