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 46char *TCID = "mremap05"; 47 48struct test_case_t { 49 char *old_address; 50 char *new_address; 51 size_t old_size; /* in pages */ 52 size_t new_size; /* in pages */ 53 int flags; 54 const char *msg; 55 void *exp_ret; 56 int exp_errno; 57 char *ret; 58 void (*setup) (struct test_case_t *); 59 void (*cleanup) (struct test_case_t *); 60}; 61 62static void setup(void); 63static void cleanup(void); 64static void setup0(struct test_case_t *); 65static void setup1(struct test_case_t *); 66static void setup2(struct test_case_t *); 67static void setup3(struct test_case_t *); 68static void setup4(struct test_case_t *); 69static void cleanup0(struct test_case_t *); 70static void cleanup1(struct test_case_t *); 71 72struct test_case_t tdat[] = { 73 { 74 .old_size = 1, 75 .new_size = 1, 76 .flags = MREMAP_FIXED, 77 .msg = "MREMAP_FIXED requires MREMAP_MAYMOVE", 78 .exp_ret = MAP_FAILED, 79 .exp_errno = EINVAL, 80 .setup = setup0, 81 .cleanup = cleanup0}, 82 { 83 .old_size = 1, 84 .new_size = 1, 85 .flags = MREMAP_FIXED | MREMAP_MAYMOVE, 86 .msg = "new_addr has to be page aligned", 87 .exp_ret = MAP_FAILED, 88 .exp_errno = EINVAL, 89 .setup = setup1, 90 .cleanup = cleanup0}, 91 { 92 .old_size = 2, 93 .new_size = 1, 94 .flags = MREMAP_FIXED | MREMAP_MAYMOVE, 95 .msg = "old/new area must not overlap", 96 .exp_ret = MAP_FAILED, 97 .exp_errno = EINVAL, 98 .setup = setup2, 99 .cleanup = cleanup0}, 100 { 101 .old_size = 1, 102 .new_size = 1, 103 .flags = MREMAP_FIXED | MREMAP_MAYMOVE, 104 .msg = "mremap #1", 105 .setup = setup3, 106 .cleanup = cleanup0}, 107 { 108 .old_size = 1, 109 .new_size = 1, 110 .flags = MREMAP_FIXED | MREMAP_MAYMOVE, 111 .msg = "mremap #2", 112 .setup = setup4, 113 .cleanup = cleanup1}, 114}; 115 116static int pagesize; 117static int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]); 118 119static void free_test_area(void *p, int size) 120{ 121 SAFE_MUNMAP(cleanup, p, size); 122} 123 124static void *get_test_area(int size, int free_area) 125{ 126 void *p; 127 p = mmap(NULL, size, PROT_READ | PROT_WRITE, 128 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 129 if (p == MAP_FAILED) 130 tst_brkm(TBROK | TERRNO, cleanup, "get_test_area mmap"); 131 if (free_area) 132 free_test_area(p, size); 133 return p; 134} 135 136static void test_mremap(struct test_case_t *t) 137{ 138 t->ret = mremap(t->old_address, t->old_size, t->new_size, t->flags, 139 t->new_address); 140 141 if (t->ret == t->exp_ret) { 142 if (t->ret != MAP_FAILED) { 143 tst_resm(TPASS, "%s", t->msg); 144 if (*(t->ret) == 0x1) 145 tst_resm(TPASS, "%s value OK", t->msg); 146 else 147 tst_resm(TPASS, "%s value failed", t->msg); 148 } else { 149 if (errno == t->exp_errno) 150 tst_resm(TPASS, "%s", t->msg); 151 else 152 tst_resm(TFAIL | TERRNO, "%s", t->msg); 153 } 154 } else { 155 tst_resm(TFAIL, "%s ret: %p, expected: %p", t->msg, 156 t->ret, t->exp_ret); 157 } 158} 159 160static void setup0(struct test_case_t *t) 161{ 162 t->old_address = get_test_area(t->old_size * pagesize, 0); 163 t->new_address = get_test_area(t->new_size * pagesize, 1); 164} 165 166static void setup1(struct test_case_t *t) 167{ 168 t->old_address = get_test_area(t->old_size * pagesize, 0); 169 t->new_address = get_test_area((t->new_size + 1) * pagesize, 1) + 1; 170} 171 172static void setup2(struct test_case_t *t) 173{ 174 t->old_address = get_test_area(t->old_size * pagesize, 0); 175 t->new_address = t->old_address; 176} 177 178static void setup3(struct test_case_t *t) 179{ 180 t->old_address = get_test_area(t->old_size * pagesize, 0); 181 t->new_address = get_test_area(t->new_size * pagesize, 1); 182 t->exp_ret = t->new_address; 183 *(t->old_address) = 0x1; 184} 185 186static void setup4(struct test_case_t *t) 187{ 188 t->old_address = get_test_area(t->old_size * pagesize, 0); 189 t->new_address = get_test_area(t->new_size * pagesize, 0); 190 t->exp_ret = t->new_address; 191 *(t->old_address) = 0x1; 192 *(t->new_address) = 0x2; 193} 194 195static void cleanup0(struct test_case_t *t) 196{ 197 if (t->ret == MAP_FAILED) 198 free_test_area(t->old_address, t->old_size * pagesize); 199 else 200 free_test_area(t->ret, t->new_size * pagesize); 201} 202 203static void cleanup1(struct test_case_t *t) 204{ 205 if (t->ret == MAP_FAILED) { 206 free_test_area(t->old_address, t->old_size * pagesize); 207 free_test_area(t->new_address, t->new_size * pagesize); 208 } else { 209 free_test_area(t->ret, t->new_size * pagesize); 210 } 211} 212 213int main(int ac, char **av) 214{ 215 int lc, testno; 216 217 tst_parse_opts(ac, av, NULL, NULL); 218 219 setup(); 220 for (lc = 0; TEST_LOOPING(lc); lc++) { 221 tst_count = 0; 222 for (testno = 0; testno < TST_TOTAL; testno++) { 223 tdat[testno].setup(&tdat[testno]); 224 test_mremap(&tdat[testno]); 225 tdat[testno].cleanup(&tdat[testno]); 226 } 227 } 228 cleanup(); 229 tst_exit(); 230} 231 232static void setup(void) 233{ 234 pagesize = getpagesize(); 235} 236 237static void cleanup(void) 238{ 239} 240