nds32: fix build error "relocation truncated to fit: R_NDS32_25_PCREL_RELA" when
[linux-2.6-microblaze.git] / tools / testing / selftests / vm / mlock2-tests.c
1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 #include <sys/mman.h>
4 #include <stdint.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <sys/time.h>
8 #include <sys/resource.h>
9 #include <stdbool.h>
10 #include "mlock2.h"
11
12 struct vm_boundaries {
13         unsigned long start;
14         unsigned long end;
15 };
16
17 static int get_vm_area(unsigned long addr, struct vm_boundaries *area)
18 {
19         FILE *file;
20         int ret = 1;
21         char line[1024] = {0};
22         char *end_addr;
23         char *stop;
24         unsigned long start;
25         unsigned long end;
26
27         if (!area)
28                 return ret;
29
30         file = fopen("/proc/self/maps", "r");
31         if (!file) {
32                 perror("fopen");
33                 return ret;
34         }
35
36         memset(area, 0, sizeof(struct vm_boundaries));
37
38         while(fgets(line, 1024, file)) {
39                 end_addr = strchr(line, '-');
40                 if (!end_addr) {
41                         printf("cannot parse /proc/self/maps\n");
42                         goto out;
43                 }
44                 *end_addr = '\0';
45                 end_addr++;
46                 stop = strchr(end_addr, ' ');
47                 if (!stop) {
48                         printf("cannot parse /proc/self/maps\n");
49                         goto out;
50                 }
51                 stop = '\0';
52
53                 sscanf(line, "%lx", &start);
54                 sscanf(end_addr, "%lx", &end);
55
56                 if (start <= addr && end > addr) {
57                         area->start = start;
58                         area->end = end;
59                         ret = 0;
60                         goto out;
61                 }
62         }
63 out:
64         fclose(file);
65         return ret;
66 }
67
68 static uint64_t get_pageflags(unsigned long addr)
69 {
70         FILE *file;
71         uint64_t pfn;
72         unsigned long offset;
73
74         file = fopen("/proc/self/pagemap", "r");
75         if (!file) {
76                 perror("fopen pagemap");
77                 _exit(1);
78         }
79
80         offset = addr / getpagesize() * sizeof(pfn);
81
82         if (fseek(file, offset, SEEK_SET)) {
83                 perror("fseek pagemap");
84                 _exit(1);
85         }
86
87         if (fread(&pfn, sizeof(pfn), 1, file) != 1) {
88                 perror("fread pagemap");
89                 _exit(1);
90         }
91
92         fclose(file);
93         return pfn;
94 }
95
96 static uint64_t get_kpageflags(unsigned long pfn)
97 {
98         uint64_t flags;
99         FILE *file;
100
101         file = fopen("/proc/kpageflags", "r");
102         if (!file) {
103                 perror("fopen kpageflags");
104                 _exit(1);
105         }
106
107         if (fseek(file, pfn * sizeof(flags), SEEK_SET)) {
108                 perror("fseek kpageflags");
109                 _exit(1);
110         }
111
112         if (fread(&flags, sizeof(flags), 1, file) != 1) {
113                 perror("fread kpageflags");
114                 _exit(1);
115         }
116
117         fclose(file);
118         return flags;
119 }
120
121 #define VMFLAGS "VmFlags:"
122
123 static bool is_vmflag_set(unsigned long addr, const char *vmflag)
124 {
125         char *line = NULL;
126         char *flags;
127         size_t size = 0;
128         bool ret = false;
129         FILE *smaps;
130
131         smaps = seek_to_smaps_entry(addr);
132         if (!smaps) {
133                 printf("Unable to parse /proc/self/smaps\n");
134                 goto out;
135         }
136
137         while (getline(&line, &size, smaps) > 0) {
138                 if (!strstr(line, VMFLAGS)) {
139                         free(line);
140                         line = NULL;
141                         size = 0;
142                         continue;
143                 }
144
145                 flags = line + strlen(VMFLAGS);
146                 ret = (strstr(flags, vmflag) != NULL);
147                 goto out;
148         }
149
150 out:
151         free(line);
152         fclose(smaps);
153         return ret;
154 }
155
156 #define SIZE "Size:"
157 #define RSS  "Rss:"
158 #define LOCKED "lo"
159
160 static bool is_vma_lock_on_fault(unsigned long addr)
161 {
162         bool ret = false;
163         bool locked;
164         FILE *smaps = NULL;
165         unsigned long vma_size, vma_rss;
166         char *line = NULL;
167         char *value;
168         size_t size = 0;
169
170         locked = is_vmflag_set(addr, LOCKED);
171         if (!locked)
172                 goto out;
173
174         smaps = seek_to_smaps_entry(addr);
175         if (!smaps) {
176                 printf("Unable to parse /proc/self/smaps\n");
177                 goto out;
178         }
179
180         while (getline(&line, &size, smaps) > 0) {
181                 if (!strstr(line, SIZE)) {
182                         free(line);
183                         line = NULL;
184                         size = 0;
185                         continue;
186                 }
187
188                 value = line + strlen(SIZE);
189                 if (sscanf(value, "%lu kB", &vma_size) < 1) {
190                         printf("Unable to parse smaps entry for Size\n");
191                         goto out;
192                 }
193                 break;
194         }
195
196         while (getline(&line, &size, smaps) > 0) {
197                 if (!strstr(line, RSS)) {
198                         free(line);
199                         line = NULL;
200                         size = 0;
201                         continue;
202                 }
203
204                 value = line + strlen(RSS);
205                 if (sscanf(value, "%lu kB", &vma_rss) < 1) {
206                         printf("Unable to parse smaps entry for Rss\n");
207                         goto out;
208                 }
209                 break;
210         }
211
212         ret = locked && (vma_rss < vma_size);
213 out:
214         free(line);
215         if (smaps)
216                 fclose(smaps);
217         return ret;
218 }
219
220 #define PRESENT_BIT     0x8000000000000000ULL
221 #define PFN_MASK        0x007FFFFFFFFFFFFFULL
222 #define UNEVICTABLE_BIT (1UL << 18)
223
224 static int lock_check(char *map)
225 {
226         unsigned long page_size = getpagesize();
227         uint64_t page1_flags, page2_flags;
228
229         page1_flags = get_pageflags((unsigned long)map);
230         page2_flags = get_pageflags((unsigned long)map + page_size);
231
232         /* Both pages should be present */
233         if (((page1_flags & PRESENT_BIT) == 0) ||
234             ((page2_flags & PRESENT_BIT) == 0)) {
235                 printf("Failed to make both pages present\n");
236                 return 1;
237         }
238
239         page1_flags = get_kpageflags(page1_flags & PFN_MASK);
240         page2_flags = get_kpageflags(page2_flags & PFN_MASK);
241
242         /* Both pages should be unevictable */
243         if (((page1_flags & UNEVICTABLE_BIT) == 0) ||
244             ((page2_flags & UNEVICTABLE_BIT) == 0)) {
245                 printf("Failed to make both pages unevictable\n");
246                 return 1;
247         }
248
249         if (!is_vmflag_set((unsigned long)map, LOCKED)) {
250                 printf("VMA flag %s is missing on page 1\n", LOCKED);
251                 return 1;
252         }
253
254         if (!is_vmflag_set((unsigned long)map + page_size, LOCKED)) {
255                 printf("VMA flag %s is missing on page 2\n", LOCKED);
256                 return 1;
257         }
258
259         return 0;
260 }
261
262 static int unlock_lock_check(char *map)
263 {
264         unsigned long page_size = getpagesize();
265         uint64_t page1_flags, page2_flags;
266
267         page1_flags = get_pageflags((unsigned long)map);
268         page2_flags = get_pageflags((unsigned long)map + page_size);
269         page1_flags = get_kpageflags(page1_flags & PFN_MASK);
270         page2_flags = get_kpageflags(page2_flags & PFN_MASK);
271
272         if ((page1_flags & UNEVICTABLE_BIT) || (page2_flags & UNEVICTABLE_BIT)) {
273                 printf("A page is still marked unevictable after unlock\n");
274                 return 1;
275         }
276
277         if (is_vmflag_set((unsigned long)map, LOCKED)) {
278                 printf("VMA flag %s is present on page 1 after unlock\n", LOCKED);
279                 return 1;
280         }
281
282         if (is_vmflag_set((unsigned long)map + page_size, LOCKED)) {
283                 printf("VMA flag %s is present on page 2 after unlock\n", LOCKED);
284                 return 1;
285         }
286
287         return 0;
288 }
289
290 static int test_mlock_lock()
291 {
292         char *map;
293         int ret = 1;
294         unsigned long page_size = getpagesize();
295
296         map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
297                    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
298         if (map == MAP_FAILED) {
299                 perror("test_mlock_locked mmap");
300                 goto out;
301         }
302
303         if (mlock2_(map, 2 * page_size, 0)) {
304                 if (errno == ENOSYS) {
305                         printf("Cannot call new mlock family, skipping test\n");
306                         _exit(0);
307                 }
308                 perror("mlock2(0)");
309                 goto unmap;
310         }
311
312         if (lock_check(map))
313                 goto unmap;
314
315         /* Now unlock and recheck attributes */
316         if (munlock(map, 2 * page_size)) {
317                 perror("munlock()");
318                 goto unmap;
319         }
320
321         ret = unlock_lock_check(map);
322
323 unmap:
324         munmap(map, 2 * page_size);
325 out:
326         return ret;
327 }
328
329 static int onfault_check(char *map)
330 {
331         unsigned long page_size = getpagesize();
332         uint64_t page1_flags, page2_flags;
333
334         page1_flags = get_pageflags((unsigned long)map);
335         page2_flags = get_pageflags((unsigned long)map + page_size);
336
337         /* Neither page should be present */
338         if ((page1_flags & PRESENT_BIT) || (page2_flags & PRESENT_BIT)) {
339                 printf("Pages were made present by MLOCK_ONFAULT\n");
340                 return 1;
341         }
342
343         *map = 'a';
344         page1_flags = get_pageflags((unsigned long)map);
345         page2_flags = get_pageflags((unsigned long)map + page_size);
346
347         /* Only page 1 should be present */
348         if ((page1_flags & PRESENT_BIT) == 0) {
349                 printf("Page 1 is not present after fault\n");
350                 return 1;
351         } else if (page2_flags & PRESENT_BIT) {
352                 printf("Page 2 was made present\n");
353                 return 1;
354         }
355
356         page1_flags = get_kpageflags(page1_flags & PFN_MASK);
357
358         /* Page 1 should be unevictable */
359         if ((page1_flags & UNEVICTABLE_BIT) == 0) {
360                 printf("Failed to make faulted page unevictable\n");
361                 return 1;
362         }
363
364         if (!is_vma_lock_on_fault((unsigned long)map)) {
365                 printf("VMA is not marked for lock on fault\n");
366                 return 1;
367         }
368
369         if (!is_vma_lock_on_fault((unsigned long)map + page_size)) {
370                 printf("VMA is not marked for lock on fault\n");
371                 return 1;
372         }
373
374         return 0;
375 }
376
377 static int unlock_onfault_check(char *map)
378 {
379         unsigned long page_size = getpagesize();
380         uint64_t page1_flags;
381
382         page1_flags = get_pageflags((unsigned long)map);
383         page1_flags = get_kpageflags(page1_flags & PFN_MASK);
384
385         if (page1_flags & UNEVICTABLE_BIT) {
386                 printf("Page 1 is still marked unevictable after unlock\n");
387                 return 1;
388         }
389
390         if (is_vma_lock_on_fault((unsigned long)map) ||
391             is_vma_lock_on_fault((unsigned long)map + page_size)) {
392                 printf("VMA is still lock on fault after unlock\n");
393                 return 1;
394         }
395
396         return 0;
397 }
398
399 static int test_mlock_onfault()
400 {
401         char *map;
402         int ret = 1;
403         unsigned long page_size = getpagesize();
404
405         map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
406                    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
407         if (map == MAP_FAILED) {
408                 perror("test_mlock_locked mmap");
409                 goto out;
410         }
411
412         if (mlock2_(map, 2 * page_size, MLOCK_ONFAULT)) {
413                 if (errno == ENOSYS) {
414                         printf("Cannot call new mlock family, skipping test\n");
415                         _exit(0);
416                 }
417                 perror("mlock2(MLOCK_ONFAULT)");
418                 goto unmap;
419         }
420
421         if (onfault_check(map))
422                 goto unmap;
423
424         /* Now unlock and recheck attributes */
425         if (munlock(map, 2 * page_size)) {
426                 if (errno == ENOSYS) {
427                         printf("Cannot call new mlock family, skipping test\n");
428                         _exit(0);
429                 }
430                 perror("munlock()");
431                 goto unmap;
432         }
433
434         ret = unlock_onfault_check(map);
435 unmap:
436         munmap(map, 2 * page_size);
437 out:
438         return ret;
439 }
440
441 static int test_lock_onfault_of_present()
442 {
443         char *map;
444         int ret = 1;
445         unsigned long page_size = getpagesize();
446         uint64_t page1_flags, page2_flags;
447
448         map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
449                    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
450         if (map == MAP_FAILED) {
451                 perror("test_mlock_locked mmap");
452                 goto out;
453         }
454
455         *map = 'a';
456
457         if (mlock2_(map, 2 * page_size, MLOCK_ONFAULT)) {
458                 if (errno == ENOSYS) {
459                         printf("Cannot call new mlock family, skipping test\n");
460                         _exit(0);
461                 }
462                 perror("mlock2(MLOCK_ONFAULT)");
463                 goto unmap;
464         }
465
466         page1_flags = get_pageflags((unsigned long)map);
467         page2_flags = get_pageflags((unsigned long)map + page_size);
468         page1_flags = get_kpageflags(page1_flags & PFN_MASK);
469         page2_flags = get_kpageflags(page2_flags & PFN_MASK);
470
471         /* Page 1 should be unevictable */
472         if ((page1_flags & UNEVICTABLE_BIT) == 0) {
473                 printf("Failed to make present page unevictable\n");
474                 goto unmap;
475         }
476
477         if (!is_vma_lock_on_fault((unsigned long)map) ||
478             !is_vma_lock_on_fault((unsigned long)map + page_size)) {
479                 printf("VMA with present pages is not marked lock on fault\n");
480                 goto unmap;
481         }
482         ret = 0;
483 unmap:
484         munmap(map, 2 * page_size);
485 out:
486         return ret;
487 }
488
489 static int test_munlockall()
490 {
491         char *map;
492         int ret = 1;
493         unsigned long page_size = getpagesize();
494
495         map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
496                    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
497
498         if (map == MAP_FAILED) {
499                 perror("test_munlockall mmap");
500                 goto out;
501         }
502
503         if (mlockall(MCL_CURRENT)) {
504                 perror("mlockall(MCL_CURRENT)");
505                 goto out;
506         }
507
508         if (lock_check(map))
509                 goto unmap;
510
511         if (munlockall()) {
512                 perror("munlockall()");
513                 goto unmap;
514         }
515
516         if (unlock_lock_check(map))
517                 goto unmap;
518
519         munmap(map, 2 * page_size);
520
521         map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
522                    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
523
524         if (map == MAP_FAILED) {
525                 perror("test_munlockall second mmap");
526                 goto out;
527         }
528
529         if (mlockall(MCL_CURRENT | MCL_ONFAULT)) {
530                 perror("mlockall(MCL_CURRENT | MCL_ONFAULT)");
531                 goto unmap;
532         }
533
534         if (onfault_check(map))
535                 goto unmap;
536
537         if (munlockall()) {
538                 perror("munlockall()");
539                 goto unmap;
540         }
541
542         if (unlock_onfault_check(map))
543                 goto unmap;
544
545         if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
546                 perror("mlockall(MCL_CURRENT | MCL_FUTURE)");
547                 goto out;
548         }
549
550         if (lock_check(map))
551                 goto unmap;
552
553         if (munlockall()) {
554                 perror("munlockall()");
555                 goto unmap;
556         }
557
558         ret = unlock_lock_check(map);
559
560 unmap:
561         munmap(map, 2 * page_size);
562 out:
563         munlockall();
564         return ret;
565 }
566
567 static int test_vma_management(bool call_mlock)
568 {
569         int ret = 1;
570         void *map;
571         unsigned long page_size = getpagesize();
572         struct vm_boundaries page1;
573         struct vm_boundaries page2;
574         struct vm_boundaries page3;
575
576         map = mmap(NULL, 3 * page_size, PROT_READ | PROT_WRITE,
577                    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
578         if (map == MAP_FAILED) {
579                 perror("mmap()");
580                 return ret;
581         }
582
583         if (call_mlock && mlock2_(map, 3 * page_size, MLOCK_ONFAULT)) {
584                 if (errno == ENOSYS) {
585                         printf("Cannot call new mlock family, skipping test\n");
586                         _exit(0);
587                 }
588                 perror("mlock(ONFAULT)\n");
589                 goto out;
590         }
591
592         if (get_vm_area((unsigned long)map, &page1) ||
593             get_vm_area((unsigned long)map + page_size, &page2) ||
594             get_vm_area((unsigned long)map + page_size * 2, &page3)) {
595                 printf("couldn't find mapping in /proc/self/maps\n");
596                 goto out;
597         }
598
599         /*
600          * Before we unlock a portion, we need to that all three pages are in
601          * the same VMA.  If they are not we abort this test (Note that this is
602          * not a failure)
603          */
604         if (page1.start != page2.start || page2.start != page3.start) {
605                 printf("VMAs are not merged to start, aborting test\n");
606                 ret = 0;
607                 goto out;
608         }
609
610         if (munlock(map + page_size, page_size)) {
611                 perror("munlock()");
612                 goto out;
613         }
614
615         if (get_vm_area((unsigned long)map, &page1) ||
616             get_vm_area((unsigned long)map + page_size, &page2) ||
617             get_vm_area((unsigned long)map + page_size * 2, &page3)) {
618                 printf("couldn't find mapping in /proc/self/maps\n");
619                 goto out;
620         }
621
622         /* All three VMAs should be different */
623         if (page1.start == page2.start || page2.start == page3.start) {
624                 printf("failed to split VMA for munlock\n");
625                 goto out;
626         }
627
628         /* Now unlock the first and third page and check the VMAs again */
629         if (munlock(map, page_size * 3)) {
630                 perror("munlock()");
631                 goto out;
632         }
633
634         if (get_vm_area((unsigned long)map, &page1) ||
635             get_vm_area((unsigned long)map + page_size, &page2) ||
636             get_vm_area((unsigned long)map + page_size * 2, &page3)) {
637                 printf("couldn't find mapping in /proc/self/maps\n");
638                 goto out;
639         }
640
641         /* Now all three VMAs should be the same */
642         if (page1.start != page2.start || page2.start != page3.start) {
643                 printf("failed to merge VMAs after munlock\n");
644                 goto out;
645         }
646
647         ret = 0;
648 out:
649         munmap(map, 3 * page_size);
650         return ret;
651 }
652
653 static int test_mlockall(int (test_function)(bool call_mlock))
654 {
655         int ret = 1;
656
657         if (mlockall(MCL_CURRENT | MCL_ONFAULT | MCL_FUTURE)) {
658                 perror("mlockall");
659                 return ret;
660         }
661
662         ret = test_function(false);
663         munlockall();
664         return ret;
665 }
666
667 int main(int argc, char **argv)
668 {
669         int ret = 0;
670         ret += test_mlock_lock();
671         ret += test_mlock_onfault();
672         ret += test_munlockall();
673         ret += test_lock_onfault_of_present();
674         ret += test_vma_management(true);
675         ret += test_mlockall(test_vma_management);
676         return ret;
677 }