1 // SPDX-License-Identifier: GPL-2.0-only
3 * MADV_POPULATE_READ and MADV_POPULATE_WRITE tests
5 * Copyright 2021, Red Hat, Inc.
7 * Author(s): David Hildenbrand <david@redhat.com>
17 #include <linux/mman.h>
20 #include "../kselftest.h"
23 #ifndef MADV_POPULATE_READ
24 #define MADV_POPULATE_READ 22
25 #endif /* MADV_POPULATE_READ */
26 #ifndef MADV_POPULATE_WRITE
27 #define MADV_POPULATE_WRITE 23
28 #endif /* MADV_POPULATE_WRITE */
31 * For now, we're using 2 MiB of private anonymous memory for all tests.
33 #define SIZE (2 * 1024 * 1024)
35 static size_t pagesize;
37 static void sense_support(void)
42 addr = mmap(0, pagesize, PROT_READ | PROT_WRITE,
43 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
45 ksft_exit_fail_msg("mmap failed\n");
47 ret = madvise(addr, pagesize, MADV_POPULATE_READ);
49 ksft_exit_skip("MADV_POPULATE_READ is not available\n");
51 ret = madvise(addr, pagesize, MADV_POPULATE_WRITE);
53 ksft_exit_skip("MADV_POPULATE_WRITE is not available\n");
55 munmap(addr, pagesize);
58 static void test_prot_read(void)
63 ksft_print_msg("[RUN] %s\n", __func__);
65 addr = mmap(0, SIZE, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
66 if (addr == MAP_FAILED)
67 ksft_exit_fail_msg("mmap failed\n");
69 ret = madvise(addr, SIZE, MADV_POPULATE_READ);
70 ksft_test_result(!ret, "MADV_POPULATE_READ with PROT_READ\n");
72 ret = madvise(addr, SIZE, MADV_POPULATE_WRITE);
73 ksft_test_result(ret == -1 && errno == EINVAL,
74 "MADV_POPULATE_WRITE with PROT_READ\n");
79 static void test_prot_write(void)
84 ksft_print_msg("[RUN] %s\n", __func__);
86 addr = mmap(0, SIZE, PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
87 if (addr == MAP_FAILED)
88 ksft_exit_fail_msg("mmap failed\n");
90 ret = madvise(addr, SIZE, MADV_POPULATE_READ);
91 ksft_test_result(ret == -1 && errno == EINVAL,
92 "MADV_POPULATE_READ with PROT_WRITE\n");
94 ret = madvise(addr, SIZE, MADV_POPULATE_WRITE);
95 ksft_test_result(!ret, "MADV_POPULATE_WRITE with PROT_WRITE\n");
100 static void test_holes(void)
105 ksft_print_msg("[RUN] %s\n", __func__);
107 addr = mmap(0, SIZE, PROT_READ | PROT_WRITE,
108 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
109 if (addr == MAP_FAILED)
110 ksft_exit_fail_msg("mmap failed\n");
111 ret = munmap(addr + pagesize, pagesize);
113 ksft_exit_fail_msg("munmap failed\n");
115 /* Hole in the middle */
116 ret = madvise(addr, SIZE, MADV_POPULATE_READ);
117 ksft_test_result(ret == -1 && errno == ENOMEM,
118 "MADV_POPULATE_READ with holes in the middle\n");
119 ret = madvise(addr, SIZE, MADV_POPULATE_WRITE);
120 ksft_test_result(ret == -1 && errno == ENOMEM,
121 "MADV_POPULATE_WRITE with holes in the middle\n");
124 ret = madvise(addr, 2 * pagesize, MADV_POPULATE_READ);
125 ksft_test_result(ret == -1 && errno == ENOMEM,
126 "MADV_POPULATE_READ with holes at the end\n");
127 ret = madvise(addr, 2 * pagesize, MADV_POPULATE_WRITE);
128 ksft_test_result(ret == -1 && errno == ENOMEM,
129 "MADV_POPULATE_WRITE with holes at the end\n");
131 /* Hole at beginning */
132 ret = madvise(addr + pagesize, pagesize, MADV_POPULATE_READ);
133 ksft_test_result(ret == -1 && errno == ENOMEM,
134 "MADV_POPULATE_READ with holes at the beginning\n");
135 ret = madvise(addr + pagesize, pagesize, MADV_POPULATE_WRITE);
136 ksft_test_result(ret == -1 && errno == ENOMEM,
137 "MADV_POPULATE_WRITE with holes at the beginning\n");
142 static bool range_is_populated(char *start, ssize_t size)
144 int fd = open("/proc/self/pagemap", O_RDONLY);
148 ksft_exit_fail_msg("opening pagemap failed\n");
149 for (; size > 0 && ret; size -= pagesize, start += pagesize)
150 if (!pagemap_is_populated(fd, start))
156 static bool range_is_not_populated(char *start, ssize_t size)
158 int fd = open("/proc/self/pagemap", O_RDONLY);
162 ksft_exit_fail_msg("opening pagemap failed\n");
163 for (; size > 0 && ret; size -= pagesize, start += pagesize)
164 if (pagemap_is_populated(fd, start))
170 static void test_populate_read(void)
175 ksft_print_msg("[RUN] %s\n", __func__);
177 addr = mmap(0, SIZE, PROT_READ | PROT_WRITE,
178 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
179 if (addr == MAP_FAILED)
180 ksft_exit_fail_msg("mmap failed\n");
181 ksft_test_result(range_is_not_populated(addr, SIZE),
182 "range initially not populated\n");
184 ret = madvise(addr, SIZE, MADV_POPULATE_READ);
185 ksft_test_result(!ret, "MADV_POPULATE_READ\n");
186 ksft_test_result(range_is_populated(addr, SIZE),
187 "range is populated\n");
192 static void test_populate_write(void)
197 ksft_print_msg("[RUN] %s\n", __func__);
199 addr = mmap(0, SIZE, PROT_READ | PROT_WRITE,
200 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
201 if (addr == MAP_FAILED)
202 ksft_exit_fail_msg("mmap failed\n");
203 ksft_test_result(range_is_not_populated(addr, SIZE),
204 "range initially not populated\n");
206 ret = madvise(addr, SIZE, MADV_POPULATE_WRITE);
207 ksft_test_result(!ret, "MADV_POPULATE_WRITE\n");
208 ksft_test_result(range_is_populated(addr, SIZE),
209 "range is populated\n");
214 static bool range_is_softdirty(char *start, ssize_t size)
216 int fd = open("/proc/self/pagemap", O_RDONLY);
220 ksft_exit_fail_msg("opening pagemap failed\n");
221 for (; size > 0 && ret; size -= pagesize, start += pagesize)
222 if (!pagemap_is_softdirty(fd, start))
228 static bool range_is_not_softdirty(char *start, ssize_t size)
230 int fd = open("/proc/self/pagemap", O_RDONLY);
234 ksft_exit_fail_msg("opening pagemap failed\n");
235 for (; size > 0 && ret; size -= pagesize, start += pagesize)
236 if (pagemap_is_softdirty(fd, start))
242 static void test_softdirty(void)
247 ksft_print_msg("[RUN] %s\n", __func__);
249 addr = mmap(0, SIZE, PROT_READ | PROT_WRITE,
250 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
251 if (addr == MAP_FAILED)
252 ksft_exit_fail_msg("mmap failed\n");
254 /* Clear any softdirty bits. */
256 ksft_test_result(range_is_not_softdirty(addr, SIZE),
257 "range is not softdirty\n");
259 /* Populating READ should set softdirty. */
260 ret = madvise(addr, SIZE, MADV_POPULATE_READ);
261 ksft_test_result(!ret, "MADV_POPULATE_READ\n");
262 ksft_test_result(range_is_not_softdirty(addr, SIZE),
263 "range is not softdirty\n");
265 /* Populating WRITE should set softdirty. */
266 ret = madvise(addr, SIZE, MADV_POPULATE_WRITE);
267 ksft_test_result(!ret, "MADV_POPULATE_WRITE\n");
268 ksft_test_result(range_is_softdirty(addr, SIZE),
269 "range is softdirty\n");
274 int main(int argc, char **argv)
278 pagesize = getpagesize();
287 test_populate_read();
288 test_populate_write();
291 err = ksft_get_fail_cnt();
293 ksft_exit_fail_msg("%d out of %d tests failed\n",
294 err, ksft_test_num());
295 return ksft_exit_pass();