|
@@ -1,140 +1,100 @@
|
|
|
#! /bin/sh
|
|
|
-# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
-# Copyright (c) 2012 FUJITSU LIMITED
|
|
|
-# Copyright (c) 2014-2019 Linux Test Project
|
|
|
-# Copyright (c) 2021 Joerg Vehlow <joerg.vehlow@aox-tech.de>
|
|
|
-#
|
|
|
-# Author: Peng Haitao <penght@cn.fujitsu.com>
|
|
|
|
|
|
-TST_NEEDS_CHECKPOINTS=1
|
|
|
-TST_NEEDS_ROOT=1
|
|
|
-TST_NEEDS_TMPDIR=1
|
|
|
-TST_NEEDS_CMDS="killall find kill"
|
|
|
-TST_CLEANUP=memcg_cleanup
|
|
|
-TST_SETUP=memcg_setup
|
|
|
-TST_TESTFUNC=memcg_testfunc
|
|
|
+################################################################################
|
|
|
+## ##
|
|
|
+## Copyright (c) 2012 FUJITSU LIMITED ##
|
|
|
+## ##
|
|
|
+## This program is free software; you can redistribute it and#or modify ##
|
|
|
+## it under the terms of the GNU General Public License as published by ##
|
|
|
+## the Free Software Foundation; either version 2 of the License, or ##
|
|
|
+## (at your option) any later version. ##
|
|
|
+## ##
|
|
|
+## This program is distributed in the hope that it will be useful, but ##
|
|
|
+## WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ##
|
|
|
+## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ##
|
|
|
+## for more details. ##
|
|
|
+## ##
|
|
|
+## You should have received a copy of the GNU General Public License ##
|
|
|
+## along with this program; if not, write to the Free Software ##
|
|
|
+## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ##
|
|
|
+## ##
|
|
|
+## Author: Peng Haitao <penght@cn.fujitsu.com> ##
|
|
|
+## ##
|
|
|
+################################################################################
|
|
|
|
|
|
-MEMCG_SHMMAX=${MEMCG_SHMMAX:-0}
|
|
|
-MEMCG_TESTFUNC=${MEMCG_TESTFUNC:-memcg_no_testfunc}
|
|
|
+TST_NEEDS_CHECKPOINTS=1
|
|
|
+. test.sh
|
|
|
|
|
|
-. cgroup_lib.sh
|
|
|
+if [ "x$(grep -w memory /proc/cgroups | cut -f4)" != "x1" ]; then
|
|
|
+ tst_brkm TCONF "Kernel does not support the memory resource controller"
|
|
|
+fi
|
|
|
|
|
|
PAGESIZE=$(tst_getconf PAGESIZE)
|
|
|
if [ $? -ne 0 ]; then
|
|
|
- tst_brk TBROK "tst_getconf PAGESIZE failed"
|
|
|
+ tst_brkm TBROK "tst_getconf PAGESIZE failed"
|
|
|
fi
|
|
|
|
|
|
+# Check for dependencies
|
|
|
+tst_require_cmds killall
|
|
|
+
|
|
|
# Post 4.16 kernel updates stat in batch (> 32 pages) every time
|
|
|
-PAGESIZES=$(($PAGESIZE * 33))
|
|
|
+PAGESIZES=$(( $PAGESIZE * 33 ))
|
|
|
|
|
|
HUGEPAGESIZE=$(awk '/Hugepagesize/ {print $2}' /proc/meminfo)
|
|
|
[ -z $HUGEPAGESIZE ] && HUGEPAGESIZE=0
|
|
|
-HUGEPAGESIZE=$(($HUGEPAGESIZE * 1024))
|
|
|
+HUGEPAGESIZE=$(( $HUGEPAGESIZE * 1024 ))
|
|
|
+orig_memory_use_hierarchy=""
|
|
|
|
|
|
-orig_memory_use_hierarchy=
|
|
|
-orig_shmmax=
|
|
|
+MEMSW_USAGE_FLAG=0
|
|
|
+MEMSW_LIMIT_FLAG=0
|
|
|
|
|
|
-memcg_require_memsw()
|
|
|
-{
|
|
|
- if ! [ -e /dev/memcg/memory.limit_in_bytes ]; then
|
|
|
- tst_brk TBROK "/dev/memcg must be mounted before calling memcg_require_memsw"
|
|
|
- fi
|
|
|
- if ! [ -e /dev/memcg/memory.memsw.limit_in_bytes ]; then
|
|
|
- tst_brk TCONF "mem+swap is not enabled"
|
|
|
- fi
|
|
|
-}
|
|
|
+tst_tmpdir
|
|
|
+TMP_DIR="$PWD"
|
|
|
|
|
|
-memcg_require_hierarchy_disabled()
|
|
|
+cleanup()
|
|
|
{
|
|
|
- if [ ! -e "/dev/memcg/memory.use_hierarchy" ]; then
|
|
|
- tst_brk TBROK "/dev/memcg must be mounted before calling memcg_require_hierarchy_disabled"
|
|
|
- fi
|
|
|
- if [ $(cat /dev/memcg/memory.use_hierarchy) -eq 1 ]; then
|
|
|
- tst_brk TCONF "Test requires root cgroup memory.use_hierarchy=0"
|
|
|
+ if [ -n "$LOCAL_CLEANUP" ]; then
|
|
|
+ $LOCAL_CLEANUP
|
|
|
fi
|
|
|
-}
|
|
|
|
|
|
-memcg_setup()
|
|
|
-{
|
|
|
- if ! is_cgroup_subsystem_available_and_enabled "memory"; then
|
|
|
- tst_brk TCONF "Either kernel does not support Memory Resource Controller or feature not enabled"
|
|
|
- fi
|
|
|
+ killall -9 memcg_process 2> /dev/null
|
|
|
+ wait
|
|
|
|
|
|
- # Setup IPC
|
|
|
- LTP_IPC_PATH="/dev/shm/ltp_${TCID}_$$"
|
|
|
- LTP_IPC_SIZE=$PAGESIZE
|
|
|
- ROD_SILENT dd if=/dev/zero of="$LTP_IPC_PATH" bs="$LTP_IPC_SIZE" count=1
|
|
|
- ROD_SILENT chmod 600 "$LTP_IPC_PATH"
|
|
|
- export LTP_IPC_PATH
|
|
|
- # Setup IPC end
|
|
|
+ cd "$TMP_DIR"
|
|
|
|
|
|
- ROD mkdir /dev/memcg
|
|
|
- ROD mount -t cgroup -omemory memcg /dev/memcg
|
|
|
+ if [ -n "$TEST_ID" -a -d "/dev/memcg/$TEST_ID" ]; then
|
|
|
+ for i in "/dev/memcg/$TEST_ID/"*; do
|
|
|
+ if [ -d "$i" ]; then
|
|
|
+ rmdir "$i"
|
|
|
+ fi
|
|
|
+ done
|
|
|
|
|
|
- # The default value for memory.use_hierarchy is 0 and some of tests
|
|
|
- # (memcg_stat_test.sh and memcg_use_hierarchy_test.sh) expect it so
|
|
|
- # while there are distributions (RHEL7U0Beta for example) that sets
|
|
|
- # it to 1.
|
|
|
- # Note: If there are already subgroups created it is not possible,
|
|
|
- # to set this back to 0.
|
|
|
- # This seems to be the default for all systems using systemd.
|
|
|
- orig_memory_use_hierarchy=$(cat /dev/memcg/memory.use_hierarchy)
|
|
|
- if [ -z "$orig_memory_use_hierarchy" ];then
|
|
|
- tst_res TINFO "cat /dev/memcg/ failed"
|
|
|
- elif [ "$orig_memory_use_hierarchy" = "0" ];then
|
|
|
- orig_memory_use_hierarchy=""
|
|
|
- else
|
|
|
- echo 0 > /dev/memcg/memory.use_hierarchy 2>/dev/null
|
|
|
- if [ $? -ne 0 ];then
|
|
|
- tst_res TINFO "set /dev/memcg/memory.use_hierarchy to 0 failed"
|
|
|
- fi
|
|
|
- fi
|
|
|
-
|
|
|
- [ "$MEMCG_SHMMAX" = "1" ] && shmmax_setup
|
|
|
-}
|
|
|
-
|
|
|
-memcg_cleanup()
|
|
|
-{
|
|
|
- kill -9 $MEMCG_PROCESS_PID 2> /dev/null
|
|
|
-
|
|
|
- cd $TST_TMPDIR
|
|
|
- # In order to remove all subgroups, we have to remove them recursively
|
|
|
- if [ -e /dev/memcg/ltp_$$ ]; then
|
|
|
- ROD find /dev/memcg/ltp_$$ -depth -type d -delete
|
|
|
+ rmdir "/dev/memcg/$TEST_ID"
|
|
|
fi
|
|
|
|
|
|
- if [ -n "$orig_memory_use_hierarchy" ];then
|
|
|
- echo $orig_memory_use_hierarchy > /dev/memcg/memory.use_hierarchy
|
|
|
- if [ $? -ne 0 ];then
|
|
|
- tst_res TINFO "restore /dev/memcg/memory.use_hierarchy failed"
|
|
|
- fi
|
|
|
- orig_memory_use_hierarchy=""
|
|
|
- fi
|
|
|
-
|
|
|
- if [ -e "/dev/memcg" ]; then
|
|
|
+ if [ -d "/dev/memcg" ]; then
|
|
|
umount /dev/memcg
|
|
|
rmdir /dev/memcg
|
|
|
fi
|
|
|
|
|
|
- [ "$MEMCG_SHMMAX" = "1" ] && shmmax_cleanup
|
|
|
+ tst_rmdir
|
|
|
}
|
|
|
+TST_CLEANUP=cleanup
|
|
|
|
|
|
shmmax_setup()
|
|
|
{
|
|
|
tst_require_cmds bc
|
|
|
|
|
|
- tst_res TINFO "Setting shmmax"
|
|
|
-
|
|
|
- orig_shmmax=$(cat /proc/sys/kernel/shmmax)
|
|
|
- if [ $(echo "$orig_shmmax < $HUGEPAGESIZE" | bc) -eq 1 ]; then
|
|
|
+ shmmax=`cat /proc/sys/kernel/shmmax`
|
|
|
+ if [ $(echo "$shmmax < $HUGEPAGESIZE" |bc) -eq 1 ]; then
|
|
|
ROD echo "$HUGEPAGESIZE" \> /proc/sys/kernel/shmmax
|
|
|
fi
|
|
|
}
|
|
|
|
|
|
shmmax_cleanup()
|
|
|
{
|
|
|
- if [ -n "$orig_shmmax" ]; then
|
|
|
- echo "$orig_shmmax" > /proc/sys/kernel/shmmax
|
|
|
+ if [ -n "$shmmax" ]; then
|
|
|
+ echo "$shmmax" > /proc/sys/kernel/shmmax
|
|
|
fi
|
|
|
}
|
|
|
|
|
@@ -143,36 +103,27 @@ shmmax_cleanup()
|
|
|
# $2 - Expected size
|
|
|
check_mem_stat()
|
|
|
{
|
|
|
- local item_size
|
|
|
-
|
|
|
if [ -e $1 ]; then
|
|
|
- item_size=$(cat $1)
|
|
|
+ item_size=`cat $1`
|
|
|
else
|
|
|
- item_size=$(grep -w $1 memory.stat | cut -d " " -f 2)
|
|
|
+ item_size=`grep -w $1 memory.stat | cut -d " " -f 2`
|
|
|
fi
|
|
|
|
|
|
if [ "$2" = "$item_size" ]; then
|
|
|
- tst_res TPASS "$1 is $2 as expected"
|
|
|
+ tst_resm TPASS "$1 is $2 as expected"
|
|
|
else
|
|
|
- tst_res TFAIL "$1 is $item_size, $2 expected"
|
|
|
+ tst_resm TFAIL "$1 is $item_size, $2 expected"
|
|
|
fi
|
|
|
}
|
|
|
|
|
|
-start_memcg_process()
|
|
|
-{
|
|
|
- tst_res TINFO "Running memcg_process $@"
|
|
|
- memcg_process "$@" &
|
|
|
- MEMCG_PROCESS_PID=$!
|
|
|
- ROD tst_checkpoint wait 10000 0
|
|
|
-}
|
|
|
-
|
|
|
signal_memcg_process()
|
|
|
{
|
|
|
- local size=$1
|
|
|
- local path=$2
|
|
|
+ local pid=$1
|
|
|
+ local size=$2
|
|
|
+ local path=$3
|
|
|
local usage_start=$(cat ${path}memory.usage_in_bytes)
|
|
|
|
|
|
- kill -s USR1 $MEMCG_PROCESS_PID 2> /dev/null
|
|
|
+ kill -s USR1 $pid 2> /dev/null
|
|
|
|
|
|
if [ -z "$size" ]; then
|
|
|
return
|
|
@@ -180,7 +131,7 @@ signal_memcg_process()
|
|
|
|
|
|
local loops=100
|
|
|
|
|
|
- while kill -0 $MEMCG_PROCESS_PID 2> /dev/null; do
|
|
|
+ while kill -0 $pid 2> /dev/null; do
|
|
|
local usage=$(cat ${path}memory.usage_in_bytes)
|
|
|
local diff_a=$((usage_start - usage))
|
|
|
local diff_b=$((usage - usage_start))
|
|
@@ -193,32 +144,34 @@ signal_memcg_process()
|
|
|
|
|
|
loops=$((loops - 1))
|
|
|
if [ $loops -le 0 ]; then
|
|
|
- tst_brk TBROK "timed out on memory.usage_in_bytes"
|
|
|
+ tst_brkm TBROK "timeouted on memory.usage_in_bytes"
|
|
|
fi
|
|
|
done
|
|
|
}
|
|
|
|
|
|
stop_memcg_process()
|
|
|
{
|
|
|
- [ -z "$MEMCG_PROCESS_PID" ] && return
|
|
|
- kill -s INT $MEMCG_PROCESS_PID 2> /dev/null
|
|
|
- wait $MEMCG_PROCESS_PID
|
|
|
- MEMCG_PROCESS_PID=
|
|
|
+ local pid=$1
|
|
|
+ kill -s INT $pid 2> /dev/null
|
|
|
+ wait $pid
|
|
|
}
|
|
|
|
|
|
warmup()
|
|
|
{
|
|
|
- tst_res TINFO "Warming up pid: $MEMCG_PROCESS_PID"
|
|
|
- signal_memcg_process
|
|
|
- signal_memcg_process
|
|
|
+ local pid=$1
|
|
|
+
|
|
|
+ tst_resm TINFO "Warming up pid: $pid"
|
|
|
+ signal_memcg_process $pid
|
|
|
+ signal_memcg_process $pid
|
|
|
sleep 1
|
|
|
|
|
|
- if ! kill -0 $MEMCG_PROCESS_PID; then
|
|
|
- wait $MEMCG_PROCESS_PID
|
|
|
- tst_res TFAIL "Process $MEMCG_PROCESS_PID exited with $? after warm up"
|
|
|
+ kill -0 $pid
|
|
|
+ if [ $? -ne 0 ]; then
|
|
|
+ wait $pid
|
|
|
+ tst_resm TFAIL "Process $pid exited with $? after warm up"
|
|
|
return 1
|
|
|
else
|
|
|
- tst_res TINFO "Process is still here after warm up: $MEMCG_PROCESS_PID"
|
|
|
+ tst_resm TINFO "Process is still here after warm up: $pid"
|
|
|
fi
|
|
|
|
|
|
return 0
|
|
@@ -235,23 +188,86 @@ test_mem_stat()
|
|
|
local exp_stat_size=$5
|
|
|
local check_after_free=$6
|
|
|
|
|
|
- start_memcg_process $memtypes -s $size
|
|
|
+ tst_resm TINFO "Running memcg_process $memtypes -s $size"
|
|
|
+ memcg_process $memtypes -s $size &
|
|
|
+ TST_CHECKPOINT_WAIT 0
|
|
|
|
|
|
- if ! warmup; then
|
|
|
+ warmup $!
|
|
|
+ if [ $? -ne 0 ]; then
|
|
|
return
|
|
|
fi
|
|
|
|
|
|
- echo $MEMCG_PROCESS_PID > tasks
|
|
|
- signal_memcg_process $size
|
|
|
+ echo $! > tasks
|
|
|
+ signal_memcg_process $! $size
|
|
|
|
|
|
check_mem_stat $stat_name $exp_stat_size
|
|
|
|
|
|
- signal_memcg_process $size
|
|
|
+ signal_memcg_process $! $size
|
|
|
if $check_after_free; then
|
|
|
check_mem_stat $stat_name 0
|
|
|
fi
|
|
|
|
|
|
- stop_memcg_process
|
|
|
+ stop_memcg_process $!
|
|
|
+}
|
|
|
+
|
|
|
+# Run test cases which checks memory.max_usage_in_bytes after make
|
|
|
+# some memory allocation
|
|
|
+# $1 - the parameters of 'process', such as --shm
|
|
|
+# $2 - the -s parameter of 'process', such as 4096
|
|
|
+# $3 - item name
|
|
|
+# $4 - the expected size
|
|
|
+# $5 - check after free ?
|
|
|
+test_max_usage_in_bytes()
|
|
|
+{
|
|
|
+ tst_resm TINFO "Running memcg_process $1 -s $2"
|
|
|
+ memcg_process $1 -s $2 &
|
|
|
+ TST_CHECKPOINT_WAIT 0
|
|
|
+
|
|
|
+ warmup $!
|
|
|
+ if [ $? -ne 0 ]; then
|
|
|
+ return
|
|
|
+ fi
|
|
|
+
|
|
|
+ echo $! > tasks
|
|
|
+ signal_memcg_process $! $2
|
|
|
+ signal_memcg_process $! $2
|
|
|
+
|
|
|
+ check_mem_stat $3 $4
|
|
|
+
|
|
|
+ if [ $5 -eq 1 ]; then
|
|
|
+ echo 0 > $3
|
|
|
+ check_mem_stat $3 0
|
|
|
+ fi
|
|
|
+
|
|
|
+ stop_memcg_process $!
|
|
|
+}
|
|
|
+
|
|
|
+# make some memory allocation
|
|
|
+# $1 - the parameters of 'process', such as --shm
|
|
|
+# $2 - the -s parameter of 'process', such as 4096
|
|
|
+malloc_free_memory()
|
|
|
+{
|
|
|
+ tst_resm TINFO "Running memcg_process $1 -s $2"
|
|
|
+ memcg_process $1 -s $2 &
|
|
|
+ TST_CHECKPOINT_WAIT 0
|
|
|
+
|
|
|
+ echo $! > tasks
|
|
|
+ signal_memcg_process $! $2
|
|
|
+ signal_memcg_process $! $2
|
|
|
+
|
|
|
+ stop_memcg_process $!
|
|
|
+}
|
|
|
+
|
|
|
+# Test if failcnt > 0, which means page reclamation occured
|
|
|
+# $1 - item name in memcg
|
|
|
+test_failcnt()
|
|
|
+{
|
|
|
+ failcnt=`cat $1`
|
|
|
+ if [ $failcnt -gt 0 ]; then
|
|
|
+ tst_resm TPASS "$1 is $failcnt, > 0 as expected"
|
|
|
+ else
|
|
|
+ tst_resm TFAIL "$1 is $failcnt, <= 0 expected"
|
|
|
+ fi
|
|
|
}
|
|
|
|
|
|
# Test process will be killed due to exceed memory limit
|
|
@@ -261,27 +277,28 @@ test_mem_stat()
|
|
|
# $4 - use mem+swap limitation
|
|
|
test_proc_kill()
|
|
|
{
|
|
|
- local limit=$1
|
|
|
- local memtypes="$2"
|
|
|
- local size=$3
|
|
|
- local use_memsw=$4
|
|
|
- local tpk_iter
|
|
|
-
|
|
|
- echo $limit > memory.limit_in_bytes
|
|
|
- if [ $use_memsw -eq 1 ]; then
|
|
|
- memcg_require_memsw
|
|
|
- echo $limit > memory.memsw.limit_in_bytes
|
|
|
+ echo $1 > memory.limit_in_bytes
|
|
|
+ if [ $4 -eq 1 ]; then
|
|
|
+ if [ -e memory.memsw.limit_in_bytes ]; then
|
|
|
+ echo $1 > memory.memsw.limit_in_bytes
|
|
|
+ else
|
|
|
+ tst_resm TCONF "mem+swap is not enabled"
|
|
|
+ return
|
|
|
+ fi
|
|
|
fi
|
|
|
|
|
|
- start_memcg_process $memtypes -s $size
|
|
|
- echo $MEMCG_PROCESS_PID > tasks
|
|
|
+ memcg_process $2 -s $3 &
|
|
|
+ pid=$!
|
|
|
+ TST_CHECKPOINT_WAIT 0
|
|
|
+ echo $pid > tasks
|
|
|
+ sleep 1
|
|
|
|
|
|
- signal_memcg_process $size
|
|
|
+ signal_memcg_process $pid $3
|
|
|
|
|
|
- local tpk_pid_exists=1
|
|
|
+ tpk_pid_exists=1
|
|
|
for tpk_iter in $(seq 20); do
|
|
|
- if [ ! -d "/proc/$MEMCG_PROCESS_PID" ] ||
|
|
|
- grep -q 'Z (zombie)' "/proc/$MEMCG_PROCESS_PID/status"; then
|
|
|
+ if [ ! -d "/proc/$pid" ] ||
|
|
|
+ grep -q 'Z (zombie)' "/proc/$pid/status"; then
|
|
|
tpk_pid_exists=0
|
|
|
break
|
|
|
fi
|
|
@@ -290,18 +307,18 @@ test_proc_kill()
|
|
|
done
|
|
|
|
|
|
if [ $tpk_pid_exists -eq 0 ]; then
|
|
|
- wait $MEMCG_PROCESS_PID
|
|
|
+ wait $pid
|
|
|
ret=$?
|
|
|
if [ $ret -eq 1 ]; then
|
|
|
- tst_res TFAIL "process $MEMCG_PROCESS_PID is killed by error"
|
|
|
+ tst_resm TFAIL "process $pid is killed by error"
|
|
|
elif [ $ret -eq 2 ]; then
|
|
|
- tst_res TPASS "Failed to lock memory"
|
|
|
+ tst_resm TPASS "Failed to lock memory"
|
|
|
else
|
|
|
- tst_res TPASS "process $MEMCG_PROCESS_PID is killed"
|
|
|
+ tst_resm TPASS "process $pid is killed"
|
|
|
fi
|
|
|
else
|
|
|
- stop_memcg_process
|
|
|
- tst_res TFAIL "process $MEMCG_PROCESS_PID is not killed"
|
|
|
+ stop_memcg_process $!
|
|
|
+ tst_resm TFAIL "process $pid is not killed"
|
|
|
fi
|
|
|
}
|
|
|
|
|
@@ -310,46 +327,229 @@ test_proc_kill()
|
|
|
# $2 - use mem+swap limitation
|
|
|
test_limit_in_bytes()
|
|
|
{
|
|
|
- local limit=$1
|
|
|
- local use_memsw=$2
|
|
|
- local elimit
|
|
|
-
|
|
|
- echo $limit > memory.limit_in_bytes
|
|
|
- if [ $use_memsw -eq 1 ]; then
|
|
|
- memcg_require_memsw
|
|
|
- echo $limit > memory.memsw.limit_in_bytes
|
|
|
- elimit=$(cat memory.memsw.limit_in_bytes)
|
|
|
+ echo $1 > memory.limit_in_bytes
|
|
|
+ if [ $2 -eq 1 ]; then
|
|
|
+ if [ -e memory.memsw.limit_in_bytes ]; then
|
|
|
+ echo $1 > memory.memsw.limit_in_bytes
|
|
|
+ limit=`cat memory.memsw.limit_in_bytes`
|
|
|
+ else
|
|
|
+ tst_resm TCONF "mem+swap is not enabled"
|
|
|
+ return
|
|
|
+ fi
|
|
|
else
|
|
|
- elimit=$(cat memory.limit_in_bytes)
|
|
|
+ limit=`cat memory.limit_in_bytes`
|
|
|
fi
|
|
|
|
|
|
- # Kernels prior to 3.19 were rounding up,
|
|
|
- # but newer kernels are rounding down
|
|
|
- local limit_up=$(( PAGESIZE * (limit / PAGESIZE) ))
|
|
|
- local limit_down=$(( PAGESIZE * ((limit + PAGESIZE - 1) / PAGESIZE) ))
|
|
|
- if [ $limit_up -eq $elimit ] || [ $limit_down -eq $elimit ]; then
|
|
|
- tst_res TPASS "input=$limit, limit_in_bytes=$elimit"
|
|
|
+ # Kernels prior to 3.19 were rounding up but newer kernels
|
|
|
+ # are rounding down
|
|
|
+ if [ \( $(($PAGESIZE*($1/$PAGESIZE))) -eq $limit \) \
|
|
|
+ -o \( $(($PAGESIZE*(($1+$PAGESIZE-1)/$PAGESIZE))) -eq $limit \) ]; then
|
|
|
+ tst_resm TPASS "input=$1, limit_in_bytes=$limit"
|
|
|
else
|
|
|
- tst_res TFAIL "input=$limit, limit_in_bytes=$elimit"
|
|
|
+ tst_resm TFAIL "input=$1, limit_in_bytes=$limit"
|
|
|
fi
|
|
|
}
|
|
|
|
|
|
-memcg_testfunc()
|
|
|
+# Never used, so untested
|
|
|
+#
|
|
|
+# Test memory controller doesn't charge hugepage
|
|
|
+# $1 - the value of /proc/sys/vm/nr_hugepages
|
|
|
+# $2 - the parameters of 'process', --mmap-file or --shm
|
|
|
+# $3 - the -s parameter of 'process', such as $HUGEPAGESIZE
|
|
|
+# $4 - 0: expected failure, 1: expected success
|
|
|
+test_hugepage()
|
|
|
{
|
|
|
- ROD mkdir /dev/memcg/ltp_$$
|
|
|
- cd /dev/memcg/ltp_$$
|
|
|
+ TMP_FILE="$TMP_DIR/tmp"
|
|
|
+ nr_hugepages=`cat /proc/sys/vm/nr_hugepages`
|
|
|
+
|
|
|
+ mkdir /hugetlb
|
|
|
+ mount -t hugetlbfs none /hugetlb
|
|
|
+
|
|
|
+ echo $1 > /proc/sys/vm/nr_hugepages
|
|
|
+
|
|
|
+ memcg_process $2 --hugepage -s $3 > $TMP_FILE 2>&1 &
|
|
|
+ TST_CHECKPOINT_WAIT 0
|
|
|
|
|
|
- if type ${MEMCG_TESTFUNC}1 > /dev/null 2>&1; then
|
|
|
- ${MEMCG_TESTFUNC}$1 $1 "$2"
|
|
|
+ signal_memcg_process $! $3
|
|
|
+
|
|
|
+ check_mem_stat "rss" 0
|
|
|
+
|
|
|
+ echo "TMP_FILE:"
|
|
|
+ cat $TMP_FILE
|
|
|
+
|
|
|
+ if [ $4 -eq 0 ]; then
|
|
|
+ test -s $TMP_FILE
|
|
|
+ if [ $? -eq 0 ]; then
|
|
|
+ tst_resm TPASS "allocate hugepage failed as expected"
|
|
|
+ else
|
|
|
+ signal_memcg_process $! $3
|
|
|
+ stop_memcg_process $!
|
|
|
+ tst_resm TFAIL "allocate hugepage should fail"
|
|
|
+ fi
|
|
|
else
|
|
|
- ${MEMCG_TESTFUNC} $1 "$2"
|
|
|
+ test ! -s $TMP_FILE
|
|
|
+ if [ $? -eq 0 ]; then
|
|
|
+ signal_memcg_process $! $3
|
|
|
+ stop_memcg_process $!
|
|
|
+ tst_resm TPASS "allocate hugepage succeeded"
|
|
|
+ else
|
|
|
+ tst_resm TFAIL "allocate hugepage failed"
|
|
|
+ fi
|
|
|
fi
|
|
|
|
|
|
- cd $TST_TMPDIR
|
|
|
- ROD rmdir /dev/memcg/ltp_$$
|
|
|
+ sleep 1
|
|
|
+ rm -rf $TMP_FILE
|
|
|
+ umount /hugetlb
|
|
|
+ rmdir /hugetlb
|
|
|
+ echo $nr_hugepages > /proc/sys/vm/nr_hugepages
|
|
|
}
|
|
|
|
|
|
-memcg_no_testfunc()
|
|
|
+# Test the memory charge won't move to subgroup
|
|
|
+# $1 - memory.limit_in_bytes in parent group
|
|
|
+# $2 - memory.limit_in_bytes in sub group
|
|
|
+test_subgroup()
|
|
|
{
|
|
|
- tst_brk TBROK "No testfunc specified, set MEMCG_TESTFUNC"
|
|
|
+ mkdir subgroup
|
|
|
+ echo $1 > memory.limit_in_bytes
|
|
|
+ echo $2 > subgroup/memory.limit_in_bytes
|
|
|
+
|
|
|
+ tst_resm TINFO "Running memcg_process --mmap-anon -s $PAGESIZES"
|
|
|
+ memcg_process --mmap-anon -s $PAGESIZES &
|
|
|
+ TST_CHECKPOINT_WAIT 0
|
|
|
+
|
|
|
+ warmup $! $PAGESIZES
|
|
|
+ if [ $? -ne 0 ]; then
|
|
|
+ return
|
|
|
+ fi
|
|
|
+
|
|
|
+ echo $! > tasks
|
|
|
+ signal_memcg_process $! $PAGESIZES
|
|
|
+ check_mem_stat "rss" $PAGESIZES
|
|
|
+
|
|
|
+ cd subgroup
|
|
|
+ echo $! > tasks
|
|
|
+ check_mem_stat "rss" 0
|
|
|
+
|
|
|
+ # cleanup
|
|
|
+ cd ..
|
|
|
+ echo $! > tasks
|
|
|
+ stop_memcg_process $!
|
|
|
+ rmdir subgroup
|
|
|
+}
|
|
|
+
|
|
|
+# Run test cases which test memory.move_charge_at_immigrate
|
|
|
+test_move_charge()
|
|
|
+{
|
|
|
+ local memtypes="$1"
|
|
|
+ local size=$2
|
|
|
+ local total_size=$3
|
|
|
+ local move_charge_mask=$4
|
|
|
+ local b_rss=$5
|
|
|
+ local b_cache=$6
|
|
|
+ local a_rss=$7
|
|
|
+ local a_cache=$8
|
|
|
+
|
|
|
+ mkdir subgroup_a
|
|
|
+
|
|
|
+ tst_resm TINFO "Running memcg_process $memtypes -s $size"
|
|
|
+ memcg_process $memtypes -s $size &
|
|
|
+ TST_CHECKPOINT_WAIT 0
|
|
|
+ warmup $!
|
|
|
+ if [ $? -ne 0 ]; then
|
|
|
+ rmdir subgroup_a
|
|
|
+ return
|
|
|
+ fi
|
|
|
+
|
|
|
+ echo $! > subgroup_a/tasks
|
|
|
+ signal_memcg_process $! $total_size "subgroup_a/"
|
|
|
+
|
|
|
+ mkdir subgroup_b
|
|
|
+ echo $move_charge_mask > subgroup_b/memory.move_charge_at_immigrate
|
|
|
+ echo $! > subgroup_b/tasks
|
|
|
+
|
|
|
+ cd subgroup_b
|
|
|
+ check_mem_stat "rss" $b_rss
|
|
|
+ check_mem_stat "cache" $b_cache
|
|
|
+ cd ../subgroup_a
|
|
|
+ check_mem_stat "rss" $a_rss
|
|
|
+ check_mem_stat "cache" $a_cache
|
|
|
+ cd ..
|
|
|
+ stop_memcg_process $!
|
|
|
+ rmdir subgroup_a subgroup_b
|
|
|
+}
|
|
|
+
|
|
|
+cleanup_test()
|
|
|
+{
|
|
|
+ TEST_ID="$1"
|
|
|
+
|
|
|
+ if [ -n "$orig_memory_use_hierarchy" ];then
|
|
|
+ echo $orig_memory_use_hierarchy > \
|
|
|
+ /dev/memcg/memory.use_hierarchy
|
|
|
+ if [ $? -ne 0 ];then
|
|
|
+ tst_resm TINFO "restore "\
|
|
|
+ "/dev/memcg/memory.use_hierarchy failed"
|
|
|
+ fi
|
|
|
+ orig_memory_use_hierarchy=""
|
|
|
+ fi
|
|
|
+
|
|
|
+ killall -9 memcg_process 2>/dev/null
|
|
|
+ wait
|
|
|
+
|
|
|
+ ROD cd "$TMP_DIR"
|
|
|
+
|
|
|
+ ROD rmdir "/dev/memcg/$TEST_ID"
|
|
|
+ TEST_ID=""
|
|
|
+ ROD umount /dev/memcg
|
|
|
+ ROD rmdir /dev/memcg
|
|
|
+}
|
|
|
+
|
|
|
+setup_test()
|
|
|
+{
|
|
|
+ TEST_ID="$1"
|
|
|
+
|
|
|
+ ROD mkdir /dev/memcg
|
|
|
+ ROD mount -t cgroup -omemory memcg /dev/memcg
|
|
|
+
|
|
|
+ # The default value for memory.use_hierarchy is 0 and some of tests
|
|
|
+ # (memcg_stat_test.sh and memcg_use_hierarchy_test.sh) expect it so
|
|
|
+ # while there are distributions (RHEL7U0Beta for example) that sets
|
|
|
+ # it to 1.
|
|
|
+ orig_memory_use_hierarchy=$(cat /dev/memcg/memory.use_hierarchy)
|
|
|
+ if [ -z "$orig_memory_use_hierarchy" ];then
|
|
|
+ tst_resm TINFO "cat /dev/memcg/memory.use_hierarchy failed"
|
|
|
+ elif [ "$orig_memory_use_hierarchy" = "0" ];then
|
|
|
+ orig_memory_use_hierarchy=""
|
|
|
+ else
|
|
|
+ echo 0 > /dev/memcg/memory.use_hierarchy
|
|
|
+ if [ $? -ne 0 ];then
|
|
|
+ tst_resm TINFO "set /dev/memcg/memory.use_hierarchy" \
|
|
|
+ "to 0 failed"
|
|
|
+ fi
|
|
|
+ fi
|
|
|
+
|
|
|
+ ROD mkdir "/dev/memcg/$TEST_ID"
|
|
|
+ ROD cd "/dev/memcg/$TEST_ID"
|
|
|
+}
|
|
|
+
|
|
|
+# Run all the test cases
|
|
|
+run_tests()
|
|
|
+{
|
|
|
+ for i in $(seq 1 $TST_TOTAL); do
|
|
|
+
|
|
|
+ tst_resm TINFO "Starting test $i"
|
|
|
+
|
|
|
+ setup_test $i
|
|
|
+
|
|
|
+ if [ -e memory.memsw.limit_in_bytes ]; then
|
|
|
+ MEMSW_LIMIT_FLAG=1
|
|
|
+ fi
|
|
|
+
|
|
|
+ if [ -e memory.memsw.max_usage_in_bytes ]; then
|
|
|
+ MEMSW_USAGE_FLAG=1
|
|
|
+ fi
|
|
|
+
|
|
|
+ testcase_$i
|
|
|
+
|
|
|
+ cleanup_test $i
|
|
|
+ done
|
|
|
}
|