1 /* 2 * Copyright (c) 2013 FNST, DAN LI <li.dan@cn.fujitsu.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 12 * the GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 /* 20 * Test Description: 21 * Verify MAP_POPULATE works fine. 22 * "For a file mapping, this causes read-ahead on the file. 23 * Later accesses to the mapping will not be blocked by page faults" 24 * 25 * Expected Result: 26 * mmap() with MAP_POPULATE should succeed returning the address of the 27 * mapped region and this file has been read into RAM, so pages should 28 * be present. 29 */ 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <sys/types.h> 33 #include <errno.h> 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include <string.h> 37 #include <signal.h> 38 #include <stdint.h> 39 #include <sys/stat.h> 40 #include <sys/mman.h> 41 #include <sys/shm.h> 42 43 #include "tst_test.h" 44 45 #define TEMPFILE "mmapfile" 46 #define PATHLEN 256 47 #define MMAPSIZE (1UL<<20) 48 49 static int fildes; 50 static char *addr; 51 52 static void page_check(void) 53 { 54 int i = 1; 55 int flag = 0; 56 int pm; 57 int num_pages; 58 long index; 59 off_t offset; 60 size_t page_sz; 61 uint64_t pagemap; 62 unsigned long vmstart; 63 64 vmstart = (unsigned long)addr; 65 page_sz = getpagesize(); 66 67 num_pages = MMAPSIZE / page_sz; 68 index = (vmstart / page_sz) * sizeof(uint64_t); 69 70 pm = open("/proc/self/pagemap", O_RDONLY); 71 if (pm == -1) { 72 if ((errno == EPERM) && (geteuid() != 0)) { 73 tst_res(TCONF | TERRNO, 74 "don't have permission to open dev pagemap"); 75 return; 76 } else { 77 tst_brk(TFAIL | TERRNO, "pen dev pagemap failed"); 78 } 79 } 80 81 offset = SAFE_LSEEK(pm, index, SEEK_SET); 82 if (offset != index) 83 tst_brk(TFAIL | TERRNO, "Reposition offset failed"); 84 85 while (i <= num_pages) { 86 SAFE_READ(1, pm, &pagemap, sizeof(uint64_t)); 87 88 /* 89 * Check if the page is present. 90 */ 91 if (!(pagemap & (1ULL<<63))) { 92 tst_res(TINFO, "The %dth page addressed at %lX is not " 93 "present", i, vmstart + i * page_sz); 94 flag = 1; 95 } 96 97 i++; 98 } 99 100 close(pm); 101 102 if (!flag) 103 tst_res(TINFO, "All pages are present"); 104 } 105 106 void verify_mmap(void) 107 { 108 unsigned int i; 109 110 addr = mmap(NULL, MMAPSIZE, PROT_READ | PROT_WRITE, 111 MAP_PRIVATE | MAP_POPULATE, fildes, 0); 112 113 if (addr == MAP_FAILED) { 114 tst_res(TFAIL | TERRNO, "mmap of %s failed", TEMPFILE); 115 return; 116 } 117 118 page_check(); 119 120 for (i = 0; i < MMAPSIZE; i++) { 121 if (addr[i]) { 122 tst_res(TFAIL, "Non-zero byte at offset %i", i); 123 goto unmap; 124 } 125 } 126 127 tst_res(TPASS, "File mapped properly"); 128 129 unmap: 130 SAFE_MUNMAP(addr, MMAPSIZE); 131 } 132 133 static void setup(void) 134 { 135 fildes = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0766); 136 137 SAFE_FTRUNCATE(fildes, MMAPSIZE); 138 } 139 140 static void cleanup(void) 141 { 142 if (fildes > 0) 143 SAFE_CLOSE(fildes); 144 } 145 146 static struct tst_test test = { 147 .setup = setup, 148 .cleanup = cleanup, 149 .test_all = verify_mmap, 150 .needs_tmpdir = 1, 151 .min_kver = "2.6.25", 152 }; 153