#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # Kselftest framework requirement - SKIP code is 4. ksft_skip=4 set -e if [[ $(id -u) -ne 0 ]]; then echo "This test must be run as root. Skipping..." exit $ksft_skip fi nr_hugepgs=$(cat /proc/sys/vm/nr_hugepages) usage_file=usage_in_bytes if [[ "$1" == "-cgroup-v2" ]]; then cgroup2=1 usage_file=current fi if [[ $cgroup2 ]]; then CGROUP_ROOT=$(mount -t cgroup2 | head -1 | awk '{print $3}') if [[ -z "$CGROUP_ROOT" ]]; then CGROUP_ROOT=$(mktemp -d) mount -t cgroup2 none $CGROUP_ROOT do_umount=1 fi echo "+hugetlb +memory" >$CGROUP_ROOT/cgroup.subtree_control else CGROUP_ROOT=$(mount -t cgroup | grep ",hugetlb" | awk '{print $3}') if [[ -z "$CGROUP_ROOT" ]]; then CGROUP_ROOT=/dev/cgroup/memory mount -t cgroup memory,hugetlb $CGROUP_ROOT do_umount=1 fi fi MNT='/mnt/huge' function get_machine_hugepage_size() { hpz=$(grep -i hugepagesize /proc/meminfo) kb=${hpz:14:-3} mb=$(($kb / 1024)) echo $mb } MB=$(get_machine_hugepage_size) function cleanup() { echo cleanup set +e rm -rf "$MNT"/* 2>/dev/null umount "$MNT" 2>/dev/null rmdir "$MNT" 2>/dev/null rmdir "$CGROUP_ROOT"/a/b 2>/dev/null rmdir "$CGROUP_ROOT"/a 2>/dev/null rmdir "$CGROUP_ROOT"/test1 2>/dev/null echo $nr_hugepgs >/proc/sys/vm/nr_hugepages set -e } function assert_with_retry() { local actual_path="$1" local expected="$2" local tolerance=$((7 * 1024 * 1024)) local timeout=20 local interval=1 local start_time local now local elapsed local actual start_time=$(date +%s) while true; do actual="$(cat "$actual_path")" if [[ $actual -ge $(($expected - $tolerance)) ]] && [[ $actual -le $(($expected + $tolerance)) ]]; then return 0 fi now=$(date +%s) elapsed=$((now - start_time)) if [[ $elapsed -ge $timeout ]]; then echo "actual = $((${actual%% *} / 1024 / 1024)) MB" echo "expected = $((${expected%% *} / 1024 / 1024)) MB" cleanup exit 1 fi sleep $interval done } function assert_state() { local expected_a="$1" local expected_a_hugetlb="$2" local expected_b="" local expected_b_hugetlb="" if [ ! -z ${3:-} ] && [ ! -z ${4:-} ]; then expected_b="$3" expected_b_hugetlb="$4" fi assert_with_retry "$CGROUP_ROOT/a/memory.$usage_file" "$expected_a" assert_with_retry "$CGROUP_ROOT/a/hugetlb.${MB}MB.$usage_file" "$expected_a_hugetlb" if [[ -n "$expected_b" && -n "$expected_b_hugetlb" ]]; then assert_with_retry "$CGROUP_ROOT/a/b/memory.$usage_file" "$expected_b" assert_with_retry "$CGROUP_ROOT/a/b/hugetlb.${MB}MB.$usage_file" "$expected_b_hugetlb" fi } function setup() { echo 100 >/proc/sys/vm/nr_hugepages mkdir "$CGROUP_ROOT"/a sleep 1 if [[ $cgroup2 ]]; then echo "+hugetlb +memory" >$CGROUP_ROOT/a/cgroup.subtree_control else echo 0 >$CGROUP_ROOT/a/cpuset.mems echo 0 >$CGROUP_ROOT/a/cpuset.cpus fi mkdir "$CGROUP_ROOT"/a/b if [[ ! $cgroup2 ]]; then echo 0 >$CGROUP_ROOT/a/b/cpuset.mems echo 0 >$CGROUP_ROOT/a/b/cpuset.cpus fi mkdir -p "$MNT" mount -t hugetlbfs none "$MNT" } write_hugetlbfs() { local cgroup="$1" local path="$2" local size="$3" if [[ $cgroup2 ]]; then echo $$ >$CGROUP_ROOT/$cgroup/cgroup.procs else echo 0 >$CGROUP_ROOT/$cgroup/cpuset.mems echo 0 >$CGROUP_ROOT/$cgroup/cpuset.cpus echo $$ >"$CGROUP_ROOT/$cgroup/tasks" fi ./write_to_hugetlbfs -p "$path" -s "$size" -m 0 -o if [[ $cgroup2 ]]; then echo $$ >$CGROUP_ROOT/cgroup.procs else echo $$ >"$CGROUP_ROOT/tasks" fi echo } set -e size=$((${MB} * 1024 * 1024 * 25)) # 50MB = 25 * 2MB hugepages. cleanup echo echo Test charge, rmdir, uncharge setup echo mkdir mkdir $CGROUP_ROOT/test1 echo write write_hugetlbfs test1 "$MNT"/test $size echo rmdir rmdir $CGROUP_ROOT/test1 mkdir $CGROUP_ROOT/test1 echo uncharge rm -rf /mnt/huge/* cleanup echo done echo if [[ ! $cgroup2 ]]; then echo "Test parent and child hugetlb usage" setup echo write write_hugetlbfs a "$MNT"/test $size echo Assert memory charged correctly for parent use. assert_state 0 $size 0 0 write_hugetlbfs a/b "$MNT"/test2 $size echo Assert memory charged correctly for child use. assert_state 0 $(($size * 2)) 0 $size rmdir "$CGROUP_ROOT"/a/b echo Assert memory reparent correctly. assert_state 0 $(($size * 2)) rm -rf "$MNT"/* umount "$MNT" echo Assert memory uncharged correctly. assert_state 0 0 cleanup fi echo echo "Test child only hugetlb usage" echo setup setup echo write write_hugetlbfs a/b "$MNT"/test2 $size echo Assert memory charged correctly for child only use. assert_state 0 $(($size)) 0 $size rmdir "$CGROUP_ROOT"/a/b echo Assert memory reparent correctly. assert_state 0 $size rm -rf "$MNT"/* umount "$MNT" echo Assert memory uncharged correctly. assert_state 0 0 cleanup echo ALL PASS if [[ $do_umount ]]; then umount $CGROUP_ROOT rm -rf $CGROUP_ROOT fi echo "$nr_hugepgs" > /proc/sys/vm/nr_hugepages