xref: /linux/tools/testing/selftests/mm/hugetlb-mmap.c (revision 3d5e48944e824bddc20d7b874e784f7b279636fe)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * hugetlb-mmap:
4  *
5  * Example of using huge page memory in a user application using the mmap
6  * system call.  Before running this application, make sure that the
7  * administrator has mounted the hugetlbfs filesystem (on some directory
8  * like /mnt) using the command mount -t hugetlbfs nodev /mnt. In this
9  * example, the app is requesting memory of size 256MB that is backed by
10  * huge pages.
11  */
12 #define _GNU_SOURCE
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <sys/mman.h>
17 #include <fcntl.h>
18 #include <linux/memfd.h>
19 #include "vm_util.h"
20 #include "kselftest.h"
21 #include "hugepage_settings.h"
22 
23 #define LENGTH (256UL*1024*1024)
24 #define PROTECTION (PROT_READ | PROT_WRITE)
25 
26 static void check_bytes(char *addr)
27 {
28 	ksft_print_msg("First hex is %x\n", *((unsigned int *)addr));
29 }
30 
31 static void write_bytes(char *addr, size_t length)
32 {
33 	unsigned long i;
34 
35 	for (i = 0; i < length; i++)
36 		*(addr + i) = (char)i;
37 }
38 
39 static bool verify_bytes(char *addr, size_t length)
40 {
41 	unsigned long i;
42 
43 	check_bytes(addr);
44 	for (i = 0; i < length; i++)
45 		if (*(addr + i) != (char)i) {
46 			ksft_print_msg("Error: Mismatch at %lu(%p)\n", i, addr);
47 			return false;
48 		}
49 
50 	return true;
51 }
52 
53 static void test_mmap(size_t length, int mmap_flags, int fd,
54 		      const char *test_name)
55 {
56 	bool passed = true;
57 	void *addr;
58 
59 	addr = mmap(NULL, length, PROTECTION, mmap_flags, fd, 0);
60 	if (addr == MAP_FAILED)
61 		ksft_exit_fail_perror("mmap");
62 
63 	ksft_print_msg("Returned address is %p\n", addr);
64 	check_bytes(addr);
65 	write_bytes(addr, length);
66 	if (!verify_bytes(addr, length))
67 		passed = false;
68 
69 	/* munmap() length of MAP_HUGETLB memory must be hugepage aligned */
70 	if (munmap(addr, length))
71 		ksft_exit_fail_perror("munmap");
72 
73 	ksft_test_result(passed, "%s\n", test_name);
74 }
75 
76 static void test_anon_mmap(size_t length, int shift)
77 {
78 	const char *test_name = "hugetlb anonymous mmap";
79 	int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB;
80 
81 	if (shift)
82 		mmap_flags |= (shift & MAP_HUGE_MASK) << MAP_HUGE_SHIFT;
83 
84 	test_mmap(length, mmap_flags, -1, test_name);
85 }
86 
87 static void test_file_mmap(size_t length, int shift)
88 {
89 	const char *test_name = "hugetlb file mmap";
90 	int mfd_flags = MFD_HUGETLB;
91 	int fd;
92 
93 	if (shift)
94 		mfd_flags |= (shift & MFD_HUGE_MASK) << MFD_HUGE_SHIFT;
95 
96 	fd = memfd_create("hugetlb-mmap", mfd_flags);
97 	if (fd < 0)
98 		ksft_exit_fail_perror("memfd_create");
99 
100 	test_mmap(length, MAP_SHARED, fd, test_name);
101 	close(fd);
102 }
103 
104 int main(int argc, char **argv)
105 {
106 	size_t hugepage_size;
107 	size_t length = LENGTH;
108 	int shift = 0, nr;
109 
110 	ksft_print_header();
111 
112 	if (argc > 1)
113 		length = atol(argv[1]) << 20;
114 	if (argc > 2)
115 		shift = atoi(argv[2]);
116 
117 	hugetlb_save_settings();
118 	if (shift) {
119 		hugepage_size = (1UL << shift);
120 		ksft_print_msg("%lu kB hugepages\n", 1UL << (shift - 10));
121 	} else {
122 		hugepage_size = default_huge_page_size();
123 		if (!hugepage_size)
124 			ksft_exit_skip("Could not detect default hugetlb page size.");
125 		ksft_print_msg("Default size hugepages (%lu kB)\n", hugepage_size >> 10);
126 	}
127 
128 	/* munmap will fail if the length is not page aligned */
129 	length = (length + hugepage_size - 1) & ~(hugepage_size - 1);
130 	nr = length / hugepage_size;
131 
132 	hugetlb_set_nr_pages(hugepage_size, nr);
133 	if (hugetlb_free_pages(hugepage_size) < nr)
134 		ksft_exit_skip("Not enough %lu Kb pages\n", hugepage_size >> 10);
135 
136 	ksft_set_plan(2);
137 	ksft_print_msg("Mapping %lu Mbytes\n", (unsigned long)length >> 20);
138 
139 	test_anon_mmap(length, shift);
140 	test_file_mmap(length, shift);
141 
142 	ksft_finished();
143 }
144