// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) Ricardo Salveti de Araujo , 2007 * * DESCRIPTION * The remap_file_pages() system call is used to create a non-linear * mapping, that is, a mapping in which the pages of the file are mapped * into a non-sequential order in memory. The advantage of using * remap_file_pages() over using repeated calls to mmap(2) is that * the former approach does not require the kernel to create * additional VMA (Virtual Memory Area) data structures. * * Runs remap_file_pages with wrong values and see if got the expected error * * Setup: * 1. Global: * 2. Create a file, do a normal mmap with MAP_SHARED flag * * Test: * 1. Test with a valid mmap but without MAP_SHARED flag * 2. Test with a invalid start argument * 3. Test with a invalid size argument * 4. Test with a invalid prot argument * * HISTORY * * 02/11/2008 - Removed the pgoff test case, as the latest kernels doesn't * verify the page offset (http://lkml.org/lkml/2007/11/29/325) - Ricardo * Salveti de Araujo, */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "tst_test.h" #include "lapi/syscalls.h" #define WINDOW_START 0x48000000 static unsigned int page_sz; static int fd; static char *data = NULL; static char *data01 = NULL; static void setup01(int test); static void setup02(int test); static void setup03(int test); static void setup04(int test); static struct tcase { char *err_desc; int exp_errno; void (*setup)(int); void *start; size_t size; int prot; ssize_t pgoff; int flags; } tcases[] = { {"start is not valid MAP_SHARED mapping", EINVAL, setup01, NULL, 0, 0, 2, 0}, {"start is invalid", EINVAL, setup02, NULL, 0, 0, 2, 0}, {"size is invalid", EINVAL, setup03, NULL, 0, 0, 0, 0}, {"prot is invalid", EINVAL, setup04, NULL, 0, 0, 2, 0} }; static void run(unsigned i) { TEST(tst_syscall(__NR_remap_file_pages, tcases[i].start, tcases[i].size, tcases[i].prot, tcases[i].pgoff, tcases[i].flags)); if ((TST_RET == -1) && (TST_ERR == tcases[i].exp_errno)) { tst_res(TPASS | TTERRNO, "remap_file_pages(2) %s", tcases[i].err_desc); return; } tst_res(TFAIL | TTERRNO, "remap_file_pages(2) %s expected %s got", tcases[i].err_desc, tst_strerrno(tcases[i].exp_errno)); } static void setup01(int test) { tcases[test].start = data01; tcases[test].size = page_sz; } static void setup02(int test) { tcases[test].start = data + page_sz; tcases[test].size = page_sz; } static void setup03(int test) { tcases[test].start = data; tcases[test].size = 2 * page_sz; } static void setup04(int test) { tcases[test].start = data; tcases[test].size = page_sz; tcases[test].prot = -1; } static void setup(void) { unsigned int i; #if defined (__s390__) || (__s390x__) || (__ia64__) if ((tst_kvercmp(2, 6, 12)) < 0) tst_brk(TCONF, "This test can only run on kernels that are 2.6.12 and higher"); #endif page_sz = getpagesize(); fd = SAFE_OPEN("cache", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU); SAFE_FTRUNCATE(fd, page_sz); data = SAFE_MMAP((void *)WINDOW_START, page_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); data01 = SAFE_MMAP(NULL, page_sz, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); for (i = 0; i < ARRAY_SIZE(tcases); i++) { if (tcases[i].setup) tcases[i].setup(i); } } static void cleanup(void) { SAFE_CLOSE(fd); if (data) SAFE_MUNMAP(data, page_sz); if (data01) SAFE_MUNMAP(data01, page_sz); } static struct tst_test test = { .tcnt = ARRAY_SIZE(tcases), .test = run, .cleanup = cleanup, .setup = setup, .needs_tmpdir = 1, };