Home | History | Annotate | Download | only in mremap
      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 
    121 static void free_test_area(void *p, int size)
    122 {
    123 	SAFE_MUNMAP(cleanup, p, size);
    124 }
    125 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    234 static void setup(void)
    235 {
    236 	pagesize = getpagesize();
    237 }
    238 
    239 static void cleanup(void)
    240 {
    241 }
    242 
    243 #else
    244 
    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