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"
24 * For now, we're using 2 MiB of private anonymous memory for all tests.
26 #define SIZE (2 * 1024 * 1024)
28 static size_t pagesize
;
30 static void sense_support(void)
35 addr
= mmap(0, pagesize
, PROT_READ
| PROT_WRITE
,
36 MAP_ANONYMOUS
| MAP_PRIVATE
, 0, 0);
38 ksft_exit_fail_msg("mmap failed\n");
40 ret
= madvise(addr
, pagesize
, MADV_POPULATE_READ
);
42 ksft_exit_skip("MADV_POPULATE_READ is not available\n");
44 ret
= madvise(addr
, pagesize
, MADV_POPULATE_WRITE
);
46 ksft_exit_skip("MADV_POPULATE_WRITE is not available\n");
48 munmap(addr
, pagesize
);
51 static void test_prot_read(void)
56 ksft_print_msg("[RUN] %s\n", __func__
);
58 addr
= mmap(0, SIZE
, PROT_READ
, MAP_ANONYMOUS
| MAP_PRIVATE
, 0, 0);
59 if (addr
== MAP_FAILED
)
60 ksft_exit_fail_msg("mmap failed\n");
62 ret
= madvise(addr
, SIZE
, MADV_POPULATE_READ
);
63 ksft_test_result(!ret
, "MADV_POPULATE_READ with PROT_READ\n");
65 ret
= madvise(addr
, SIZE
, MADV_POPULATE_WRITE
);
66 ksft_test_result(ret
== -1 && errno
== EINVAL
,
67 "MADV_POPULATE_WRITE with PROT_READ\n");
72 static void test_prot_write(void)
77 ksft_print_msg("[RUN] %s\n", __func__
);
79 addr
= mmap(0, SIZE
, PROT_WRITE
, MAP_ANONYMOUS
| MAP_PRIVATE
, 0, 0);
80 if (addr
== MAP_FAILED
)
81 ksft_exit_fail_msg("mmap failed\n");
83 ret
= madvise(addr
, SIZE
, MADV_POPULATE_READ
);
84 ksft_test_result(ret
== -1 && errno
== EINVAL
,
85 "MADV_POPULATE_READ with PROT_WRITE\n");
87 ret
= madvise(addr
, SIZE
, MADV_POPULATE_WRITE
);
88 ksft_test_result(!ret
, "MADV_POPULATE_WRITE with PROT_WRITE\n");
93 static void test_holes(void)
98 ksft_print_msg("[RUN] %s\n", __func__
);
100 addr
= mmap(0, SIZE
, PROT_READ
| PROT_WRITE
,
101 MAP_ANONYMOUS
| MAP_PRIVATE
, 0, 0);
102 if (addr
== MAP_FAILED
)
103 ksft_exit_fail_msg("mmap failed\n");
104 ret
= munmap(addr
+ pagesize
, pagesize
);
106 ksft_exit_fail_msg("munmap failed\n");
108 /* Hole in the middle */
109 ret
= madvise(addr
, SIZE
, MADV_POPULATE_READ
);
110 ksft_test_result(ret
== -1 && errno
== ENOMEM
,
111 "MADV_POPULATE_READ with holes in the middle\n");
112 ret
= madvise(addr
, SIZE
, MADV_POPULATE_WRITE
);
113 ksft_test_result(ret
== -1 && errno
== ENOMEM
,
114 "MADV_POPULATE_WRITE with holes in the middle\n");
117 ret
= madvise(addr
, 2 * pagesize
, MADV_POPULATE_READ
);
118 ksft_test_result(ret
== -1 && errno
== ENOMEM
,
119 "MADV_POPULATE_READ with holes at the end\n");
120 ret
= madvise(addr
, 2 * pagesize
, MADV_POPULATE_WRITE
);
121 ksft_test_result(ret
== -1 && errno
== ENOMEM
,
122 "MADV_POPULATE_WRITE with holes at the end\n");
124 /* Hole at beginning */
125 ret
= madvise(addr
+ pagesize
, pagesize
, MADV_POPULATE_READ
);
126 ksft_test_result(ret
== -1 && errno
== ENOMEM
,
127 "MADV_POPULATE_READ with holes at the beginning\n");
128 ret
= madvise(addr
+ pagesize
, pagesize
, MADV_POPULATE_WRITE
);
129 ksft_test_result(ret
== -1 && errno
== ENOMEM
,
130 "MADV_POPULATE_WRITE with holes at the beginning\n");
135 static bool range_is_populated(char *start
, ssize_t size
)
137 int fd
= open("/proc/self/pagemap", O_RDONLY
);
141 ksft_exit_fail_msg("opening pagemap failed\n");
142 for (; size
> 0 && ret
; size
-= pagesize
, start
+= pagesize
)
143 if (!pagemap_is_populated(fd
, start
))
149 static bool range_is_not_populated(char *start
, ssize_t size
)
151 int fd
= open("/proc/self/pagemap", O_RDONLY
);
155 ksft_exit_fail_msg("opening pagemap failed\n");
156 for (; size
> 0 && ret
; size
-= pagesize
, start
+= pagesize
)
157 if (pagemap_is_populated(fd
, start
))
163 static void test_populate_read(void)
168 ksft_print_msg("[RUN] %s\n", __func__
);
170 addr
= mmap(0, SIZE
, PROT_READ
| PROT_WRITE
,
171 MAP_ANONYMOUS
| MAP_PRIVATE
, 0, 0);
172 if (addr
== MAP_FAILED
)
173 ksft_exit_fail_msg("mmap failed\n");
174 ksft_test_result(range_is_not_populated(addr
, SIZE
),
175 "range initially not populated\n");
177 ret
= madvise(addr
, SIZE
, MADV_POPULATE_READ
);
178 ksft_test_result(!ret
, "MADV_POPULATE_READ\n");
179 ksft_test_result(range_is_populated(addr
, SIZE
),
180 "range is populated\n");
185 static void test_populate_write(void)
190 ksft_print_msg("[RUN] %s\n", __func__
);
192 addr
= mmap(0, SIZE
, PROT_READ
| PROT_WRITE
,
193 MAP_ANONYMOUS
| MAP_PRIVATE
, 0, 0);
194 if (addr
== MAP_FAILED
)
195 ksft_exit_fail_msg("mmap failed\n");
196 ksft_test_result(range_is_not_populated(addr
, SIZE
),
197 "range initially not populated\n");
199 ret
= madvise(addr
, SIZE
, MADV_POPULATE_WRITE
);
200 ksft_test_result(!ret
, "MADV_POPULATE_WRITE\n");
201 ksft_test_result(range_is_populated(addr
, SIZE
),
202 "range is populated\n");
207 static bool range_is_softdirty(char *start
, ssize_t size
)
209 int fd
= open("/proc/self/pagemap", O_RDONLY
);
213 ksft_exit_fail_msg("opening pagemap failed\n");
214 for (; size
> 0 && ret
; size
-= pagesize
, start
+= pagesize
)
215 if (!pagemap_is_softdirty(fd
, start
))
221 static bool range_is_not_softdirty(char *start
, ssize_t size
)
223 int fd
= open("/proc/self/pagemap", O_RDONLY
);
227 ksft_exit_fail_msg("opening pagemap failed\n");
228 for (; size
> 0 && ret
; size
-= pagesize
, start
+= pagesize
)
229 if (pagemap_is_softdirty(fd
, start
))
235 static void test_softdirty(void)
240 ksft_print_msg("[RUN] %s\n", __func__
);
242 addr
= mmap(0, SIZE
, PROT_READ
| PROT_WRITE
,
243 MAP_ANONYMOUS
| MAP_PRIVATE
, 0, 0);
244 if (addr
== MAP_FAILED
)
245 ksft_exit_fail_msg("mmap failed\n");
247 /* Clear any softdirty bits. */
249 ksft_test_result(range_is_not_softdirty(addr
, SIZE
),
250 "range is not softdirty\n");
252 /* Populating READ should set softdirty. */
253 ret
= madvise(addr
, SIZE
, MADV_POPULATE_READ
);
254 ksft_test_result(!ret
, "MADV_POPULATE_READ\n");
255 ksft_test_result(range_is_not_softdirty(addr
, SIZE
),
256 "range is not softdirty\n");
258 /* Populating WRITE should set softdirty. */
259 ret
= madvise(addr
, SIZE
, MADV_POPULATE_WRITE
);
260 ksft_test_result(!ret
, "MADV_POPULATE_WRITE\n");
261 ksft_test_result(range_is_softdirty(addr
, SIZE
),
262 "range is softdirty\n");
267 static int system_has_softdirty(void)
270 * There is no way to check if the kernel supports soft-dirty, other
271 * than by writing to a page and seeing if the bit was set. But the
272 * tests are intended to check that the bit gets set when it should, so
273 * doing that check would turn a potentially legitimate fail into a
274 * skip. Fortunately, we know for sure that arm64 does not support
275 * soft-dirty. So for now, let's just use the arch as a corse guide.
277 #if defined(__aarch64__)
284 int main(int argc
, char **argv
)
289 pagesize
= getpagesize();
291 if (system_has_softdirty())
295 ksft_set_plan(nr_tests
);
301 test_populate_read();
302 test_populate_write();
303 if (system_has_softdirty())
306 err
= ksft_get_fail_cnt();
308 ksft_exit_fail_msg("%d out of %d tests failed\n",
309 err
, ksft_test_num());