// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2013 FNST, DAN LI
*/
/*
* Test Description:
* Verify MAP_POPULATE works fine.
* "For a file mapping, this causes read-ahead on the file.
* Later accesses to the mapping will not be blocked by page faults"
*
* Expected Result:
* mmap() with MAP_POPULATE should succeed returning the address of the
* mapped region and this file has been read into RAM, so pages should
* be present.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "tst_test.h"
#define TEMPFILE "mmapfile"
#define PATHLEN 256
#define MMAPSIZE (1UL<<20)
static int fildes;
static char *addr;
static void page_check(void)
{
int i = 1;
int flag = 0;
int pm;
int num_pages;
long index;
off_t offset;
size_t page_sz;
uint64_t pagemap;
unsigned long vmstart;
vmstart = (unsigned long)addr;
page_sz = getpagesize();
num_pages = MMAPSIZE / page_sz;
index = (vmstart / page_sz) * sizeof(uint64_t);
pm = open("/proc/self/pagemap", O_RDONLY);
if (pm == -1) {
if ((errno == EPERM) && (geteuid() != 0)) {
tst_res(TCONF | TERRNO,
"don't have permission to open dev pagemap");
return;
} else {
tst_brk(TFAIL | TERRNO, "pen dev pagemap failed");
}
}
offset = SAFE_LSEEK(pm, index, SEEK_SET);
if (offset != index)
tst_brk(TFAIL | TERRNO, "Reposition offset failed");
while (i <= num_pages) {
SAFE_READ(1, pm, &pagemap, sizeof(uint64_t));
/*
* Check if the page is present.
*/
if (!(pagemap & (1ULL<<63))) {
tst_res(TINFO, "The %dth page addressed at %lX is not "
"present", i, vmstart + i * page_sz);
flag = 1;
}
i++;
}
close(pm);
if (!flag)
tst_res(TINFO, "All pages are present");
}
void verify_mmap(void)
{
unsigned int i;
addr = mmap(NULL, MMAPSIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_POPULATE, fildes, 0);
if (addr == MAP_FAILED) {
tst_res(TFAIL | TERRNO, "mmap of %s failed", TEMPFILE);
return;
}
page_check();
for (i = 0; i < MMAPSIZE; i++) {
if (addr[i]) {
tst_res(TFAIL, "Non-zero byte at offset %i", i);
goto unmap;
}
}
tst_res(TPASS, "File mapped properly");
unmap:
SAFE_MUNMAP(addr, MMAPSIZE);
}
static void setup(void)
{
fildes = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0766);
SAFE_FTRUNCATE(fildes, MMAPSIZE);
}
static void cleanup(void)
{
if (fildes > 0)
SAFE_CLOSE(fildes);
}
static struct tst_test test = {
.setup = setup,
.cleanup = cleanup,
.test_all = verify_mmap,
.needs_tmpdir = 1,
.min_kver = "2.6.25",
};