[LTP] [PATCH 1/5] acpi_hotplug: Add library file for ACPI based cpu and memory hotplug
Masayoshi Mizuma
msys.mizuma@gmail.com
Mon Aug 20 21:49:11 CEST 2018
From: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
This file includes some APIs to use ACPI based cpu and memory hotplug.
Signed-off-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
---
.../hotplug/acpi_hotplug/ACPIHOTPLUG_lib.sh | 310 ++++++++++++++++++
1 file changed, 310 insertions(+)
create mode 100755 testcases/kernel/hotplug/acpi_hotplug/ACPIHOTPLUG_lib.sh
diff --git a/testcases/kernel/hotplug/acpi_hotplug/ACPIHOTPLUG_lib.sh b/testcases/kernel/hotplug/acpi_hotplug/ACPIHOTPLUG_lib.sh
new file mode 100755
index 000000000..8c5dc1d89
--- /dev/null
+++ b/testcases/kernel/hotplug/acpi_hotplug/ACPIHOTPLUG_lib.sh
@@ -0,0 +1,310 @@
+#!/bin/sh
+
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2018, FUJITSU LIMITED. All rights reserved.
+
+export HOTPLUGABLE_CONTAINER=
+export HOTPLUGABLE_NODES=()
+RETRY=5
+RETRY_TIME=60
+
+# $1: node number
+is_memoryless_node()
+{
+ local node=$1
+
+ numactl -H | awk '
+ /node '$node' size:/ {
+ if ($4 == 0)
+ prine 1
+ else
+ print 0
+ }'
+}
+
+# $1: node number
+is_movable_node()
+{
+ local node=$1
+
+ awk '
+ BEGIN {
+ zone = ""
+ NotMovableFound = 0
+ nextnode = '$node' + 1
+ }
+ /^Node '$node'/{
+ zone = $4
+ }
+ /present/ {
+ if (zone != "") {
+ if ((zone != "Movable") && ($2 != 0)) {
+ NotMovableFound = 1
+ exit
+ }
+ }
+ }
+ match($0, "^Node " nextnode) {
+ exit
+ }
+
+ END {
+ if (NotMovableFound == 0)
+ print 1
+ else
+ print 0
+ }
+ ' /proc/zoneinfo
+}
+
+stop_udev()
+{
+ systemctl stop systemd-udevd-kernel.socket
+ systemctl stop systemd-udevd-control.socket
+ systemctl stop systemd-udevd.service
+}
+
+resume_udev()
+{
+ systemctl start systemd-udevd.service
+ systemctl start systemd-udevd-kernel.socket
+ systemctl start systemd-udevd-control.socket
+}
+
+_setup()
+{
+ local ACPI_CONTAINERS=()
+ local ONLINE_CONTAINERS=()
+ local CPUS=()
+ local tmp_NODES=()
+ local NODES=()
+ local movable_node=
+ local NOHP_NODES=0
+
+ ACPI_CONTAINERS=( $(find /sys/devices/LNXSYSTM\:00/ -name 'ACPI0004:*') )
+
+ ONLINE_CONTAINERS=()
+ for c in ${ACPI_CONTAINERS[@]}; do
+ status=$(cat $c/status)
+ if [[ $status -ne 0 ]]; then
+ ONLINE_CONTAINERS=( ${ONLINE_CONTAINERS[@]} $c )
+ fi
+ done
+
+ if [[ ${#ONLINE_CONTAINERS[@]} -lt 2 ]]; then
+ tst_brk TCONF "The number of online ACPI containers is not enough. 2 or more online ACPI containers are needed, but this system has ${#ONLINE_CONTAINERS[@]} contianers."
+ fi
+
+ for c in ${ONLINE_CONTAINERS[@]}; do
+ CPUS=( $(find $c -name 'ACPI0007:*' ) )
+ tmp_NODES=()
+ NODES=()
+ NOHP_NODES=0
+ for cpu in ${CPUS[@]}; do
+ tmp_NODES=( ${tmp_NODES[@]} $(ls $cpu/physical_node/ 2> /dev/null | grep ^node | sed -e 's/node//') )
+ done
+ NODES=( $(echo ${tmp_NODES[@]} | tr ' ' '\n' | sort | uniq ) )
+
+ # Memory device ID is PNP0C80, however, the memory ID is not used here
+ # but the node ID is used.
+ # The hotplugable memory section has ACPI_SRAT_MEM_HOT_PLUGGABLE flag
+ # and the zone is handled as Movable zone. Following assumes that
+ # the node has only Movable zone or it is memory less node.
+ # So using the node ID gets this test cleared rather than using memory ID.
+ for n in ${NODES[@]}; do
+ if [[ $(is_movable_node $n) -eq 0 ]] && [[ $(is_memoryless_node $n) -eq 0 ]]; then
+ NOHP_NODES=1
+ break
+ fi
+ done
+ if [[ $NOHP_NODES -eq 0 ]]; then
+ HOTPLUGABLE_CONTAINER=$(basename $c)
+ HOTPLUGABLE_NODES=( ${NODES[@]} )
+ break
+ fi
+ done
+
+ # Some hotplug udev rules may disturb for this test.
+ # Let's stop them.
+ stop_udev
+
+ tst_res TINFO "TARGET ACPI CONTANIER: $HOTPLUGABLE_CONTAINER"
+ tst_res TINFO "TARGET NODES: ${HOTPLUGABLE_NODES[@]}"
+}
+
+_cleanup()
+{
+ resume_udev
+}
+
+cpu_hp()
+{
+ local hpop=
+ local CPUS=( $(echo /sys/bus/acpi/devices/$HOTPLUGABLE_CONTAINER/ACPI0007:*/physical_node/online) )
+
+ local hp_cpus=${#CPUS[@]}
+ local current_cpus=$(nproc)
+ local expected_cpus=
+ local ACPI_CPU=
+ local force=0
+ local hotplugedcpus=0
+
+ if [[ $1 == "hotremove" ]]; then
+ hpop=0
+ else
+ hpop=1
+ fi
+ if [[ $2 == "force" ]]; then
+ force=1
+ fi
+
+ if [[ $hpop -eq 0 ]]; then
+ expected_cpus=$(( current_cpus - hp_cpus ))
+ else
+ expected_cpus=$(( current_cpus + hp_cpus ))
+ fi
+
+ for cpu in ${CPUS[@]}; do
+ echo -n $hpop > $cpu 2> /dev/null
+ ACPI_CPU=$( echo $cpu | sed -e 's#/sys/bus/acpi/devices/ACPI0004:[0-9a-f]\+/\(ACPI0007:.*\)/physical_node/online#\1#')
+ if [[ $? -ne 0 ]]; then
+ tst_res TINFO "CPU: $ACPI_CPU $1 failed."
+ if [[ $force -eq 0 ]]; then
+ return 1
+ fi
+ else
+ if [[ $force -ne 0 ]]; then
+ tst_res TINFO "CPU: $ACPI_CPU $1 successed."
+ fi
+ hotplugedcpus=$(( hotplugedcpus + 1 ))
+ fi
+ done
+
+ tst_res TINFO "CPU: current: $(nproc) hotpluged: $hotplugedcpus"
+ if [[ $(nproc) -eq $expected_cpus ]]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+# $1: node number
+# $2: expected memory size (MB)
+memhp_result()
+{
+ local node=$1
+ local expected=$2
+ local current=
+
+ current=$(numactl -H | awk '
+ /^node '$node' size/ {
+ print $4
+ }
+ ')
+
+ if [[ $current -eq $expected ]]; then
+ echo 1
+ else
+ echo 0
+ fi
+}
+
+memory_hp()
+{
+ local hpop=
+ local memory=()
+ local memhpdone=
+ local expected=
+ local block_size_bytes=$(cat /sys/devices/system/memory/block_size_bytes )
+ block_size_bytes=$(echo "obase=10;ibase=16;$block_size_bytes" | bc)
+ local result=0
+ local force=0
+ local hotplugedsections=
+ local removable=
+
+ declare -A mem_hotpluged
+
+ if [[ $1 == "hotremove" ]]; then
+ hpop="offline"
+ else
+ hpop="online_movable"
+ fi
+ if [[ $2 == "force" ]]; then
+ force=1
+ fi
+
+ for node in ${HOTPLUGABLE_NODES[@]}; do
+ memory=$(ls /sys/devices/system/node/node$node/ | grep memory | sort -n -r)
+ for mem in ${memory[@]}; do
+ if [[ $force -eq 1 ]]; then
+ echo -n $hpop > /sys/devices/system/node/node$node/$mem/state 2> /dev/null
+ mem_hotpluged[$node]=$(( mem_hotpluged[$node] + 1 ))
+ hotplugedsections=$(( hotplugedsections + 1 ))
+ else
+ memhpdone=0
+ for ((i = 1; i <= RETRY; i++)); do
+ echo -n $hpop > /sys/devices/system/node/node$node/$mem/state
+ if [[ $? -eq 0 ]]; then
+ memhpdone=1
+ break
+ else
+ removable=$(cat /sys/devices/system/node/node$node/$mem/removable)
+ if [[ $removable -ne 1 ]]; then
+ tst_res TINFO "memory: Node: $node section: $mem something wrong..."
+ return 1
+ fi
+ tst_res TINFO "memory: Node: $node section: $mem $1 failed ($i times). Retry..."
+ fi
+ sleep $RETRY_TIME
+ done
+ if [[ $memhpdone -eq 0 ]]; then
+ tst_res TINFO "memory: Node: $node section: $mem $1 failed."
+ return 1
+ else
+ tst_res TINFO "memory: Node: $node section: $mem $1 successed."
+ mem_hotpluged[$node]=$(( mem_hotpluged[$node] + 1 ))
+ hotplugedsections=$(( hotplugedsections + 1 ))
+ fi
+ fi
+ done
+ done
+
+ for node in ${HOTPLUGABLE_NODES[@]}; do
+ if [[ $hpop == "offline" ]]; then
+ expected=0
+ else
+ expected=$(echo "${mem_hotpluged[$node]} * $block_size_bytes/1024/1024" | bc)
+ fi
+ if [[ $(memhp_result $node $expected) -ne 1 ]]; then
+ result=$((result + 1))
+ fi
+ tst_res TINFO "Memory: Node: $node $hotplugedsections sections hotpluged."
+ done
+
+ return $result
+}
+
+container_hp()
+{
+ local hpop=
+ local online_ret=0
+
+ if [[ $1 == "hotremove" ]]; then
+ hpop=0
+ else
+ hpop=1
+ fi
+
+ echo $hpop > /sys/bus/acpi/devices/$HOTPLUGABLE_CONTAINER/physical_node/online
+ online_ret=$?
+
+ if [[ $online_ret -ne 0 ]]; then
+ tst_res TINFO "ACPI container: $HOTPLUGABLE_CONTAINER $1 failed."
+ numactl -H
+ return 1
+ else
+ tst_res TINFO "ACPI container: $HOTPLUGABLE_CONTAINER $1 successed."
+ fi
+
+ return 0
+}
--
2.18.0
More information about the ltp
mailing list