drm/nouveau: fence: fix undefined fence state after emit
[platform/kernel/linux-rpi.git] / tools / testing / selftests / mincore / mincore_selftest.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * kselftest suite for mincore().
4  *
5  * Copyright (C) 2020 Collabora, Ltd.
6  */
7
8 #define _GNU_SOURCE
9
10 #include <stdio.h>
11 #include <errno.h>
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <sys/mman.h>
15 #include <string.h>
16 #include <fcntl.h>
17
18 #include "../kselftest.h"
19 #include "../kselftest_harness.h"
20
21 /* Default test file size: 4MB */
22 #define MB (1UL << 20)
23 #define FILE_SIZE (4 * MB)
24
25
26 /*
27  * Tests the user interface. This test triggers most of the documented
28  * error conditions in mincore().
29  */
30 TEST(basic_interface)
31 {
32         int retval;
33         int page_size;
34         unsigned char vec[1];
35         char *addr;
36
37         page_size = sysconf(_SC_PAGESIZE);
38
39         /* Query a 0 byte sized range */
40         retval = mincore(0, 0, vec);
41         EXPECT_EQ(0, retval);
42
43         /* Addresses in the specified range are invalid or unmapped */
44         errno = 0;
45         retval = mincore(NULL, page_size, vec);
46         EXPECT_EQ(-1, retval);
47         EXPECT_EQ(ENOMEM, errno);
48
49         errno = 0;
50         addr = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
51                 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
52         ASSERT_NE(MAP_FAILED, addr) {
53                 TH_LOG("mmap error: %s", strerror(errno));
54         }
55
56         /* <addr> argument is not page-aligned */
57         errno = 0;
58         retval = mincore(addr + 1, page_size, vec);
59         EXPECT_EQ(-1, retval);
60         EXPECT_EQ(EINVAL, errno);
61
62         /* <length> argument is too large */
63         errno = 0;
64         retval = mincore(addr, -1, vec);
65         EXPECT_EQ(-1, retval);
66         EXPECT_EQ(ENOMEM, errno);
67
68         /* <vec> argument points to an illegal address */
69         errno = 0;
70         retval = mincore(addr, page_size, NULL);
71         EXPECT_EQ(-1, retval);
72         EXPECT_EQ(EFAULT, errno);
73         munmap(addr, page_size);
74 }
75
76
77 /*
78  * Test mincore() behavior on a private anonymous page mapping.
79  * Check that the page is not loaded into memory right after the mapping
80  * but after accessing it (on-demand allocation).
81  * Then free the page and check that it's not memory-resident.
82  */
83 TEST(check_anonymous_locked_pages)
84 {
85         unsigned char vec[1];
86         char *addr;
87         int retval;
88         int page_size;
89
90         page_size = sysconf(_SC_PAGESIZE);
91
92         /* Map one page and check it's not memory-resident */
93         errno = 0;
94         addr = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
95                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
96         ASSERT_NE(MAP_FAILED, addr) {
97                 TH_LOG("mmap error: %s", strerror(errno));
98         }
99         retval = mincore(addr, page_size, vec);
100         ASSERT_EQ(0, retval);
101         ASSERT_EQ(0, vec[0]) {
102                 TH_LOG("Page found in memory before use");
103         }
104
105         /* Touch the page and check again. It should now be in memory */
106         addr[0] = 1;
107         mlock(addr, page_size);
108         retval = mincore(addr, page_size, vec);
109         ASSERT_EQ(0, retval);
110         ASSERT_EQ(1, vec[0]) {
111                 TH_LOG("Page not found in memory after use");
112         }
113
114         /*
115          * It shouldn't be memory-resident after unlocking it and
116          * marking it as unneeded.
117          */
118         munlock(addr, page_size);
119         madvise(addr, page_size, MADV_DONTNEED);
120         retval = mincore(addr, page_size, vec);
121         ASSERT_EQ(0, retval);
122         ASSERT_EQ(0, vec[0]) {
123                 TH_LOG("Page in memory after being zapped");
124         }
125         munmap(addr, page_size);
126 }
127
128
129 /*
130  * Check mincore() behavior on huge pages.
131  * This test will be skipped if the mapping fails (ie. if there are no
132  * huge pages available).
133  *
134  * Make sure the system has at least one free huge page, check
135  * "HugePages_Free" in /proc/meminfo.
136  * Increment /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages if
137  * needed.
138  */
139 TEST(check_huge_pages)
140 {
141         unsigned char vec[1];
142         char *addr;
143         int retval;
144         int page_size;
145
146         page_size = sysconf(_SC_PAGESIZE);
147
148         errno = 0;
149         addr = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
150                 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
151                 -1, 0);
152         if (addr == MAP_FAILED) {
153                 if (errno == ENOMEM)
154                         SKIP(return, "No huge pages available.");
155                 else
156                         TH_LOG("mmap error: %s", strerror(errno));
157         }
158         retval = mincore(addr, page_size, vec);
159         ASSERT_EQ(0, retval);
160         ASSERT_EQ(0, vec[0]) {
161                 TH_LOG("Page found in memory before use");
162         }
163
164         addr[0] = 1;
165         mlock(addr, page_size);
166         retval = mincore(addr, page_size, vec);
167         ASSERT_EQ(0, retval);
168         ASSERT_EQ(1, vec[0]) {
169                 TH_LOG("Page not found in memory after use");
170         }
171
172         munlock(addr, page_size);
173         munmap(addr, page_size);
174 }
175
176
177 /*
178  * Test mincore() behavior on a file-backed page.
179  * No pages should be loaded into memory right after the mapping. Then,
180  * accessing any address in the mapping range should load the page
181  * containing the address and a number of subsequent pages (readahead).
182  *
183  * The actual readahead settings depend on the test environment, so we
184  * can't make a lot of assumptions about that. This test covers the most
185  * general cases.
186  */
187 TEST(check_file_mmap)
188 {
189         unsigned char *vec;
190         int vec_size;
191         char *addr;
192         int retval;
193         int page_size;
194         int fd;
195         int i;
196         int ra_pages = 0;
197
198         page_size = sysconf(_SC_PAGESIZE);
199         vec_size = FILE_SIZE / page_size;
200         if (FILE_SIZE % page_size)
201                 vec_size++;
202
203         vec = calloc(vec_size, sizeof(unsigned char));
204         ASSERT_NE(NULL, vec) {
205                 TH_LOG("Can't allocate array");
206         }
207
208         errno = 0;
209         fd = open(".", O_TMPFILE | O_RDWR, 0600);
210         if (fd < 0) {
211                 ASSERT_EQ(errno, EOPNOTSUPP) {
212                         TH_LOG("Can't create temporary file: %s",
213                                strerror(errno));
214                 }
215                 SKIP(goto out_free, "O_TMPFILE not supported by filesystem.");
216         }
217         errno = 0;
218         retval = fallocate(fd, 0, 0, FILE_SIZE);
219         if (retval) {
220                 ASSERT_EQ(errno, EOPNOTSUPP) {
221                         TH_LOG("Error allocating space for the temporary file: %s",
222                                strerror(errno));
223                 }
224                 SKIP(goto out_close, "fallocate not supported by filesystem.");
225         }
226
227         /*
228          * Map the whole file, the pages shouldn't be fetched yet.
229          */
230         errno = 0;
231         addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE,
232                         MAP_SHARED, fd, 0);
233         ASSERT_NE(MAP_FAILED, addr) {
234                 TH_LOG("mmap error: %s", strerror(errno));
235         }
236         retval = mincore(addr, FILE_SIZE, vec);
237         ASSERT_EQ(0, retval);
238         for (i = 0; i < vec_size; i++) {
239                 ASSERT_EQ(0, vec[i]) {
240                         TH_LOG("Unexpected page in memory");
241                 }
242         }
243
244         /*
245          * Touch a page in the middle of the mapping. We expect the next
246          * few pages (the readahead window) to be populated too.
247          */
248         addr[FILE_SIZE / 2] = 1;
249         retval = mincore(addr, FILE_SIZE, vec);
250         ASSERT_EQ(0, retval);
251         ASSERT_EQ(1, vec[FILE_SIZE / 2 / page_size]) {
252                 TH_LOG("Page not found in memory after use");
253         }
254
255         i = FILE_SIZE / 2 / page_size + 1;
256         while (i < vec_size && vec[i]) {
257                 ra_pages++;
258                 i++;
259         }
260         EXPECT_GT(ra_pages, 0) {
261                 TH_LOG("No read-ahead pages found in memory");
262         }
263
264         EXPECT_LT(i, vec_size) {
265                 TH_LOG("Read-ahead pages reached the end of the file");
266         }
267         /*
268          * End of the readahead window. The rest of the pages shouldn't
269          * be in memory.
270          */
271         if (i < vec_size) {
272                 while (i < vec_size && !vec[i])
273                         i++;
274                 EXPECT_EQ(vec_size, i) {
275                         TH_LOG("Unexpected page in memory beyond readahead window");
276                 }
277         }
278
279         munmap(addr, FILE_SIZE);
280 out_close:
281         close(fd);
282 out_free:
283         free(vec);
284 }
285
286
287 /*
288  * Test mincore() behavior on a page backed by a tmpfs file.  This test
289  * performs the same steps as the previous one. However, we don't expect
290  * any readahead in this case.
291  */
292 TEST(check_tmpfs_mmap)
293 {
294         unsigned char *vec;
295         int vec_size;
296         char *addr;
297         int retval;
298         int page_size;
299         int fd;
300         int i;
301         int ra_pages = 0;
302
303         page_size = sysconf(_SC_PAGESIZE);
304         vec_size = FILE_SIZE / page_size;
305         if (FILE_SIZE % page_size)
306                 vec_size++;
307
308         vec = calloc(vec_size, sizeof(unsigned char));
309         ASSERT_NE(NULL, vec) {
310                 TH_LOG("Can't allocate array");
311         }
312
313         errno = 0;
314         fd = open("/dev/shm", O_TMPFILE | O_RDWR, 0600);
315         ASSERT_NE(-1, fd) {
316                 TH_LOG("Can't create temporary file: %s",
317                         strerror(errno));
318         }
319         errno = 0;
320         retval = fallocate(fd, 0, 0, FILE_SIZE);
321         ASSERT_EQ(0, retval) {
322                 TH_LOG("Error allocating space for the temporary file: %s",
323                         strerror(errno));
324         }
325
326         /*
327          * Map the whole file, the pages shouldn't be fetched yet.
328          */
329         errno = 0;
330         addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE,
331                         MAP_SHARED, fd, 0);
332         ASSERT_NE(MAP_FAILED, addr) {
333                 TH_LOG("mmap error: %s", strerror(errno));
334         }
335         retval = mincore(addr, FILE_SIZE, vec);
336         ASSERT_EQ(0, retval);
337         for (i = 0; i < vec_size; i++) {
338                 ASSERT_EQ(0, vec[i]) {
339                         TH_LOG("Unexpected page in memory");
340                 }
341         }
342
343         /*
344          * Touch a page in the middle of the mapping. We expect only
345          * that page to be fetched into memory.
346          */
347         addr[FILE_SIZE / 2] = 1;
348         retval = mincore(addr, FILE_SIZE, vec);
349         ASSERT_EQ(0, retval);
350         ASSERT_EQ(1, vec[FILE_SIZE / 2 / page_size]) {
351                 TH_LOG("Page not found in memory after use");
352         }
353
354         i = FILE_SIZE / 2 / page_size + 1;
355         while (i < vec_size && vec[i]) {
356                 ra_pages++;
357                 i++;
358         }
359         ASSERT_EQ(ra_pages, 0) {
360                 TH_LOG("Read-ahead pages found in memory");
361         }
362
363         munmap(addr, FILE_SIZE);
364         close(fd);
365         free(vec);
366 }
367
368 TEST_HARNESS_MAIN