1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# Kselftest framework requirement - SKIP code is 4.
5ksft_skip=4
6
7set -e
8
9if [[ $(id -u) -ne 0 ]]; then
10  echo "This test must be run as root. Skipping..."
11  exit $ksft_skip
12fi
13
14usage_file=usage_in_bytes
15
16if [[ "$1" == "-cgroup-v2" ]]; then
17  cgroup2=1
18  usage_file=current
19fi
20
21
22if [[ $cgroup2 ]]; then
23  CGROUP_ROOT=$(mount -t cgroup2 | head -1 | awk -e '{print $3}')
24  if [[ -z "$CGROUP_ROOT" ]]; then
25    CGROUP_ROOT=/dev/cgroup/memory
26    mount -t cgroup2 none $CGROUP_ROOT
27    do_umount=1
28  fi
29  echo "+hugetlb +memory" >$CGROUP_ROOT/cgroup.subtree_control
30else
31  CGROUP_ROOT=$(mount -t cgroup | grep ",hugetlb" | awk -e '{print $3}')
32  if [[ -z "$CGROUP_ROOT" ]]; then
33    CGROUP_ROOT=/dev/cgroup/memory
34    mount -t cgroup memory,hugetlb $CGROUP_ROOT
35    do_umount=1
36  fi
37fi
38MNT='/mnt/huge/'
39
40function get_machine_hugepage_size() {
41  hpz=$(grep -i hugepagesize /proc/meminfo)
42  kb=${hpz:14:-3}
43  mb=$(($kb / 1024))
44  echo $mb
45}
46
47MB=$(get_machine_hugepage_size)
48
49function cleanup() {
50  echo cleanup
51  set +e
52  rm -rf "$MNT"/* 2>/dev/null
53  umount "$MNT" 2>/dev/null
54  rmdir "$MNT" 2>/dev/null
55  rmdir "$CGROUP_ROOT"/a/b 2>/dev/null
56  rmdir "$CGROUP_ROOT"/a 2>/dev/null
57  rmdir "$CGROUP_ROOT"/test1 2>/dev/null
58  echo 0 >/proc/sys/vm/nr_hugepages
59  set -e
60}
61
62function assert_state() {
63  local expected_a="$1"
64  local expected_a_hugetlb="$2"
65  local expected_b=""
66  local expected_b_hugetlb=""
67
68  if [ ! -z ${3:-} ] && [ ! -z ${4:-} ]; then
69    expected_b="$3"
70    expected_b_hugetlb="$4"
71  fi
72  local tolerance=$((5 * 1024 * 1024))
73
74  local actual_a
75  actual_a="$(cat "$CGROUP_ROOT"/a/memory.$usage_file)"
76  if [[ $actual_a -lt $(($expected_a - $tolerance)) ]] ||
77    [[ $actual_a -gt $(($expected_a + $tolerance)) ]]; then
78    echo actual a = $((${actual_a%% *} / 1024 / 1024)) MB
79    echo expected a = $((${expected_a%% *} / 1024 / 1024)) MB
80    echo fail
81
82    cleanup
83    exit 1
84  fi
85
86  local actual_a_hugetlb
87  actual_a_hugetlb="$(cat "$CGROUP_ROOT"/a/hugetlb.${MB}MB.$usage_file)"
88  if [[ $actual_a_hugetlb -lt $(($expected_a_hugetlb - $tolerance)) ]] ||
89    [[ $actual_a_hugetlb -gt $(($expected_a_hugetlb + $tolerance)) ]]; then
90    echo actual a hugetlb = $((${actual_a_hugetlb%% *} / 1024 / 1024)) MB
91    echo expected a hugetlb = $((${expected_a_hugetlb%% *} / 1024 / 1024)) MB
92    echo fail
93
94    cleanup
95    exit 1
96  fi
97
98  if [[ -z "$expected_b" || -z "$expected_b_hugetlb" ]]; then
99    return
100  fi
101
102  local actual_b
103  actual_b="$(cat "$CGROUP_ROOT"/a/b/memory.$usage_file)"
104  if [[ $actual_b -lt $(($expected_b - $tolerance)) ]] ||
105    [[ $actual_b -gt $(($expected_b + $tolerance)) ]]; then
106    echo actual b = $((${actual_b%% *} / 1024 / 1024)) MB
107    echo expected b = $((${expected_b%% *} / 1024 / 1024)) MB
108    echo fail
109
110    cleanup
111    exit 1
112  fi
113
114  local actual_b_hugetlb
115  actual_b_hugetlb="$(cat "$CGROUP_ROOT"/a/b/hugetlb.${MB}MB.$usage_file)"
116  if [[ $actual_b_hugetlb -lt $(($expected_b_hugetlb - $tolerance)) ]] ||
117    [[ $actual_b_hugetlb -gt $(($expected_b_hugetlb + $tolerance)) ]]; then
118    echo actual b hugetlb = $((${actual_b_hugetlb%% *} / 1024 / 1024)) MB
119    echo expected b hugetlb = $((${expected_b_hugetlb%% *} / 1024 / 1024)) MB
120    echo fail
121
122    cleanup
123    exit 1
124  fi
125}
126
127function setup() {
128  echo 100 >/proc/sys/vm/nr_hugepages
129  mkdir "$CGROUP_ROOT"/a
130  sleep 1
131  if [[ $cgroup2 ]]; then
132    echo "+hugetlb +memory" >$CGROUP_ROOT/a/cgroup.subtree_control
133  else
134    echo 0 >$CGROUP_ROOT/a/cpuset.mems
135    echo 0 >$CGROUP_ROOT/a/cpuset.cpus
136  fi
137
138  mkdir "$CGROUP_ROOT"/a/b
139
140  if [[ ! $cgroup2 ]]; then
141    echo 0 >$CGROUP_ROOT/a/b/cpuset.mems
142    echo 0 >$CGROUP_ROOT/a/b/cpuset.cpus
143  fi
144
145  mkdir -p "$MNT"
146  mount -t hugetlbfs none "$MNT"
147}
148
149write_hugetlbfs() {
150  local cgroup="$1"
151  local path="$2"
152  local size="$3"
153
154  if [[ $cgroup2 ]]; then
155    echo $$ >$CGROUP_ROOT/$cgroup/cgroup.procs
156  else
157    echo 0 >$CGROUP_ROOT/$cgroup/cpuset.mems
158    echo 0 >$CGROUP_ROOT/$cgroup/cpuset.cpus
159    echo $$ >"$CGROUP_ROOT/$cgroup/tasks"
160  fi
161  ./write_to_hugetlbfs -p "$path" -s "$size" -m 0 -o
162  if [[ $cgroup2 ]]; then
163    echo $$ >$CGROUP_ROOT/cgroup.procs
164  else
165    echo $$ >"$CGROUP_ROOT/tasks"
166  fi
167  echo
168}
169
170set -e
171
172size=$((${MB} * 1024 * 1024 * 25)) # 50MB = 25 * 2MB hugepages.
173
174cleanup
175
176echo
177echo
178echo Test charge, rmdir, uncharge
179setup
180echo mkdir
181mkdir $CGROUP_ROOT/test1
182
183echo write
184write_hugetlbfs test1 "$MNT"/test $size
185
186echo rmdir
187rmdir $CGROUP_ROOT/test1
188mkdir $CGROUP_ROOT/test1
189
190echo uncharge
191rm -rf /mnt/huge/*
192
193cleanup
194
195echo done
196echo
197echo
198if [[ ! $cgroup2 ]]; then
199  echo "Test parent and child hugetlb usage"
200  setup
201
202  echo write
203  write_hugetlbfs a "$MNT"/test $size
204
205  echo Assert memory charged correctly for parent use.
206  assert_state 0 $size 0 0
207
208  write_hugetlbfs a/b "$MNT"/test2 $size
209
210  echo Assert memory charged correctly for child use.
211  assert_state 0 $(($size * 2)) 0 $size
212
213  rmdir "$CGROUP_ROOT"/a/b
214  sleep 5
215  echo Assert memory reparent correctly.
216  assert_state 0 $(($size * 2))
217
218  rm -rf "$MNT"/*
219  umount "$MNT"
220  echo Assert memory uncharged correctly.
221  assert_state 0 0
222
223  cleanup
224fi
225
226echo
227echo
228echo "Test child only hugetlb usage"
229echo setup
230setup
231
232echo write
233write_hugetlbfs a/b "$MNT"/test2 $size
234
235echo Assert memory charged correctly for child only use.
236assert_state 0 $(($size)) 0 $size
237
238rmdir "$CGROUP_ROOT"/a/b
239echo Assert memory reparent correctly.
240assert_state 0 $size
241
242rm -rf "$MNT"/*
243umount "$MNT"
244echo Assert memory uncharged correctly.
245assert_state 0 0
246
247cleanup
248
249echo ALL PASS
250
251umount $CGROUP_ROOT
252rm -rf $CGROUP_ROOT
253