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