1212
1313#define ADDR ((void *)(0x0UL))
1414#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
15- /* mapping 8 MBs == 4 hugepages */
16- #define LENGTH (8UL*1024*1024)
1715#define PROTECTION (PROT_READ | PROT_WRITE)
1816
17+ /*
18+ * This value matches the kernel's MEMCG_CHARGE_BATCH definition:
19+ * see include/linux/memcontrol.h. If the kernel value changes, this
20+ * test constant must be updated accordingly to stay consistent.
21+ */
22+ #define MEMCG_CHARGE_BATCH 64U
23+
1924/* borrowed from mm/hmm-tests.c */
2025static long get_hugepage_size (void )
2126{
@@ -84,38 +89,43 @@ static unsigned int check_first(char *addr)
8489 return * (unsigned int * )addr ;
8590}
8691
87- static void write_data (char * addr )
92+ static void write_data (char * addr , size_t length )
8893{
8994 unsigned long i ;
9095
91- for (i = 0 ; i < LENGTH ; i ++ )
96+ for (i = 0 ; i < length ; i ++ )
9297 * (addr + i ) = (char )i ;
9398}
9499
95100static int hugetlb_test_program (const char * cgroup , void * arg )
96101{
97102 char * test_group = (char * )arg ;
98103 void * addr ;
104+ long hpage_size = get_hugepage_size () * 1024 ;
99105 long old_current , expected_current , current ;
100106 int ret = EXIT_FAILURE ;
107+ size_t length = 4 * hpage_size ;
108+ int pagesize , nr_pages ;
109+
110+ pagesize = getpagesize ();
101111
102112 old_current = cg_read_long (test_group , "memory.current" );
103113 set_nr_hugepages (20 );
104114 current = cg_read_long (test_group , "memory.current" );
105- if (current - old_current >= MB ( 2 ) ) {
115+ if (current - old_current >= hpage_size ) {
106116 ksft_print_msg (
107117 "setting nr_hugepages should not increase hugepage usage.\n" );
108118 ksft_print_msg ("before: %ld, after: %ld\n" , old_current , current );
109119 return EXIT_FAILURE ;
110120 }
111121
112- addr = mmap (ADDR , LENGTH , PROTECTION , FLAGS , 0 , 0 );
122+ addr = mmap (ADDR , length , PROTECTION , FLAGS , 0 , 0 );
113123 if (addr == MAP_FAILED ) {
114124 ksft_print_msg ("fail to mmap.\n" );
115125 return EXIT_FAILURE ;
116126 }
117127 current = cg_read_long (test_group , "memory.current" );
118- if (current - old_current >= MB ( 2 ) ) {
128+ if (current - old_current >= hpage_size ) {
119129 ksft_print_msg ("mmap should not increase hugepage usage.\n" );
120130 ksft_print_msg ("before: %ld, after: %ld\n" , old_current , current );
121131 goto out_failed_munmap ;
@@ -124,30 +134,44 @@ static int hugetlb_test_program(const char *cgroup, void *arg)
124134
125135 /* read the first page */
126136 check_first (addr );
127- expected_current = old_current + MB (2 );
137+ nr_pages = hpage_size / pagesize ;
138+ expected_current = old_current + hpage_size ;
128139 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" );
140+ if (nr_pages < MEMCG_CHARGE_BATCH && current == old_current ) {
141+ /*
142+ * Memory cgroup charging uses per-CPU stocks and batched updates to the
143+ * memcg usage counters. For hugetlb allocations, the number of pages
144+ * that memcg charges is expressed in base pages (nr_pages), not
145+ * in hugepage units. When the charge for an allocation is smaller than
146+ * the internal batching threshold (nr_pages < MEMCG_CHARGE_BATCH),
147+ * it may be fully satisfied from the CPU’s local stock. In such
148+ * cases memory.current does not necessarily
149+ * increase.
150+ * Therefore, Treat a zero delta as valid behaviour here.
151+ */
152+ ksft_print_msg ("no visible memcg charge, allocation consumed from local stock.\n" );
153+ } else if (!values_close (expected_current , current , 5 )) {
154+ ksft_print_msg ("memory usage should increase by ~1 huge page.\n" );
131155 ksft_print_msg (
132156 "expected memory: %ld, actual memory: %ld\n" ,
133157 expected_current , current );
134158 goto out_failed_munmap ;
135159 }
136160
137161 /* write to the whole range */
138- write_data (addr );
162+ write_data (addr , length );
139163 current = cg_read_long (test_group , "memory.current" );
140- expected_current = old_current + MB ( 8 ) ;
164+ expected_current = old_current + length ;
141165 if (!values_close (expected_current , current , 5 )) {
142- ksft_print_msg ("memory usage should increase by around 8MB .\n" );
166+ ksft_print_msg ("memory usage should increase by around 4 huge pages .\n" );
143167 ksft_print_msg (
144168 "expected memory: %ld, actual memory: %ld\n" ,
145169 expected_current , current );
146170 goto out_failed_munmap ;
147171 }
148172
149173 /* unmap the whole range */
150- munmap (addr , LENGTH );
174+ munmap (addr , length );
151175 current = cg_read_long (test_group , "memory.current" );
152176 expected_current = old_current ;
153177 if (!values_close (expected_current , current , 5 )) {
@@ -162,13 +186,15 @@ static int hugetlb_test_program(const char *cgroup, void *arg)
162186 return ret ;
163187
164188out_failed_munmap :
165- munmap (addr , LENGTH );
189+ munmap (addr , length );
166190 return ret ;
167191}
168192
169193static int test_hugetlb_memcg (char * root )
170194{
171195 int ret = KSFT_FAIL ;
196+ int num_pages = 20 ;
197+ long hpage_size = get_hugepage_size ();
172198 char * test_group ;
173199
174200 test_group = cg_name (root , "hugetlb_memcg_test" );
@@ -177,7 +203,7 @@ static int test_hugetlb_memcg(char *root)
177203 goto out ;
178204 }
179205
180- if (cg_write (test_group , "memory.max" , "100M" )) {
206+ if (cg_write_numeric (test_group , "memory.max" , num_pages * hpage_size * 1024 )) {
181207 ksft_print_msg ("fail to set cgroup memory limit.\n" );
182208 goto out ;
183209 }
@@ -200,6 +226,7 @@ int main(int argc, char **argv)
200226{
201227 char root [PATH_MAX ];
202228 int ret = EXIT_SUCCESS , has_memory_hugetlb_acc ;
229+ long val ;
203230
204231 has_memory_hugetlb_acc = proc_mount_contains ("memory_hugetlb_accounting" );
205232 if (has_memory_hugetlb_acc < 0 )
@@ -208,12 +235,15 @@ int main(int argc, char **argv)
208235 ksft_exit_skip ("memory hugetlb accounting is disabled\n" );
209236
210237 /* Unit is kB! */
211- if (get_hugepage_size () != 2048 ) {
212- ksft_print_msg ("test_hugetlb_memcg requires 2MB hugepages\n" );
238+ val = get_hugepage_size ();
239+ if (val < 0 ) {
240+ ksft_print_msg ("Failed to read hugepage size\n" );
213241 ksft_test_result_skip ("test_hugetlb_memcg\n" );
214242 return ret ;
215243 }
216244
245+ ksft_print_msg ("Hugepage size: %ld kB\n" , val );
246+
217247 if (cg_find_unified_root (root , sizeof (root ), NULL ))
218248 ksft_exit_skip ("cgroup v2 isn't mounted\n" );
219249
0 commit comments