1 /*
2 * Copyright (C) 2012 Linux Test Project, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public
6 * License as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it
13 * is free of the rightful claim of any third person regarding
14 * infringement or the like. Any license provided herein, whether
15 * implied or otherwise, applies only to this software file. Patent
16 * licenses, if any, provided herein do not apply to combinations of
17 * this program with other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
23 */
24 /*
25 * Test Name: mremap05
26 *
27 * Test Description:
28 * Verify that MREMAP_FIXED fails without MREMAP_MAYMOVE.
29 * Verify that MREMAP_FIXED|MREMAP_MAYMOVE fails if target address
30 * is not page aligned.
31 * Verify that MREMAP_FIXED|MREMAP_MAYMOVE fails if old range
32 * overlaps with new range.
33 * Verify that MREMAP_FIXED|MREMAP_MAYMOVE can move mapping to new address.
34 * Verify that MREMAP_FIXED|MREMAP_MAYMOVE unmaps previous mapping
35 * at the address range specified by new_address and new_size.
36 */
37
38 #define _GNU_SOURCE
39 #include "config.h"
40 #include <sys/mman.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include "test.h"
44 #include "safe_macros.h"
45
46 char *TCID = "mremap05";
47
48 #ifdef HAVE_MREMAP_FIXED
49
50 struct test_case_t {
51 char *old_address;
52 char *new_address;
53 size_t old_size; /* in pages */
54 size_t new_size; /* in pages */
55 int flags;
56 const char *msg;
57 void *exp_ret;
58 int exp_errno;
59 char *ret;
60 void (*setup) (struct test_case_t *);
61 void (*cleanup) (struct test_case_t *);
62 };
63
64 static void setup(void);
65 static void cleanup(void);
66 static void setup0(struct test_case_t *);
67 static void setup1(struct test_case_t *);
68 static void setup2(struct test_case_t *);
69 static void setup3(struct test_case_t *);
70 static void setup4(struct test_case_t *);
71 static void cleanup0(struct test_case_t *);
72 static void cleanup1(struct test_case_t *);
73
74 struct test_case_t tdat[] = {
75 {
76 .old_size = 1,
77 .new_size = 1,
78 .flags = MREMAP_FIXED,
79 .msg = "MREMAP_FIXED requires MREMAP_MAYMOVE",
80 .exp_ret = MAP_FAILED,
81 .exp_errno = EINVAL,
82 .setup = setup0,
83 .cleanup = cleanup0},
84 {
85 .old_size = 1,
86 .new_size = 1,
87 .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
88 .msg = "new_addr has to be page aligned",
89 .exp_ret = MAP_FAILED,
90 .exp_errno = EINVAL,
91 .setup = setup1,
92 .cleanup = cleanup0},
93 {
94 .old_size = 2,
95 .new_size = 1,
96 .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
97 .msg = "old/new area must not overlap",
98 .exp_ret = MAP_FAILED,
99 .exp_errno = EINVAL,
100 .setup = setup2,
101 .cleanup = cleanup0},
102 {
103 .old_size = 1,
104 .new_size = 1,
105 .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
106 .msg = "mremap #1",
107 .setup = setup3,
108 .cleanup = cleanup0},
109 {
110 .old_size = 1,
111 .new_size = 1,
112 .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
113 .msg = "mremap #2",
114 .setup = setup4,
115 .cleanup = cleanup1},
116 };
117
118 static int pagesize;
119 static int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
120
free_test_area(void * p,int size)121 static void free_test_area(void *p, int size)
122 {
123 SAFE_MUNMAP(cleanup, p, size);
124 }
125
get_test_area(int size,int free_area)126 static void *get_test_area(int size, int free_area)
127 {
128 void *p;
129 p = mmap(NULL, size, PROT_READ | PROT_WRITE,
130 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
131 if (p == MAP_FAILED)
132 tst_brkm(TBROK | TERRNO, cleanup, "get_test_area mmap");
133 if (free_area)
134 free_test_area(p, size);
135 return p;
136 }
137
test_mremap(struct test_case_t * t)138 static void test_mremap(struct test_case_t *t)
139 {
140 t->ret = mremap(t->old_address, t->old_size, t->new_size, t->flags,
141 t->new_address);
142
143 if (t->ret == t->exp_ret) {
144 if (t->ret != MAP_FAILED) {
145 tst_resm(TPASS, "%s", t->msg);
146 if (*(t->ret) == 0x1)
147 tst_resm(TPASS, "%s value OK", t->msg);
148 else
149 tst_resm(TPASS, "%s value failed", t->msg);
150 } else {
151 if (errno == t->exp_errno)
152 tst_resm(TPASS, "%s", t->msg);
153 else
154 tst_resm(TFAIL | TERRNO, "%s", t->msg);
155 }
156 } else {
157 tst_resm(TFAIL, "%s ret: %p, expected: %p", t->msg,
158 t->ret, t->exp_ret);
159 }
160 }
161
setup0(struct test_case_t * t)162 static void setup0(struct test_case_t *t)
163 {
164 t->old_address = get_test_area(t->old_size * pagesize, 0);
165 t->new_address = get_test_area(t->new_size * pagesize, 1);
166 }
167
setup1(struct test_case_t * t)168 static void setup1(struct test_case_t *t)
169 {
170 t->old_address = get_test_area(t->old_size * pagesize, 0);
171 t->new_address = get_test_area((t->new_size + 1) * pagesize, 1) + 1;
172 }
173
setup2(struct test_case_t * t)174 static void setup2(struct test_case_t *t)
175 {
176 t->old_address = get_test_area(t->old_size * pagesize, 0);
177 t->new_address = t->old_address;
178 }
179
setup3(struct test_case_t * t)180 static void setup3(struct test_case_t *t)
181 {
182 t->old_address = get_test_area(t->old_size * pagesize, 0);
183 t->new_address = get_test_area(t->new_size * pagesize, 1);
184 t->exp_ret = t->new_address;
185 *(t->old_address) = 0x1;
186 }
187
setup4(struct test_case_t * t)188 static void setup4(struct test_case_t *t)
189 {
190 t->old_address = get_test_area(t->old_size * pagesize, 0);
191 t->new_address = get_test_area(t->new_size * pagesize, 0);
192 t->exp_ret = t->new_address;
193 *(t->old_address) = 0x1;
194 *(t->new_address) = 0x2;
195 }
196
cleanup0(struct test_case_t * t)197 static void cleanup0(struct test_case_t *t)
198 {
199 if (t->ret == MAP_FAILED)
200 free_test_area(t->old_address, t->old_size * pagesize);
201 else
202 free_test_area(t->ret, t->new_size * pagesize);
203 }
204
cleanup1(struct test_case_t * t)205 static void cleanup1(struct test_case_t *t)
206 {
207 if (t->ret == MAP_FAILED) {
208 free_test_area(t->old_address, t->old_size * pagesize);
209 free_test_area(t->new_address, t->new_size * pagesize);
210 } else {
211 free_test_area(t->ret, t->new_size * pagesize);
212 }
213 }
214
main(int ac,char ** av)215 int main(int ac, char **av)
216 {
217 int lc, testno;
218
219 tst_parse_opts(ac, av, NULL, NULL);
220
221 setup();
222 for (lc = 0; TEST_LOOPING(lc); lc++) {
223 tst_count = 0;
224 for (testno = 0; testno < TST_TOTAL; testno++) {
225 tdat[testno].setup(&tdat[testno]);
226 test_mremap(&tdat[testno]);
227 tdat[testno].cleanup(&tdat[testno]);
228 }
229 }
230 cleanup();
231 tst_exit();
232 }
233
setup(void)234 static void setup(void)
235 {
236 pagesize = getpagesize();
237 }
238
cleanup(void)239 static void cleanup(void)
240 {
241 }
242
243 #else
244
main(void)245 int main(void)
246 {
247 tst_brkm(TCONF, NULL, "MREMAP_FIXED not present in <sys/mman.h>");
248 }
249
250 #endif /* HAVE_MREMAP_FIXED */
251