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 45char *TCID = "mremap05"; 46 47#ifdef HAVE_MREMAP_FIXED 48 49struct test_case_t { 50 char *old_address; 51 char *new_address; 52 size_t old_size; /* in pages */ 53 size_t new_size; /* in pages */ 54 int flags; 55 const const char *msg; 56 void *exp_ret; 57 int exp_errno; 58 char *ret; 59 void (*setup) (struct test_case_t *); 60 void (*cleanup) (struct test_case_t *); 61}; 62 63static void setup(void); 64static void cleanup(void); 65static void setup0(struct test_case_t *); 66static void setup1(struct test_case_t *); 67static void setup2(struct test_case_t *); 68static void setup3(struct test_case_t *); 69static void setup4(struct test_case_t *); 70static void cleanup0(struct test_case_t *); 71static void cleanup1(struct test_case_t *); 72 73struct test_case_t tdat[] = { 74 { 75 .old_size = 1, 76 .new_size = 1, 77 .flags = MREMAP_FIXED, 78 .msg = "MREMAP_FIXED requires MREMAP_MAYMOVE", 79 .exp_ret = MAP_FAILED, 80 .exp_errno = EINVAL, 81 .setup = setup0, 82 .cleanup = cleanup0}, 83 { 84 .old_size = 1, 85 .new_size = 1, 86 .flags = MREMAP_FIXED | MREMAP_MAYMOVE, 87 .msg = "new_addr has to be page aligned", 88 .exp_ret = MAP_FAILED, 89 .exp_errno = EINVAL, 90 .setup = setup1, 91 .cleanup = cleanup0}, 92 { 93 .old_size = 2, 94 .new_size = 1, 95 .flags = MREMAP_FIXED | MREMAP_MAYMOVE, 96 .msg = "old/new area must not overlap", 97 .exp_ret = MAP_FAILED, 98 .exp_errno = EINVAL, 99 .setup = setup2, 100 .cleanup = cleanup0}, 101 { 102 .old_size = 1, 103 .new_size = 1, 104 .flags = MREMAP_FIXED | MREMAP_MAYMOVE, 105 .msg = "mremap #1", 106 .setup = setup3, 107 .cleanup = cleanup0}, 108 { 109 .old_size = 1, 110 .new_size = 1, 111 .flags = MREMAP_FIXED | MREMAP_MAYMOVE, 112 .msg = "mremap #2", 113 .setup = setup4, 114 .cleanup = cleanup1}, 115}; 116 117static int pagesize; 118static int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]); 119 120static void free_test_area(void *p, int size) 121{ 122 if (munmap(p, size) < 0) 123 tst_brkm(TBROK | TERRNO, cleanup, "free_test_area munmap"); 124} 125 126static 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 138static 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 162static 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 168static 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 174static 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 180static 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 188static 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 197static 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 205static 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 215int 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 234static void setup(void) 235{ 236 pagesize = getpagesize(); 237} 238 239static void cleanup(void) 240{ 241} 242 243#else 244 245int main(void) 246{ 247 tst_brkm(TCONF, NULL, "MREMAP_FIXED not present in <sys/mman.h>"); 248} 249 250#endif /* HAVE_MREMAP_FIXED */ 251