liyujie
2025-08-28 b3810562527858a3b3d98ffa6e9c9c5b0f4a9a8e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/* 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");
}