You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
6.0 KiB
214 lines
6.0 KiB
/* IBM Corporation */
|
|
/* 01/02/2003 Port to LTP avenkat@us.ibm.com */
|
|
/* 06/30/2001 Port to Linux nsharoff@us.ibm.com */
|
|
/*
|
|
* Copyright (c) International Business Machines Corp., 2003
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
|
* the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/*
|
|
* This test mmaps over the tail of the brk segment, growing and
|
|
* shrinking brk over holes, while changing from small to large and
|
|
* large to small virtual memory representations. After mmaping over the
|
|
* end of the brk segment, it increases the brk which should split
|
|
* it into two segments (i.e. |---brk---|-mmap-|--more brk--|). Next it
|
|
* decreases the brk segment to the end of the map, and finally decreases
|
|
* it some more. Then more vmsegments are created by punching holes in
|
|
* the brk segments with munmap. This should cause the vm system to use a
|
|
* large virtual address space object to keep track of this process. The
|
|
* above test is then repeated using the large process object. After
|
|
* this, the brk is shrunk to less than 1 page before exiting in order to
|
|
* test the code which compacts large address space objects. It also asks
|
|
* for a huge mmap which is refused.
|
|
*/
|
|
|
|
#define _KMEMUSER
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <sys/mman.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
|
|
#include "test.h"
|
|
#include "tst_kernel.h"
|
|
|
|
char *TCID = "mmapstress03";
|
|
FILE *temp;
|
|
int TST_TOTAL = 1;
|
|
|
|
int anyfail();
|
|
void ok_exit();
|
|
|
|
#define AS_SVSM_VSEG_MAX 48UL
|
|
#define AS_SVSM_MMAP_MAX 16UL
|
|
|
|
#define EXTRA_VSEGS 2L
|
|
#define NUM_SEGS (AS_SVSM_VSEG_MAX + EXTRA_VSEGS)
|
|
#define ERROR(M) (void)fprintf(stderr, "%s: errno = %d: " M "\n", TCID, \
|
|
errno)
|
|
#define NEG1 (char *)-1
|
|
|
|
static void do_test(void* brk_max, long pagesize);
|
|
|
|
int main(void)
|
|
{
|
|
char *brk_max_addr, *hole_addr, *brk_start, *hole_start;
|
|
size_t pagesize = (size_t) sysconf(_SC_PAGE_SIZE);
|
|
int kernel_bits = tst_kernel_bits();
|
|
|
|
if ((brk_start = sbrk(0)) == NEG1) {
|
|
ERROR("initial sbrk failed");
|
|
anyfail();
|
|
}
|
|
if ((u_long) brk_start % (u_long) pagesize) {
|
|
if (sbrk(pagesize - ((u_long) brk_start % (u_long) pagesize))
|
|
== NEG1) {
|
|
ERROR("couldn't round up brk to a page boundary");
|
|
anyfail();
|
|
}
|
|
}
|
|
/* The brk is now at the beginning of a page. */
|
|
|
|
if ((hole_addr = hole_start = sbrk(NUM_SEGS * 2 * pagesize)) == NEG1) {
|
|
ERROR("couldn't brk large space for segments");
|
|
anyfail();
|
|
}
|
|
if ((brk_max_addr = sbrk(0)) == NEG1) {
|
|
ERROR("couldn't find top of brk");
|
|
anyfail();
|
|
}
|
|
do_test((void*) brk_max_addr, pagesize);
|
|
|
|
/* now make holes and repeat test */
|
|
while (hole_addr + pagesize < brk_max_addr) {
|
|
if (munmap(hole_addr, pagesize) == -1) {
|
|
ERROR("failed to munmap odd hole in brk segment");
|
|
anyfail();
|
|
}
|
|
hole_addr += 2 * pagesize;
|
|
}
|
|
|
|
if (brk_max_addr != sbrk(0)) {
|
|
ERROR("do_test should leave the top of brk where it began");
|
|
anyfail();
|
|
}
|
|
do_test((void*) brk_max_addr, pagesize);
|
|
|
|
/* Shrink brk */
|
|
if (sbrk(-NUM_SEGS * pagesize) == NEG1) {
|
|
ERROR("couldn't brk back over holes");
|
|
anyfail();
|
|
}
|
|
if ((brk_max_addr = sbrk(0)) == NEG1) {
|
|
ERROR("couldn't find top of break again");
|
|
anyfail();
|
|
}
|
|
/* sbrked over about half the holes */
|
|
|
|
hole_addr = hole_start + pagesize; /* munmap the other pages */
|
|
while (hole_addr + pagesize < brk_max_addr) {
|
|
if (munmap(hole_addr, pagesize) == -1) {
|
|
ERROR("failed to munmap even hole in brk segment");
|
|
anyfail();
|
|
}
|
|
hole_addr += 2 * pagesize;
|
|
}
|
|
/* munmaped the rest of the brk except a little at the beginning */
|
|
|
|
if (brk(brk_start) == -1) {
|
|
ERROR("failed to completely remove brk");
|
|
anyfail();
|
|
}
|
|
if (sbrk(pagesize) == NEG1 || sbrk(-pagesize) == NEG1) {
|
|
ERROR("failed to fiddle with brk at the end");
|
|
anyfail();
|
|
}
|
|
|
|
/* Ask for a ridiculously large mmap region at a high address */
|
|
if (mmap((void*) (((uintptr_t)1) << ((sizeof(void*)<<3) - 1)) - pagesize,
|
|
(size_t) ((1ULL << (kernel_bits - 1)) - pagesize),
|
|
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_FIXED | MAP_SHARED,
|
|
0, 0)
|
|
!= (void*) - 1) {
|
|
ERROR("really large mmap didn't fail");
|
|
anyfail();
|
|
}
|
|
if (errno != ENOMEM && errno != EINVAL) {
|
|
ERROR("really large mmap didn't set errno = ENOMEM nor EINVAL");
|
|
anyfail();
|
|
}
|
|
|
|
ok_exit();
|
|
tst_exit();
|
|
}
|
|
|
|
/*
|
|
* do_test assumes that brk_max is a multiple of pagesize
|
|
*/
|
|
|
|
static void do_test(void* brk_max, long pagesize)
|
|
{
|
|
if (mmap((void*) ((long)brk_max - 3 * pagesize), (2 * pagesize),
|
|
PROT_READ | PROT_WRITE,
|
|
MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0)
|
|
== (void*) - 1) {
|
|
ERROR("mmap failed");
|
|
anyfail();
|
|
}
|
|
/* extend mmap */
|
|
if (mmap((void*) ((long)brk_max - 2 * pagesize), (2 * pagesize),
|
|
PROT_READ | PROT_WRITE,
|
|
MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0)
|
|
== (void*) - 1) {
|
|
ERROR("mmap failed");
|
|
anyfail();
|
|
}
|
|
if (sbrk(pagesize) == NEG1) {
|
|
ERROR("sbrk failed to grow over mmaped region");
|
|
anyfail();
|
|
}
|
|
if (sbrk(-pagesize) == NEG1) {
|
|
ERROR("sbrk failed to shrink back to mmaped region");
|
|
anyfail();
|
|
}
|
|
if (sbrk(-pagesize) == NEG1) {
|
|
ERROR("sbrk failed to shrink over mmaped region more");
|
|
anyfail();
|
|
}
|
|
if (sbrk(-pagesize) == NEG1) {
|
|
ERROR("sbrk failed to shrink some more");
|
|
anyfail();
|
|
}
|
|
if (sbrk(2 * pagesize) == NEG1) {
|
|
ERROR("sbrk failed to change brk segment to original size");
|
|
anyfail();
|
|
}
|
|
}
|
|
|
|
void ok_exit(void)
|
|
{
|
|
tst_resm(TPASS, "Test passed");
|
|
tst_exit();
|
|
}
|
|
|
|
int anyfail(void)
|
|
{
|
|
tst_brkm(TFAIL, NULL, "Test failed");
|
|
}
|