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