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