blob: 7fad17ab3cddd22baf46adadbf79a793ef56dd24 [file] [log] [blame]
/*
* Copyright (C) Ingo Molnar, 2002
* Copyright (C) Ricardo Salveti de Araujo, 2007
* Copyright (C) International Business Machines Corp., 2007
*
* 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.
*/
/*
* NAME
* remap_file_pages01
*
* 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 agains a mmaped area and check the results
*
* Setup:
* Create a temp directory, open a file and get the file descriptor
*
* Test:
* Test with a normal file and with /dev/shm/cache_<pid>
* 1. Set up the cache
* 2. Write the cache to the file
* 3. Runs mmap at the same file
* 4. Runs remap_file_pages at the mapped memory
* 5. Check the results
* $
* Cleanup:
* Remove the file and erase the tmp directory
*
* Usage: <for command-line>
* remap_file_pages01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
* where, -c n : Run n copies concurrently.
* -f : Turn off functionality Testing.
* -i n : Execute test n times.
* -I x : Execute test for x seconds.
* -P x : Pause for x seconds between iterations.
* -t : Turn on syscall timing.
*
* HISTORY
* - Ingo Molnar, <mingo@elte.hu> wrote this test case
* - Nick Piggin, <nickpiggin@yahoo.com.au> did the following cleanup
*
* 11/10/2007 - Port to LTP format by Subrata Modak, <subrata@linux.vnet.ibm.com>
* and Ricardo Salveti de Araujo, <rsalveti@linux.vnet.ibm.com>
* 25/02/2008 - Renaud Lottiaux, <Renaud.Lottiaux@kerlabs.com>
* Fix NFS remove tmpdir issue due to non unmapped files.
* Fix concurrency issue on the file /dev/shm/cache.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/times.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <linux/unistd.h>
#include "test.h" /*LTP Specific Include File */
/* Test case defines */
#define WINDOW_START 0x48000000
static int page_sz;
size_t page_words;
size_t cache_pages;
size_t cache_sz;
size_t window_pages;
size_t window_sz;
static void setup();
static void cleanup();
static void test_nonlinear(int fd);
char *TCID = "remap_file_pages01";
int TST_TOTAL = 2;
static char *cache_contents;
int fd1, fd2; /* File descriptors used at the test */
char fname[255];
int main(int ac, char **av)
{
int lc;
const char *msg;
#if defined (__s390__) || (__s390x__) || (__ia64__)
/* Disables the test in case the kernel version is lower than 2.6.12 and arch is s390 */
if ((tst_kvercmp(2, 6, 12)) < 0) {
tst_resm(TWARN,
"This test can only run on kernels that are 2.6.12 and higher");
exit(0);
}
#endif
if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) {
tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
}
setup();
for (lc = 0; TEST_LOOPING(lc); lc++) {
tst_count = 0;
test_nonlinear(fd1);
tst_resm(TPASS, "Non-Linear shm file OK");
test_nonlinear(fd2);
tst_resm(TPASS, "Non-Linear /tmp/ file OK");
}
/* clean up and exit */
cleanup();
tst_exit();
}
/* test case function, that runs remap_file_pages */
static void test_nonlinear(int fd)
{
char *data = NULL;
int i, j, repeat = 2;
for (i = 0; i < cache_pages; i++) {
char *page = cache_contents + i * page_sz;
for (j = 0; j < page_words; j++)
page[j] = i;
}
if (write(fd, cache_contents, cache_sz) != cache_sz) {
tst_resm(TFAIL,
"Write Error for \"cache_contents\" to \"cache_sz\" of %zu (errno=%d : %s)",
cache_sz, errno, strerror(errno));
cleanup(NULL);
}
data = mmap((void *)WINDOW_START,
window_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
tst_resm(TFAIL, "mmap Error, errno=%d : %s", errno,
strerror(errno));
cleanup(NULL);
}
again:
for (i = 0; i < window_pages; i += 2) {
char *page = data + i * page_sz;
if (remap_file_pages(page, page_sz * 2, 0,
(window_pages - i - 2), 0) == -1) {
tst_resm(TFAIL | TERRNO,
"remap_file_pages error for page=%p, "
"page_sz=%d, window_pages=%zu",
page, (page_sz * 2), (window_pages - i - 2));
cleanup(data);
}
}
for (i = 0; i < window_pages; i++) {
/*
* Double-check the correctness of the mapping:
*/
if (i & 1) {
if (data[i * page_sz] != window_pages - i) {
tst_resm(TFAIL,
"hm, mapped incorrect data, "
"data[%d]=%d, (window_pages-%d)=%zu",
(i * page_sz), data[i * page_sz], i,
(window_pages - i));
cleanup(data);
}
} else {
if (data[i * page_sz] != window_pages - i - 2) {
tst_resm(TFAIL,
"hm, mapped incorrect data, "
"data[%d]=%d, (window_pages-%d-2)=%zu",
(i * page_sz), data[i * page_sz], i,
(window_pages - i - 2));
cleanup(data);
}
}
}
if (--repeat)
goto again;
munmap(data, window_sz);
}
/* setup() - performs all ONE TIME setup for this test */
void setup(void)
{
tst_sig(FORK, DEF_HANDLER, cleanup);
tst_tmpdir();
TEST_PAUSE;
/* Get page size */
page_sz = getpagesize();
page_words = page_sz;
/* Set the cache size */
cache_pages = 1024;
cache_sz = cache_pages * page_sz;
cache_contents = malloc(cache_sz * sizeof(char));
/* Set the window size */
window_pages = 16;
window_sz = window_pages * page_sz;
sprintf(fname, "/dev/shm/cache_%d", getpid());
if ((fd1 = open(fname, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
tst_brkm(TBROK, cleanup,
"open(%s, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU) Failed, errno=%d : %s",
fname, errno, strerror(errno));
}
if ((fd2 = open("cache", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
tst_brkm(TBROK, cleanup,
"open(%s, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU) Failed, errno=%d : %s",
"cache", errno, strerror(errno));
}
}
/*
* cleanup() - Performs one time cleanup for this test at
* completion or premature exit
*/
void cleanup(char *data)
{
/* Close the file descriptors */
close(fd1);
close(fd2);
if (data)
munmap(data, window_sz);
/* Remove the /dev/shm/cache_<pid> file */
unlink(fname);
tst_rmdir();
}