| /* |
| * Copyright (C) 2012 Linux Test Project, Inc. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of version 2 of the GNU General Public |
| * License as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it would be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| * |
| * Further, this software is distributed without any warranty that it |
| * is free of the rightful claim of any third person regarding |
| * infringement or the like. Any license provided herein, whether |
| * implied or otherwise, applies only to this software file. Patent |
| * licenses, if any, provided herein do not apply to combinations of |
| * this program with other software, or any other product whatsoever. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| * 02110-1301, USA. |
| */ |
| /* |
| * Test Name: mremap05 |
| * |
| * Test Description: |
| * Verify that MREMAP_FIXED fails without MREMAP_MAYMOVE. |
| * Verify that MREMAP_FIXED|MREMAP_MAYMOVE fails if target address |
| * is not page aligned. |
| * Verify that MREMAP_FIXED|MREMAP_MAYMOVE fails if old range |
| * overlaps with new range. |
| * Verify that MREMAP_FIXED|MREMAP_MAYMOVE can move mapping to new address. |
| * Verify that MREMAP_FIXED|MREMAP_MAYMOVE unmaps previous mapping |
| * at the address range specified by new_address and new_size. |
| */ |
| |
| #define _GNU_SOURCE |
| #include "config.h" |
| #include <sys/mman.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include "test.h" |
| #include "safe_macros.h" |
| |
| char *TCID = "mremap05"; |
| |
| #ifdef HAVE_MREMAP_FIXED |
| |
| struct test_case_t { |
| char *old_address; |
| char *new_address; |
| size_t old_size; /* in pages */ |
| size_t new_size; /* in pages */ |
| int flags; |
| const const char *msg; |
| void *exp_ret; |
| int exp_errno; |
| char *ret; |
| void (*setup) (struct test_case_t *); |
| void (*cleanup) (struct test_case_t *); |
| }; |
| |
| static void setup(void); |
| static void cleanup(void); |
| static void setup0(struct test_case_t *); |
| static void setup1(struct test_case_t *); |
| static void setup2(struct test_case_t *); |
| static void setup3(struct test_case_t *); |
| static void setup4(struct test_case_t *); |
| static void cleanup0(struct test_case_t *); |
| static void cleanup1(struct test_case_t *); |
| |
| struct test_case_t tdat[] = { |
| { |
| .old_size = 1, |
| .new_size = 1, |
| .flags = MREMAP_FIXED, |
| .msg = "MREMAP_FIXED requires MREMAP_MAYMOVE", |
| .exp_ret = MAP_FAILED, |
| .exp_errno = EINVAL, |
| .setup = setup0, |
| .cleanup = cleanup0}, |
| { |
| .old_size = 1, |
| .new_size = 1, |
| .flags = MREMAP_FIXED | MREMAP_MAYMOVE, |
| .msg = "new_addr has to be page aligned", |
| .exp_ret = MAP_FAILED, |
| .exp_errno = EINVAL, |
| .setup = setup1, |
| .cleanup = cleanup0}, |
| { |
| .old_size = 2, |
| .new_size = 1, |
| .flags = MREMAP_FIXED | MREMAP_MAYMOVE, |
| .msg = "old/new area must not overlap", |
| .exp_ret = MAP_FAILED, |
| .exp_errno = EINVAL, |
| .setup = setup2, |
| .cleanup = cleanup0}, |
| { |
| .old_size = 1, |
| .new_size = 1, |
| .flags = MREMAP_FIXED | MREMAP_MAYMOVE, |
| .msg = "mremap #1", |
| .setup = setup3, |
| .cleanup = cleanup0}, |
| { |
| .old_size = 1, |
| .new_size = 1, |
| .flags = MREMAP_FIXED | MREMAP_MAYMOVE, |
| .msg = "mremap #2", |
| .setup = setup4, |
| .cleanup = cleanup1}, |
| }; |
| |
| static int pagesize; |
| static int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]); |
| |
| static void free_test_area(void *p, int size) |
| { |
| SAFE_MUNMAP(cleanup, p, size); |
| } |
| |
| static void *get_test_area(int size, int free_area) |
| { |
| void *p; |
| p = mmap(NULL, size, PROT_READ | PROT_WRITE, |
| MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); |
| if (p == MAP_FAILED) |
| tst_brkm(TBROK | TERRNO, cleanup, "get_test_area mmap"); |
| if (free_area) |
| free_test_area(p, size); |
| return p; |
| } |
| |
| static void test_mremap(struct test_case_t *t) |
| { |
| t->ret = mremap(t->old_address, t->old_size, t->new_size, t->flags, |
| t->new_address); |
| |
| if (t->ret == t->exp_ret) { |
| if (t->ret != MAP_FAILED) { |
| tst_resm(TPASS, "%s", t->msg); |
| if (*(t->ret) == 0x1) |
| tst_resm(TPASS, "%s value OK", t->msg); |
| else |
| tst_resm(TPASS, "%s value failed", t->msg); |
| } else { |
| if (errno == t->exp_errno) |
| tst_resm(TPASS, "%s", t->msg); |
| else |
| tst_resm(TFAIL | TERRNO, "%s", t->msg); |
| } |
| } else { |
| tst_resm(TFAIL, "%s ret: %p, expected: %p", t->msg, |
| t->ret, t->exp_ret); |
| } |
| } |
| |
| static void setup0(struct test_case_t *t) |
| { |
| t->old_address = get_test_area(t->old_size * pagesize, 0); |
| t->new_address = get_test_area(t->new_size * pagesize, 1); |
| } |
| |
| static void setup1(struct test_case_t *t) |
| { |
| t->old_address = get_test_area(t->old_size * pagesize, 0); |
| t->new_address = get_test_area((t->new_size + 1) * pagesize, 1) + 1; |
| } |
| |
| static void setup2(struct test_case_t *t) |
| { |
| t->old_address = get_test_area(t->old_size * pagesize, 0); |
| t->new_address = t->old_address; |
| } |
| |
| static void setup3(struct test_case_t *t) |
| { |
| t->old_address = get_test_area(t->old_size * pagesize, 0); |
| t->new_address = get_test_area(t->new_size * pagesize, 1); |
| t->exp_ret = t->new_address; |
| *(t->old_address) = 0x1; |
| } |
| |
| static void setup4(struct test_case_t *t) |
| { |
| t->old_address = get_test_area(t->old_size * pagesize, 0); |
| t->new_address = get_test_area(t->new_size * pagesize, 0); |
| t->exp_ret = t->new_address; |
| *(t->old_address) = 0x1; |
| *(t->new_address) = 0x2; |
| } |
| |
| static void cleanup0(struct test_case_t *t) |
| { |
| if (t->ret == MAP_FAILED) |
| free_test_area(t->old_address, t->old_size * pagesize); |
| else |
| free_test_area(t->ret, t->new_size * pagesize); |
| } |
| |
| static void cleanup1(struct test_case_t *t) |
| { |
| if (t->ret == MAP_FAILED) { |
| free_test_area(t->old_address, t->old_size * pagesize); |
| free_test_area(t->new_address, t->new_size * pagesize); |
| } else { |
| free_test_area(t->ret, t->new_size * pagesize); |
| } |
| } |
| |
| int main(int ac, char **av) |
| { |
| int lc, testno; |
| |
| tst_parse_opts(ac, av, NULL, NULL); |
| |
| setup(); |
| for (lc = 0; TEST_LOOPING(lc); lc++) { |
| tst_count = 0; |
| for (testno = 0; testno < TST_TOTAL; testno++) { |
| tdat[testno].setup(&tdat[testno]); |
| test_mremap(&tdat[testno]); |
| tdat[testno].cleanup(&tdat[testno]); |
| } |
| } |
| cleanup(); |
| tst_exit(); |
| } |
| |
| static void setup(void) |
| { |
| pagesize = getpagesize(); |
| } |
| |
| static void cleanup(void) |
| { |
| } |
| |
| #else |
| |
| int main(void) |
| { |
| tst_brkm(TCONF, NULL, "MREMAP_FIXED not present in <sys/mman.h>"); |
| } |
| |
| #endif /* HAVE_MREMAP_FIXED */ |