1 // SPDX-License-Identifier: GPL-2.0
4 #include <linux/limits.h>
10 #include "../kselftest.h"
11 #include "cgroup_util.h"
13 #define ADDR ((void *)(0x0UL))
14 #define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
15 /* mapping 8 MBs == 4 hugepages */
16 #define LENGTH (8UL*1024*1024)
17 #define PROTECTION (PROT_READ | PROT_WRITE)
19 /* borrowed from mm/hmm-tests.c */
20 static long get_hugepage_size(void)
25 char *p
, *q
, *path
= "/proc/meminfo", *tag
= "Hugepagesize:";
28 fd
= open(path
, O_RDONLY
);
30 /* Error opening the file */
34 len
= read(fd
, buf
, sizeof(buf
));
37 /* Error in reading the file */
40 if (len
== sizeof(buf
)) {
41 /* Error file is too large */
46 /* Search for a tag if provided */
50 return -1; /* looks like the line we want isn't there */
55 val
= strtol(p
, &q
, 0);
57 /* Error parsing the file */
64 static int set_file(const char *path
, long value
)
69 file
= fopen(path
, "w");
72 ret
= fprintf(file
, "%ld\n", value
);
77 static int set_nr_hugepages(long value
)
79 return set_file("/proc/sys/vm/nr_hugepages", value
);
82 static unsigned int check_first(char *addr
)
84 return *(unsigned int *)addr
;
87 static void write_data(char *addr
)
91 for (i
= 0; i
< LENGTH
; i
++)
92 *(addr
+ i
) = (char)i
;
95 static int hugetlb_test_program(const char *cgroup
, void *arg
)
97 char *test_group
= (char *)arg
;
99 long old_current
, expected_current
, current
;
100 int ret
= EXIT_FAILURE
;
102 old_current
= cg_read_long(test_group
, "memory.current");
103 set_nr_hugepages(20);
104 current
= cg_read_long(test_group
, "memory.current");
105 if (current
- old_current
>= MB(2)) {
107 "setting nr_hugepages should not increase hugepage usage.\n");
108 ksft_print_msg("before: %ld, after: %ld\n", old_current
, current
);
112 addr
= mmap(ADDR
, LENGTH
, PROTECTION
, FLAGS
, 0, 0);
113 if (addr
== MAP_FAILED
) {
114 ksft_print_msg("fail to mmap.\n");
117 current
= cg_read_long(test_group
, "memory.current");
118 if (current
- old_current
>= MB(2)) {
119 ksft_print_msg("mmap should not increase hugepage usage.\n");
120 ksft_print_msg("before: %ld, after: %ld\n", old_current
, current
);
121 goto out_failed_munmap
;
123 old_current
= current
;
125 /* read the first page */
127 expected_current
= old_current
+ MB(2);
128 current
= cg_read_long(test_group
, "memory.current");
129 if (!values_close(expected_current
, current
, 5)) {
130 ksft_print_msg("memory usage should increase by around 2MB.\n");
132 "expected memory: %ld, actual memory: %ld\n",
133 expected_current
, current
);
134 goto out_failed_munmap
;
137 /* write to the whole range */
139 current
= cg_read_long(test_group
, "memory.current");
140 expected_current
= old_current
+ MB(8);
141 if (!values_close(expected_current
, current
, 5)) {
142 ksft_print_msg("memory usage should increase by around 8MB.\n");
144 "expected memory: %ld, actual memory: %ld\n",
145 expected_current
, current
);
146 goto out_failed_munmap
;
149 /* unmap the whole range */
150 munmap(addr
, LENGTH
);
151 current
= cg_read_long(test_group
, "memory.current");
152 expected_current
= old_current
;
153 if (!values_close(expected_current
, current
, 5)) {
154 ksft_print_msg("memory usage should go back down.\n");
156 "expected memory: %ld, actual memory: %ld\n",
157 expected_current
, current
);
165 munmap(addr
, LENGTH
);
169 static int test_hugetlb_memcg(char *root
)
174 test_group
= cg_name(root
, "hugetlb_memcg_test");
175 if (!test_group
|| cg_create(test_group
)) {
176 ksft_print_msg("fail to create cgroup.\n");
180 if (cg_write(test_group
, "memory.max", "100M")) {
181 ksft_print_msg("fail to set cgroup memory limit.\n");
186 if (cg_write(test_group
, "memory.swap.max", "0")) {
187 ksft_print_msg("fail to disable swap.\n");
191 if (!cg_run(test_group
, hugetlb_test_program
, (void *)test_group
))
194 cg_destroy(test_group
);
199 int main(int argc
, char **argv
)
202 int ret
= EXIT_SUCCESS
, has_memory_hugetlb_acc
;
204 has_memory_hugetlb_acc
= proc_mount_contains("memory_hugetlb_accounting");
205 if (has_memory_hugetlb_acc
< 0)
206 ksft_exit_skip("Failed to query cgroup mount option\n");
207 else if (!has_memory_hugetlb_acc
)
208 ksft_exit_skip("memory hugetlb accounting is disabled\n");
211 if (get_hugepage_size() != 2048) {
212 ksft_print_msg("test_hugetlb_memcg requires 2MB hugepages\n");
213 ksft_test_result_skip("test_hugetlb_memcg\n");
217 if (cg_find_unified_root(root
, sizeof(root
), NULL
))
218 ksft_exit_skip("cgroup v2 isn't mounted\n");
220 switch (test_hugetlb_memcg(root
)) {
222 ksft_test_result_pass("test_hugetlb_memcg\n");
225 ksft_test_result_skip("test_hugetlb_memcg\n");
229 ksft_test_result_fail("test_hugetlb_memcg\n");