1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2013 FNST, DAN LI <li.dan@cn.fujitsu.com>
4f08c3bdfSopenharmony_ci */
5f08c3bdfSopenharmony_ci
6f08c3bdfSopenharmony_ci/*
7f08c3bdfSopenharmony_ci * Test Description:
8f08c3bdfSopenharmony_ci *  Verify MAP_POPULATE works fine.
9f08c3bdfSopenharmony_ci *  "For a file mapping, this causes read-ahead on the file.
10f08c3bdfSopenharmony_ci *   Later accesses to the mapping will not be blocked by page faults"
11f08c3bdfSopenharmony_ci *
12f08c3bdfSopenharmony_ci * Expected Result:
13f08c3bdfSopenharmony_ci *  mmap() with MAP_POPULATE should succeed returning the address of the
14f08c3bdfSopenharmony_ci *  mapped region and this file has been read into RAM, so pages should
15f08c3bdfSopenharmony_ci *  be present.
16f08c3bdfSopenharmony_ci */
17f08c3bdfSopenharmony_ci#include <stdio.h>
18f08c3bdfSopenharmony_ci#include <stdlib.h>
19f08c3bdfSopenharmony_ci#include <sys/types.h>
20f08c3bdfSopenharmony_ci#include <errno.h>
21f08c3bdfSopenharmony_ci#include <unistd.h>
22f08c3bdfSopenharmony_ci#include <fcntl.h>
23f08c3bdfSopenharmony_ci#include <string.h>
24f08c3bdfSopenharmony_ci#include <signal.h>
25f08c3bdfSopenharmony_ci#include <stdint.h>
26f08c3bdfSopenharmony_ci#include <sys/stat.h>
27f08c3bdfSopenharmony_ci#include <sys/mman.h>
28f08c3bdfSopenharmony_ci#include <sys/shm.h>
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_ci#include "tst_test.h"
31f08c3bdfSopenharmony_ci
32f08c3bdfSopenharmony_ci#define TEMPFILE        "mmapfile"
33f08c3bdfSopenharmony_ci#define PATHLEN         256
34f08c3bdfSopenharmony_ci#define MMAPSIZE        (1UL<<20)
35f08c3bdfSopenharmony_ci
36f08c3bdfSopenharmony_cistatic int fildes;
37f08c3bdfSopenharmony_cistatic char *addr;
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_cistatic void page_check(void)
40f08c3bdfSopenharmony_ci{
41f08c3bdfSopenharmony_ci	int i = 1;
42f08c3bdfSopenharmony_ci	int flag = 0;
43f08c3bdfSopenharmony_ci	int pm;
44f08c3bdfSopenharmony_ci	int num_pages;
45f08c3bdfSopenharmony_ci	long index;
46f08c3bdfSopenharmony_ci	off_t offset;
47f08c3bdfSopenharmony_ci	size_t page_sz;
48f08c3bdfSopenharmony_ci	uint64_t pagemap;
49f08c3bdfSopenharmony_ci	unsigned long vmstart;
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_ci	vmstart = (unsigned long)addr;
52f08c3bdfSopenharmony_ci	page_sz = getpagesize();
53f08c3bdfSopenharmony_ci
54f08c3bdfSopenharmony_ci	num_pages = MMAPSIZE / page_sz;
55f08c3bdfSopenharmony_ci	index = (vmstart / page_sz) * sizeof(uint64_t);
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_ci	pm = open("/proc/self/pagemap", O_RDONLY);
58f08c3bdfSopenharmony_ci	if (pm == -1) {
59f08c3bdfSopenharmony_ci		if ((errno == EPERM) && (geteuid() != 0)) {
60f08c3bdfSopenharmony_ci			tst_res(TCONF | TERRNO,
61f08c3bdfSopenharmony_ci				"don't have permission to open dev pagemap");
62f08c3bdfSopenharmony_ci			return;
63f08c3bdfSopenharmony_ci		} else {
64f08c3bdfSopenharmony_ci			tst_brk(TFAIL | TERRNO, "pen dev pagemap failed");
65f08c3bdfSopenharmony_ci		}
66f08c3bdfSopenharmony_ci	}
67f08c3bdfSopenharmony_ci
68f08c3bdfSopenharmony_ci	offset = SAFE_LSEEK(pm, index, SEEK_SET);
69f08c3bdfSopenharmony_ci	if (offset != index)
70f08c3bdfSopenharmony_ci		tst_brk(TFAIL | TERRNO, "Reposition offset failed");
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_ci	while (i <= num_pages) {
73f08c3bdfSopenharmony_ci		SAFE_READ(1, pm, &pagemap, sizeof(uint64_t));
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ci		/*
76f08c3bdfSopenharmony_ci		 * Check if the page is present.
77f08c3bdfSopenharmony_ci		 */
78f08c3bdfSopenharmony_ci		if (!(pagemap & (1ULL<<63))) {
79f08c3bdfSopenharmony_ci			tst_res(TINFO, "The %dth page addressed at %lX is not "
80f08c3bdfSopenharmony_ci				       "present", i, vmstart + i * page_sz);
81f08c3bdfSopenharmony_ci			flag = 1;
82f08c3bdfSopenharmony_ci		}
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ci		i++;
85f08c3bdfSopenharmony_ci	}
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_ci	close(pm);
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci	if (!flag)
90f08c3bdfSopenharmony_ci		tst_res(TINFO, "All pages are present");
91f08c3bdfSopenharmony_ci}
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_civoid verify_mmap(void)
94f08c3bdfSopenharmony_ci{
95f08c3bdfSopenharmony_ci	unsigned int i;
96f08c3bdfSopenharmony_ci
97f08c3bdfSopenharmony_ci	addr = mmap(NULL, MMAPSIZE, PROT_READ | PROT_WRITE,
98f08c3bdfSopenharmony_ci		    MAP_PRIVATE | MAP_POPULATE, fildes, 0);
99f08c3bdfSopenharmony_ci
100f08c3bdfSopenharmony_ci	if (addr == MAP_FAILED) {
101f08c3bdfSopenharmony_ci		tst_res(TFAIL | TERRNO, "mmap of %s failed", TEMPFILE);
102f08c3bdfSopenharmony_ci		return;
103f08c3bdfSopenharmony_ci	}
104f08c3bdfSopenharmony_ci
105f08c3bdfSopenharmony_ci	page_check();
106f08c3bdfSopenharmony_ci
107f08c3bdfSopenharmony_ci	for (i = 0; i < MMAPSIZE; i++) {
108f08c3bdfSopenharmony_ci		if (addr[i]) {
109f08c3bdfSopenharmony_ci			tst_res(TFAIL, "Non-zero byte at offset %i", i);
110f08c3bdfSopenharmony_ci			goto unmap;
111f08c3bdfSopenharmony_ci		}
112f08c3bdfSopenharmony_ci	}
113f08c3bdfSopenharmony_ci
114f08c3bdfSopenharmony_ci	tst_res(TPASS, "File mapped properly");
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_ciunmap:
117f08c3bdfSopenharmony_ci	SAFE_MUNMAP(addr, MMAPSIZE);
118f08c3bdfSopenharmony_ci}
119f08c3bdfSopenharmony_ci
120f08c3bdfSopenharmony_cistatic void setup(void)
121f08c3bdfSopenharmony_ci{
122f08c3bdfSopenharmony_ci	fildes = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0766);
123f08c3bdfSopenharmony_ci
124f08c3bdfSopenharmony_ci	SAFE_FTRUNCATE(fildes, MMAPSIZE);
125f08c3bdfSopenharmony_ci}
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_cistatic void cleanup(void)
128f08c3bdfSopenharmony_ci{
129f08c3bdfSopenharmony_ci	if (fildes > 0)
130f08c3bdfSopenharmony_ci		SAFE_CLOSE(fildes);
131f08c3bdfSopenharmony_ci}
132f08c3bdfSopenharmony_ci
133f08c3bdfSopenharmony_cistatic struct tst_test test = {
134f08c3bdfSopenharmony_ci	.setup = setup,
135f08c3bdfSopenharmony_ci	.cleanup = cleanup,
136f08c3bdfSopenharmony_ci	.test_all = verify_mmap,
137f08c3bdfSopenharmony_ci	.needs_tmpdir = 1,
138f08c3bdfSopenharmony_ci};
139