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
page_check(void)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
verify_mmap(void)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
setup(void)133 static void setup(void)
134 {
135 fildes = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0766);
136
137 SAFE_FTRUNCATE(fildes, MMAPSIZE);
138 }
139
cleanup(void)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