Home | History | Annotate | Download | only in mmapstress
      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