Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0
3
4set -e
5
6if [[ $(id -u) -ne 0 ]]; then
7 echo "This test must be run as root. Skipping..."
8 exit 0
9fi
10
11fault_limit_file=limit_in_bytes
12reservation_limit_file=rsvd.limit_in_bytes
13fault_usage_file=usage_in_bytes
14reservation_usage_file=rsvd.usage_in_bytes
15
16if [[ "$1" == "-cgroup-v2" ]]; then
17 cgroup2=1
18 fault_limit_file=max
19 reservation_limit_file=rsvd.max
20 fault_usage_file=current
21 reservation_usage_file=rsvd.current
22fi
23
24cgroup_path=/dev/cgroup/memory
25if [[ ! -e $cgroup_path ]]; then
26 mkdir -p $cgroup_path
27 if [[ $cgroup2 ]]; then
28 mount -t cgroup2 none $cgroup_path
29 else
30 mount -t cgroup memory,hugetlb $cgroup_path
31 fi
32fi
33
34if [[ $cgroup2 ]]; then
35 echo "+hugetlb" >/dev/cgroup/memory/cgroup.subtree_control
36fi
37
38function cleanup() {
39 if [[ $cgroup2 ]]; then
40 echo $$ >$cgroup_path/cgroup.procs
41 else
42 echo $$ >$cgroup_path/tasks
43 fi
44
45 if [[ -e /mnt/huge ]]; then
46 rm -rf /mnt/huge/*
47 umount /mnt/huge || echo error
48 rmdir /mnt/huge
49 fi
50 if [[ -e $cgroup_path/hugetlb_cgroup_test ]]; then
51 rmdir $cgroup_path/hugetlb_cgroup_test
52 fi
53 if [[ -e $cgroup_path/hugetlb_cgroup_test1 ]]; then
54 rmdir $cgroup_path/hugetlb_cgroup_test1
55 fi
56 if [[ -e $cgroup_path/hugetlb_cgroup_test2 ]]; then
57 rmdir $cgroup_path/hugetlb_cgroup_test2
58 fi
59 echo 0 >/proc/sys/vm/nr_hugepages
60 echo CLEANUP DONE
61}
62
63function expect_equal() {
64 local expected="$1"
65 local actual="$2"
66 local error="$3"
67
68 if [[ "$expected" != "$actual" ]]; then
69 echo "expected ($expected) != actual ($actual): $3"
70 cleanup
71 exit 1
72 fi
73}
74
75function get_machine_hugepage_size() {
76 hpz=$(grep -i hugepagesize /proc/meminfo)
77 kb=${hpz:14:-3}
78 mb=$(($kb / 1024))
79 echo $mb
80}
81
82MB=$(get_machine_hugepage_size)
83
84function setup_cgroup() {
85 local name="$1"
86 local cgroup_limit="$2"
87 local reservation_limit="$3"
88
89 mkdir $cgroup_path/$name
90
91 echo writing cgroup limit: "$cgroup_limit"
92 echo "$cgroup_limit" >$cgroup_path/$name/hugetlb.${MB}MB.$fault_limit_file
93
94 echo writing reseravation limit: "$reservation_limit"
95 echo "$reservation_limit" > \
96 $cgroup_path/$name/hugetlb.${MB}MB.$reservation_limit_file
97
98 if [ -e "$cgroup_path/$name/cpuset.cpus" ]; then
99 echo 0 >$cgroup_path/$name/cpuset.cpus
100 fi
101 if [ -e "$cgroup_path/$name/cpuset.mems" ]; then
102 echo 0 >$cgroup_path/$name/cpuset.mems
103 fi
104}
105
106function wait_for_hugetlb_memory_to_get_depleted() {
107 local cgroup="$1"
108 local path="/dev/cgroup/memory/$cgroup/hugetlb.${MB}MB.$reservation_usage_file"
109 # Wait for hugetlbfs memory to get depleted.
110 while [ $(cat $path) != 0 ]; do
111 echo Waiting for hugetlb memory to get depleted.
112 cat $path
113 sleep 0.5
114 done
115}
116
117function wait_for_hugetlb_memory_to_get_reserved() {
118 local cgroup="$1"
119 local size="$2"
120
121 local path="/dev/cgroup/memory/$cgroup/hugetlb.${MB}MB.$reservation_usage_file"
122 # Wait for hugetlbfs memory to get written.
123 while [ $(cat $path) != $size ]; do
124 echo Waiting for hugetlb memory reservation to reach size $size.
125 cat $path
126 sleep 0.5
127 done
128}
129
130function wait_for_hugetlb_memory_to_get_written() {
131 local cgroup="$1"
132 local size="$2"
133
134 local path="/dev/cgroup/memory/$cgroup/hugetlb.${MB}MB.$fault_usage_file"
135 # Wait for hugetlbfs memory to get written.
136 while [ $(cat $path) != $size ]; do
137 echo Waiting for hugetlb memory to reach size $size.
138 cat $path
139 sleep 0.5
140 done
141}
142
143function write_hugetlbfs_and_get_usage() {
144 local cgroup="$1"
145 local size="$2"
146 local populate="$3"
147 local write="$4"
148 local path="$5"
149 local method="$6"
150 local private="$7"
151 local expect_failure="$8"
152 local reserve="$9"
153
154 # Function return values.
155 reservation_failed=0
156 oom_killed=0
157 hugetlb_difference=0
158 reserved_difference=0
159
160 local hugetlb_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$fault_usage_file
161 local reserved_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file
162
163 local hugetlb_before=$(cat $hugetlb_usage)
164 local reserved_before=$(cat $reserved_usage)
165
166 echo
167 echo Starting:
168 echo hugetlb_usage="$hugetlb_before"
169 echo reserved_usage="$reserved_before"
170 echo expect_failure is "$expect_failure"
171
172 output=$(mktemp)
173 set +e
174 if [[ "$method" == "1" ]] || [[ "$method" == 2 ]] ||
175 [[ "$private" == "-r" ]] && [[ "$expect_failure" != 1 ]]; then
176
177 bash write_hugetlb_memory.sh "$size" "$populate" "$write" \
178 "$cgroup" "$path" "$method" "$private" "-l" "$reserve" 2>&1 | tee $output &
179
180 local write_result=$?
181 local write_pid=$!
182
183 until grep -q -i "DONE" $output; do
184 echo waiting for DONE signal.
185 if ! ps $write_pid > /dev/null
186 then
187 echo "FAIL: The write died"
188 cleanup
189 exit 1
190 fi
191 sleep 0.5
192 done
193
194 echo ================= write_hugetlb_memory.sh output is:
195 cat $output
196 echo ================= end output.
197
198 if [[ "$populate" == "-o" ]] || [[ "$write" == "-w" ]]; then
199 wait_for_hugetlb_memory_to_get_written "$cgroup" "$size"
200 elif [[ "$reserve" != "-n" ]]; then
201 wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size"
202 else
203 # This case doesn't produce visible effects, but we still have
204 # to wait for the async process to start and execute...
205 sleep 0.5
206 fi
207
208 echo write_result is $write_result
209 else
210 bash write_hugetlb_memory.sh "$size" "$populate" "$write" \
211 "$cgroup" "$path" "$method" "$private" "$reserve"
212 local write_result=$?
213
214 if [[ "$reserve" != "-n" ]]; then
215 wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size"
216 fi
217 fi
218 set -e
219
220 if [[ "$write_result" == 1 ]]; then
221 reservation_failed=1
222 fi
223
224 # On linus/master, the above process gets SIGBUS'd on oomkill, with
225 # return code 135. On earlier kernels, it gets actual oomkill, with return
226 # code 137, so just check for both conditions in case we're testing
227 # against an earlier kernel.
228 if [[ "$write_result" == 135 ]] || [[ "$write_result" == 137 ]]; then
229 oom_killed=1
230 fi
231
232 local hugetlb_after=$(cat $hugetlb_usage)
233 local reserved_after=$(cat $reserved_usage)
234
235 echo After write:
236 echo hugetlb_usage="$hugetlb_after"
237 echo reserved_usage="$reserved_after"
238
239 hugetlb_difference=$(($hugetlb_after - $hugetlb_before))
240 reserved_difference=$(($reserved_after - $reserved_before))
241}
242
243function cleanup_hugetlb_memory() {
244 set +e
245 local cgroup="$1"
246 if [[ "$(pgrep -f write_to_hugetlbfs)" != "" ]]; then
247 echo killing write_to_hugetlbfs
248 killall -2 write_to_hugetlbfs
249 wait_for_hugetlb_memory_to_get_depleted $cgroup
250 fi
251 set -e
252
253 if [[ -e /mnt/huge ]]; then
254 rm -rf /mnt/huge/*
255 umount /mnt/huge
256 rmdir /mnt/huge
257 fi
258}
259
260function run_test() {
261 local size=$(($1 * ${MB} * 1024 * 1024))
262 local populate="$2"
263 local write="$3"
264 local cgroup_limit=$(($4 * ${MB} * 1024 * 1024))
265 local reservation_limit=$(($5 * ${MB} * 1024 * 1024))
266 local nr_hugepages="$6"
267 local method="$7"
268 local private="$8"
269 local expect_failure="$9"
270 local reserve="${10}"
271
272 # Function return values.
273 hugetlb_difference=0
274 reserved_difference=0
275 reservation_failed=0
276 oom_killed=0
277
278 echo nr hugepages = "$nr_hugepages"
279 echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages
280
281 setup_cgroup "hugetlb_cgroup_test" "$cgroup_limit" "$reservation_limit"
282
283 mkdir -p /mnt/huge
284 mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge
285
286 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test" "$size" "$populate" \
287 "$write" "/mnt/huge/test" "$method" "$private" "$expect_failure" \
288 "$reserve"
289
290 cleanup_hugetlb_memory "hugetlb_cgroup_test"
291
292 local final_hugetlb=$(cat $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB}MB.$fault_usage_file)
293 local final_reservation=$(cat $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB}MB.$reservation_usage_file)
294
295 echo $hugetlb_difference
296 echo $reserved_difference
297 expect_equal "0" "$final_hugetlb" "final hugetlb is not zero"
298 expect_equal "0" "$final_reservation" "final reservation is not zero"
299}
300
301function run_multiple_cgroup_test() {
302 local size1="$1"
303 local populate1="$2"
304 local write1="$3"
305 local cgroup_limit1="$4"
306 local reservation_limit1="$5"
307
308 local size2="$6"
309 local populate2="$7"
310 local write2="$8"
311 local cgroup_limit2="$9"
312 local reservation_limit2="${10}"
313
314 local nr_hugepages="${11}"
315 local method="${12}"
316 local private="${13}"
317 local expect_failure="${14}"
318 local reserve="${15}"
319
320 # Function return values.
321 hugetlb_difference1=0
322 reserved_difference1=0
323 reservation_failed1=0
324 oom_killed1=0
325
326 hugetlb_difference2=0
327 reserved_difference2=0
328 reservation_failed2=0
329 oom_killed2=0
330
331 echo nr hugepages = "$nr_hugepages"
332 echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages
333
334 setup_cgroup "hugetlb_cgroup_test1" "$cgroup_limit1" "$reservation_limit1"
335 setup_cgroup "hugetlb_cgroup_test2" "$cgroup_limit2" "$reservation_limit2"
336
337 mkdir -p /mnt/huge
338 mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge
339
340 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test1" "$size1" \
341 "$populate1" "$write1" "/mnt/huge/test1" "$method" "$private" \
342 "$expect_failure" "$reserve"
343
344 hugetlb_difference1=$hugetlb_difference
345 reserved_difference1=$reserved_difference
346 reservation_failed1=$reservation_failed
347 oom_killed1=$oom_killed
348
349 local cgroup1_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$fault_usage_file
350 local cgroup1_reservation_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$reservation_usage_file
351 local cgroup2_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$fault_usage_file
352 local cgroup2_reservation_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$reservation_usage_file
353
354 local usage_before_second_write=$(cat $cgroup1_hugetlb_usage)
355 local reservation_usage_before_second_write=$(cat $cgroup1_reservation_usage)
356
357 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test2" "$size2" \
358 "$populate2" "$write2" "/mnt/huge/test2" "$method" "$private" \
359 "$expect_failure" "$reserve"
360
361 hugetlb_difference2=$hugetlb_difference
362 reserved_difference2=$reserved_difference
363 reservation_failed2=$reservation_failed
364 oom_killed2=$oom_killed
365
366 expect_equal "$usage_before_second_write" \
367 "$(cat $cgroup1_hugetlb_usage)" "Usage changed."
368 expect_equal "$reservation_usage_before_second_write" \
369 "$(cat $cgroup1_reservation_usage)" "Reservation usage changed."
370
371 cleanup_hugetlb_memory
372
373 local final_hugetlb=$(cat $cgroup1_hugetlb_usage)
374 local final_reservation=$(cat $cgroup1_reservation_usage)
375
376 expect_equal "0" "$final_hugetlb" \
377 "hugetlbt_cgroup_test1 final hugetlb is not zero"
378 expect_equal "0" "$final_reservation" \
379 "hugetlbt_cgroup_test1 final reservation is not zero"
380
381 local final_hugetlb=$(cat $cgroup2_hugetlb_usage)
382 local final_reservation=$(cat $cgroup2_reservation_usage)
383
384 expect_equal "0" "$final_hugetlb" \
385 "hugetlb_cgroup_test2 final hugetlb is not zero"
386 expect_equal "0" "$final_reservation" \
387 "hugetlb_cgroup_test2 final reservation is not zero"
388}
389
390cleanup
391
392for populate in "" "-o"; do
393 for method in 0 1 2; do
394 for private in "" "-r"; do
395 for reserve in "" "-n"; do
396
397 # Skip mmap(MAP_HUGETLB | MAP_SHARED). Doesn't seem to be supported.
398 if [[ "$method" == 1 ]] && [[ "$private" == "" ]]; then
399 continue
400 fi
401
402 # Skip populated shmem tests. Doesn't seem to be supported.
403 if [[ "$method" == 2"" ]] && [[ "$populate" == "-o" ]]; then
404 continue
405 fi
406
407 if [[ "$method" == 2"" ]] && [[ "$reserve" == "-n" ]]; then
408 continue
409 fi
410
411 cleanup
412 echo
413 echo
414 echo
415 echo Test normal case.
416 echo private=$private, populate=$populate, method=$method, reserve=$reserve
417 run_test 5 "$populate" "" 10 10 10 "$method" "$private" "0" "$reserve"
418
419 echo Memory charged to hugtlb=$hugetlb_difference
420 echo Memory charged to reservation=$reserved_difference
421
422 if [[ "$populate" == "-o" ]]; then
423 expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \
424 "Reserved memory charged to hugetlb cgroup."
425 else
426 expect_equal "0" "$hugetlb_difference" \
427 "Reserved memory charged to hugetlb cgroup."
428 fi
429
430 if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then
431 expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \
432 "Reserved memory not charged to reservation usage."
433 else
434 expect_equal "0" "$reserved_difference" \
435 "Reserved memory not charged to reservation usage."
436 fi
437
438 echo 'PASS'
439
440 cleanup
441 echo
442 echo
443 echo
444 echo Test normal case with write.
445 echo private=$private, populate=$populate, method=$method, reserve=$reserve
446 run_test 5 "$populate" '-w' 5 5 10 "$method" "$private" "0" "$reserve"
447
448 echo Memory charged to hugtlb=$hugetlb_difference
449 echo Memory charged to reservation=$reserved_difference
450
451 expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \
452 "Reserved memory charged to hugetlb cgroup."
453
454 expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \
455 "Reserved memory not charged to reservation usage."
456
457 echo 'PASS'
458
459 cleanup
460 continue
461 echo
462 echo
463 echo
464 echo Test more than reservation case.
465 echo private=$private, populate=$populate, method=$method, reserve=$reserve
466
467 if [ "$reserve" != "-n" ]; then
468 run_test "5" "$populate" '' "10" "2" "10" "$method" "$private" "1" \
469 "$reserve"
470
471 expect_equal "1" "$reservation_failed" "Reservation succeeded."
472 fi
473
474 echo 'PASS'
475
476 cleanup
477
478 echo
479 echo
480 echo
481 echo Test more than cgroup limit case.
482 echo private=$private, populate=$populate, method=$method, reserve=$reserve
483
484 # Not sure if shm memory can be cleaned up when the process gets sigbus'd.
485 if [[ "$method" != 2 ]]; then
486 run_test 5 "$populate" "-w" 2 10 10 "$method" "$private" "1" "$reserve"
487
488 expect_equal "1" "$oom_killed" "Not oom killed."
489 fi
490 echo 'PASS'
491
492 cleanup
493
494 echo
495 echo
496 echo
497 echo Test normal case, multiple cgroups.
498 echo private=$private, populate=$populate, method=$method, reserve=$reserve
499 run_multiple_cgroup_test "3" "$populate" "" "10" "10" "5" \
500 "$populate" "" "10" "10" "10" \
501 "$method" "$private" "0" "$reserve"
502
503 echo Memory charged to hugtlb1=$hugetlb_difference1
504 echo Memory charged to reservation1=$reserved_difference1
505 echo Memory charged to hugtlb2=$hugetlb_difference2
506 echo Memory charged to reservation2=$reserved_difference2
507
508 if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then
509 expect_equal "3" "$reserved_difference1" \
510 "Incorrect reservations charged to cgroup 1."
511
512 expect_equal "5" "$reserved_difference2" \
513 "Incorrect reservation charged to cgroup 2."
514
515 else
516 expect_equal "0" "$reserved_difference1" \
517 "Incorrect reservations charged to cgroup 1."
518
519 expect_equal "0" "$reserved_difference2" \
520 "Incorrect reservation charged to cgroup 2."
521 fi
522
523 if [[ "$populate" == "-o" ]]; then
524 expect_equal "3" "$hugetlb_difference1" \
525 "Incorrect hugetlb charged to cgroup 1."
526
527 expect_equal "5" "$hugetlb_difference2" \
528 "Incorrect hugetlb charged to cgroup 2."
529
530 else
531 expect_equal "0" "$hugetlb_difference1" \
532 "Incorrect hugetlb charged to cgroup 1."
533
534 expect_equal "0" "$hugetlb_difference2" \
535 "Incorrect hugetlb charged to cgroup 2."
536 fi
537 echo 'PASS'
538
539 cleanup
540 echo
541 echo
542 echo
543 echo Test normal case with write, multiple cgroups.
544 echo private=$private, populate=$populate, method=$method, reserve=$reserve
545 run_multiple_cgroup_test "3" "$populate" "-w" "10" "10" "5" \
546 "$populate" "-w" "10" "10" "10" \
547 "$method" "$private" "0" "$reserve"
548
549 echo Memory charged to hugtlb1=$hugetlb_difference1
550 echo Memory charged to reservation1=$reserved_difference1
551 echo Memory charged to hugtlb2=$hugetlb_difference2
552 echo Memory charged to reservation2=$reserved_difference2
553
554 expect_equal "3" "$hugetlb_difference1" \
555 "Incorrect hugetlb charged to cgroup 1."
556
557 expect_equal "3" "$reserved_difference1" \
558 "Incorrect reservation charged to cgroup 1."
559
560 expect_equal "5" "$hugetlb_difference2" \
561 "Incorrect hugetlb charged to cgroup 2."
562
563 expect_equal "5" "$reserved_difference2" \
564 "Incorrected reservation charged to cgroup 2."
565 echo 'PASS'
566
567 cleanup
568
569 done # reserve
570 done # private
571 done # populate
572done # method
573
574umount $cgroup_path
575rmdir $cgroup_path