// 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", };