1 // SPDX-License-Identifier: GPL-2.0
4 * A test for the patch "Allow compaction of unevictable pages".
5 * With this patch we should be able to allocate at least 1/4
6 * of RAM in huge pages. Without the patch much less is
13 #include <sys/resource.h>
19 #include "../kselftest.h"
21 #define MAP_SIZE_MB 100
22 #define MAP_SIZE (MAP_SIZE_MB * 1024 * 1024)
26 struct map_list
*next
;
29 int read_memory_info(unsigned long *memfree
, unsigned long *hugepagesize
)
31 char buffer
[256] = {0};
32 char *cmd
= "cat /proc/meminfo | grep -i memfree | grep -o '[0-9]*'";
33 FILE *cmdfile
= popen(cmd
, "r");
35 if (!(fgets(buffer
, sizeof(buffer
), cmdfile
))) {
36 ksft_print_msg("Failed to read meminfo: %s\n", strerror(errno
));
42 *memfree
= atoll(buffer
);
43 cmd
= "cat /proc/meminfo | grep -i hugepagesize | grep -o '[0-9]*'";
44 cmdfile
= popen(cmd
, "r");
46 if (!(fgets(buffer
, sizeof(buffer
), cmdfile
))) {
47 ksft_print_msg("Failed to read meminfo: %s\n", strerror(errno
));
52 *hugepagesize
= atoll(buffer
);
62 fd
= open("/proc/sys/vm/compact_unevictable_allowed",
63 O_RDONLY
| O_NONBLOCK
);
65 ksft_print_msg("Failed to open /proc/sys/vm/compact_unevictable_allowed: %s\n",
70 if (read(fd
, &allowed
, sizeof(char)) != sizeof(char)) {
71 ksft_print_msg("Failed to read from /proc/sys/vm/compact_unevictable_allowed: %s\n",
81 ksft_print_msg("Compaction isn't allowed\n");
85 int check_compaction(unsigned long mem_free
, unsigned long hugepage_size
,
86 unsigned long initial_nr_hugepages
)
88 unsigned long nr_hugepages_ul
;
90 int compaction_index
= 0;
91 char nr_hugepages
[20] = {0};
92 char init_nr_hugepages
[24] = {0};
94 snprintf(init_nr_hugepages
, sizeof(init_nr_hugepages
),
95 "%lu", initial_nr_hugepages
);
97 /* We want to test with 80% of available memory. Else, OOM killer comes
99 mem_free
= mem_free
* 0.8;
101 fd
= open("/proc/sys/vm/nr_hugepages", O_RDWR
| O_NONBLOCK
);
103 ksft_print_msg("Failed to open /proc/sys/vm/nr_hugepages: %s\n",
109 /* Request a large number of huge pages. The Kernel will allocate
111 if (write(fd
, "100000", (6*sizeof(char))) != (6*sizeof(char))) {
112 ksft_print_msg("Failed to write 100000 to /proc/sys/vm/nr_hugepages: %s\n",
117 lseek(fd
, 0, SEEK_SET
);
119 if (read(fd
, nr_hugepages
, sizeof(nr_hugepages
)) <= 0) {
120 ksft_print_msg("Failed to re-read from /proc/sys/vm/nr_hugepages: %s\n",
125 /* We should have been able to request at least 1/3 rd of the memory in
127 nr_hugepages_ul
= strtoul(nr_hugepages
, NULL
, 10);
128 if (!nr_hugepages_ul
) {
129 ksft_print_msg("ERROR: No memory is available as huge pages\n");
132 compaction_index
= mem_free
/(nr_hugepages_ul
* hugepage_size
);
134 lseek(fd
, 0, SEEK_SET
);
136 if (write(fd
, init_nr_hugepages
, strlen(init_nr_hugepages
))
137 != strlen(init_nr_hugepages
)) {
138 ksft_print_msg("Failed to write value to /proc/sys/vm/nr_hugepages: %s\n",
143 ksft_print_msg("Number of huge pages allocated = %lu\n",
146 if (compaction_index
> 3) {
147 ksft_print_msg("ERROR: Less than 1/%d of memory is available\n"
148 "as huge pages\n", compaction_index
);
157 ksft_test_result(ret
== 0, "check_compaction\n");
161 int set_zero_hugepages(unsigned long *initial_nr_hugepages
)
164 char nr_hugepages
[20] = {0};
166 fd
= open("/proc/sys/vm/nr_hugepages", O_RDWR
| O_NONBLOCK
);
168 ksft_print_msg("Failed to open /proc/sys/vm/nr_hugepages: %s\n",
172 if (read(fd
, nr_hugepages
, sizeof(nr_hugepages
)) <= 0) {
173 ksft_print_msg("Failed to read from /proc/sys/vm/nr_hugepages: %s\n",
178 lseek(fd
, 0, SEEK_SET
);
180 /* Start with the initial condition of 0 huge pages */
181 if (write(fd
, "0", sizeof(char)) != sizeof(char)) {
182 ksft_print_msg("Failed to write 0 to /proc/sys/vm/nr_hugepages: %s\n",
187 *initial_nr_hugepages
= strtoul(nr_hugepages
, NULL
, 10);
197 int main(int argc
, char **argv
)
200 struct map_list
*list
= NULL
, *entry
;
203 unsigned long mem_free
= 0;
204 unsigned long hugepage_size
= 0;
205 long mem_fragmentable_MB
= 0;
206 unsigned long initial_nr_hugepages
;
210 if (prereq() || geteuid())
211 ksft_exit_skip("Prerequisites unsatisfied\n");
215 /* Start the test without hugepages reducing mem_free */
216 if (set_zero_hugepages(&initial_nr_hugepages
))
219 lim
.rlim_cur
= RLIM_INFINITY
;
220 lim
.rlim_max
= RLIM_INFINITY
;
221 if (setrlimit(RLIMIT_MEMLOCK
, &lim
))
222 ksft_exit_fail_msg("Failed to set rlimit: %s\n", strerror(errno
));
224 page_size
= getpagesize();
226 if (read_memory_info(&mem_free
, &hugepage_size
) != 0)
227 ksft_exit_fail_msg("Failed to get meminfo\n");
229 mem_fragmentable_MB
= mem_free
* 0.8 / 1024;
231 while (mem_fragmentable_MB
> 0) {
232 map
= mmap(NULL
, MAP_SIZE
, PROT_READ
| PROT_WRITE
,
233 MAP_ANONYMOUS
| MAP_PRIVATE
| MAP_LOCKED
, -1, 0);
234 if (map
== MAP_FAILED
)
237 entry
= malloc(sizeof(struct map_list
));
239 munmap(map
, MAP_SIZE
);
246 /* Write something (in this case the address of the map) to
247 * ensure that KSM can't merge the mapped pages
249 for (i
= 0; i
< MAP_SIZE
; i
+= page_size
)
250 *(unsigned long *)(map
+ i
) = (unsigned long)map
+ i
;
252 mem_fragmentable_MB
-= MAP_SIZE_MB
;
255 for (entry
= list
; entry
!= NULL
; entry
= entry
->next
) {
256 munmap(entry
->map
, MAP_SIZE
);
262 if (check_compaction(mem_free
, hugepage_size
,
263 initial_nr_hugepages
) == 0)