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 "test.h"
44
45 #define TEMPFILE "mmapfile"
46 #define PATHLEN 256
47 #define MMAPSIZE (1UL<<20)
48
49 char *TCID = "mmap12";
50 int TST_TOTAL = 1;
51
52 static int fildes;
53 static char *addr;
54
55 static int page_check(void);
56 static void setup(void);
57 static void cleanup(void);
58
main(int argc,char * argv[])59 int main(int argc, char *argv[])
60 {
61 int lc;
62
63 tst_parse_opts(argc, argv, NULL, NULL);
64
65 setup();
66
67 for (lc = 0; TEST_LOOPING(lc); lc++) {
68 tst_count = 0;
69
70 addr = mmap(NULL, MMAPSIZE, PROT_READ | PROT_WRITE,
71 MAP_PRIVATE | MAP_POPULATE, fildes, 0);
72
73 if (addr == MAP_FAILED) {
74 tst_resm(TFAIL | TERRNO, "mmap of %s failed", TEMPFILE);
75 continue;
76 }
77
78 if (page_check())
79 tst_resm(TFAIL, "Not all pages are present");
80 else
81 tst_resm(TPASS, "Functionality of mmap() "
82 "successful");
83 if (munmap(addr, MMAPSIZE) != 0)
84 tst_brkm(TFAIL | TERRNO, NULL, "munmap failed");
85 }
86
87 cleanup();
88 tst_exit();
89 }
90
page_check(void)91 static int page_check(void)
92 {
93 int ret;
94 int i = 1;
95 int flag = 0;
96 int pm;
97 int num_pages;
98 long index;
99 off_t offset;
100 size_t page_sz;
101 uint64_t pagemap;
102 unsigned long vmstart;
103
104 vmstart = (unsigned long)addr;
105 page_sz = getpagesize();
106
107 num_pages = MMAPSIZE / page_sz;
108 index = (vmstart / page_sz) * sizeof(uint64_t);
109
110 pm = open("/proc/self/pagemap", O_RDONLY);
111 if (pm == -1) {
112 if ((errno == EPERM) && (geteuid() != 0)) {
113 tst_brkm(TCONF | TERRNO, NULL,
114 "don't have permission to open dev pagemap");
115 } else {
116 tst_brkm(TFAIL | TERRNO, NULL,
117 "Open dev pagemap failed");
118 }
119 }
120
121 offset = lseek(pm, index, SEEK_SET);
122 if (offset != index)
123 tst_brkm(TFAIL | TERRNO, NULL, "Reposition offset failed");
124
125 while (i <= num_pages) {
126 ret = read(pm, &pagemap, sizeof(uint64_t));
127 if (ret < 0)
128 tst_brkm(TFAIL | TERRNO, NULL, "Read pagemap failed");
129 /*
130 * Check if the page is present.
131 */
132 if (!(pagemap & (1ULL<<63))) {
133 tst_resm(TINFO, "The %dth page addressed at %lX is not "
134 "present", i, vmstart + i * page_sz);
135 flag = 1;
136 }
137
138 i++;
139 }
140
141 close(pm);
142
143 if (flag)
144 return 1;
145
146 return 0;
147 }
148
setup(void)149 static void setup(void)
150 {
151 tst_sig(FORK, DEF_HANDLER, cleanup);
152
153 if ((tst_kvercmp(2, 6, 25)) < 0)
154 tst_brkm(TCONF, NULL,
155 "This test can only run on kernels that are 2.6.25 and "
156 "higher");
157
158 TEST_PAUSE;
159
160 tst_tmpdir();
161
162 fildes = open(TEMPFILE, O_RDWR | O_CREAT, 0766);
163 if (fildes < 0)
164 tst_brkm(TFAIL, cleanup, "opening %s failed", TEMPFILE);
165
166 if (ftruncate(fildes, MMAPSIZE) < 0)
167 tst_brkm(TFAIL | TERRNO, cleanup, "ftruncate file failed");
168
169 }
170
cleanup(void)171 static void cleanup(void)
172 {
173 close(fildes);
174 tst_rmdir();
175 }
176