• 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 "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