• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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