162306a36Sopenharmony_ci#!/bin/bash
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci
462306a36Sopenharmony_ciSYSFS=
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci# Kselftest framework requirement - SKIP code is 4.
762306a36Sopenharmony_ciksft_skip=4
862306a36Sopenharmony_ci
962306a36Sopenharmony_ciprerequisite()
1062306a36Sopenharmony_ci{
1162306a36Sopenharmony_ci	msg="skip all tests:"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci	if [ $UID != 0 ]; then
1462306a36Sopenharmony_ci		echo $msg must be run as root >&2
1562306a36Sopenharmony_ci		exit $ksft_skip
1662306a36Sopenharmony_ci	fi
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	if [ ! -d "$SYSFS" ]; then
2162306a36Sopenharmony_ci		echo $msg sysfs is not mounted >&2
2262306a36Sopenharmony_ci		exit $ksft_skip
2362306a36Sopenharmony_ci	fi
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	if ! ls $SYSFS/devices/system/memory/memory* > /dev/null 2>&1; then
2662306a36Sopenharmony_ci		echo $msg memory hotplug is not supported >&2
2762306a36Sopenharmony_ci		exit $ksft_skip
2862306a36Sopenharmony_ci	fi
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	if ! grep -q 1 $SYSFS/devices/system/memory/memory*/removable; then
3162306a36Sopenharmony_ci		echo $msg no hot-pluggable memory >&2
3262306a36Sopenharmony_ci		exit $ksft_skip
3362306a36Sopenharmony_ci	fi
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#
3762306a36Sopenharmony_ci# list all hot-pluggable memory
3862306a36Sopenharmony_ci#
3962306a36Sopenharmony_cihotpluggable_memory()
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	local state=${1:-.\*}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	for memory in $SYSFS/devices/system/memory/memory*; do
4462306a36Sopenharmony_ci		if grep -q 1 $memory/removable &&
4562306a36Sopenharmony_ci		   grep -q $state $memory/state; then
4662306a36Sopenharmony_ci			echo ${memory##/*/memory}
4762306a36Sopenharmony_ci		fi
4862306a36Sopenharmony_ci	done
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cihotpluggable_offline_memory()
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	hotpluggable_memory offline
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cihotpluggable_online_memory()
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	hotpluggable_memory online
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cimemory_is_online()
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	grep -q online $SYSFS/devices/system/memory/memory$1/state
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cimemory_is_offline()
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	grep -q offline $SYSFS/devices/system/memory/memory$1/state
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cionline_memory()
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	echo online > $SYSFS/devices/system/memory/memory$1/state
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cioffline_memory()
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	echo offline > $SYSFS/devices/system/memory/memory$1/state
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cionline_memory_expect_success()
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	local memory=$1
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if ! online_memory $memory; then
8662306a36Sopenharmony_ci		echo $FUNCNAME $memory: unexpected fail >&2
8762306a36Sopenharmony_ci		return 1
8862306a36Sopenharmony_ci	elif ! memory_is_online $memory; then
8962306a36Sopenharmony_ci		echo $FUNCNAME $memory: unexpected offline >&2
9062306a36Sopenharmony_ci		return 1
9162306a36Sopenharmony_ci	fi
9262306a36Sopenharmony_ci	return 0
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cionline_memory_expect_fail()
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	local memory=$1
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if online_memory $memory 2> /dev/null; then
10062306a36Sopenharmony_ci		echo $FUNCNAME $memory: unexpected success >&2
10162306a36Sopenharmony_ci		return 1
10262306a36Sopenharmony_ci	elif ! memory_is_offline $memory; then
10362306a36Sopenharmony_ci		echo $FUNCNAME $memory: unexpected online >&2
10462306a36Sopenharmony_ci		return 1
10562306a36Sopenharmony_ci	fi
10662306a36Sopenharmony_ci	return 0
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cioffline_memory_expect_success()
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	local memory=$1
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if ! offline_memory $memory; then
11462306a36Sopenharmony_ci		echo $FUNCNAME $memory: unexpected fail >&2
11562306a36Sopenharmony_ci		return 1
11662306a36Sopenharmony_ci	elif ! memory_is_offline $memory; then
11762306a36Sopenharmony_ci		echo $FUNCNAME $memory: unexpected offline >&2
11862306a36Sopenharmony_ci		return 1
11962306a36Sopenharmony_ci	fi
12062306a36Sopenharmony_ci	return 0
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cioffline_memory_expect_fail()
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	local memory=$1
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if offline_memory $memory 2> /dev/null; then
12862306a36Sopenharmony_ci		echo $FUNCNAME $memory: unexpected success >&2
12962306a36Sopenharmony_ci		return 1
13062306a36Sopenharmony_ci	elif ! memory_is_online $memory; then
13162306a36Sopenharmony_ci		echo $FUNCNAME $memory: unexpected offline >&2
13262306a36Sopenharmony_ci		return 1
13362306a36Sopenharmony_ci	fi
13462306a36Sopenharmony_ci	return 0
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cionline_all_offline_memory()
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	for memory in `hotpluggable_offline_memory`; do
14062306a36Sopenharmony_ci		if ! online_memory_expect_success $memory; then
14162306a36Sopenharmony_ci			retval=1
14262306a36Sopenharmony_ci		fi
14362306a36Sopenharmony_ci	done
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cierror=-12
14762306a36Sopenharmony_cipriority=0
14862306a36Sopenharmony_ci# Run with default of ratio=2 for Kselftest run
14962306a36Sopenharmony_ciratio=2
15062306a36Sopenharmony_ciretval=0
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ciwhile getopts e:hp:r: opt; do
15362306a36Sopenharmony_ci	case $opt in
15462306a36Sopenharmony_ci	e)
15562306a36Sopenharmony_ci		error=$OPTARG
15662306a36Sopenharmony_ci		;;
15762306a36Sopenharmony_ci	h)
15862306a36Sopenharmony_ci		echo "Usage $0 [ -e errno ] [ -p notifier-priority ] [ -r percent-of-memory-to-offline ]"
15962306a36Sopenharmony_ci		exit
16062306a36Sopenharmony_ci		;;
16162306a36Sopenharmony_ci	p)
16262306a36Sopenharmony_ci		priority=$OPTARG
16362306a36Sopenharmony_ci		;;
16462306a36Sopenharmony_ci	r)
16562306a36Sopenharmony_ci		ratio=$OPTARG
16662306a36Sopenharmony_ci		if [ "$ratio" -gt 100 ] || [ "$ratio" -lt 0 ]; then
16762306a36Sopenharmony_ci			echo "The percentage should be an integer within 0~100 range"
16862306a36Sopenharmony_ci			exit 1
16962306a36Sopenharmony_ci		fi
17062306a36Sopenharmony_ci		;;
17162306a36Sopenharmony_ci	esac
17262306a36Sopenharmony_cidone
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ciif ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
17562306a36Sopenharmony_ci	echo "error code must be -4095 <= errno < 0" >&2
17662306a36Sopenharmony_ci	exit 1
17762306a36Sopenharmony_cifi
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ciprerequisite
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ciecho "Test scope: $ratio% hotplug memory"
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#
18462306a36Sopenharmony_ci# Online all hot-pluggable memory
18562306a36Sopenharmony_ci#
18662306a36Sopenharmony_cihotpluggable_num=`hotpluggable_offline_memory | wc -l`
18762306a36Sopenharmony_ciecho -e "\t online all hot-pluggable memory in offline state:"
18862306a36Sopenharmony_ciif [ "$hotpluggable_num" -gt 0 ]; then
18962306a36Sopenharmony_ci	for memory in `hotpluggable_offline_memory`; do
19062306a36Sopenharmony_ci		echo "offline->online memory$memory"
19162306a36Sopenharmony_ci		if ! online_memory_expect_success $memory; then
19262306a36Sopenharmony_ci			retval=1
19362306a36Sopenharmony_ci		fi
19462306a36Sopenharmony_ci	done
19562306a36Sopenharmony_cielse
19662306a36Sopenharmony_ci	echo -e "\t\t SKIPPED - no hot-pluggable memory in offline state"
19762306a36Sopenharmony_cifi
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci#
20062306a36Sopenharmony_ci# Offline $ratio percent of hot-pluggable memory
20162306a36Sopenharmony_ci#
20262306a36Sopenharmony_cihotpluggable_num=`hotpluggable_online_memory | wc -l`
20362306a36Sopenharmony_citarget=`echo "a=$hotpluggable_num*$ratio; if ( a%100 ) a/100+1 else a/100" | bc`
20462306a36Sopenharmony_ciecho -e "\t offline $ratio% hot-pluggable memory in online state"
20562306a36Sopenharmony_ciecho -e "\t trying to offline $target out of $hotpluggable_num memory block(s):"
20662306a36Sopenharmony_cifor memory in `hotpluggable_online_memory`; do
20762306a36Sopenharmony_ci	if [ "$target" -gt 0 ]; then
20862306a36Sopenharmony_ci		echo "online->offline memory$memory"
20962306a36Sopenharmony_ci		if offline_memory_expect_success $memory &>/dev/null; then
21062306a36Sopenharmony_ci			target=$(($target - 1))
21162306a36Sopenharmony_ci			echo "-> Success"
21262306a36Sopenharmony_ci		else
21362306a36Sopenharmony_ci			echo "-> Failure"
21462306a36Sopenharmony_ci		fi
21562306a36Sopenharmony_ci	fi
21662306a36Sopenharmony_cidone
21762306a36Sopenharmony_ciif [ "$target" -gt 0 ]; then
21862306a36Sopenharmony_ci	retval=1
21962306a36Sopenharmony_ci	echo -e "\t\t FAILED - unable to offline some memory blocks, device busy?"
22062306a36Sopenharmony_cifi
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci#
22362306a36Sopenharmony_ci# Online all hot-pluggable memory again
22462306a36Sopenharmony_ci#
22562306a36Sopenharmony_cihotpluggable_num=`hotpluggable_offline_memory | wc -l`
22662306a36Sopenharmony_ciecho -e "\t online all hot-pluggable memory in offline state:"
22762306a36Sopenharmony_ciif [ "$hotpluggable_num" -gt 0 ]; then
22862306a36Sopenharmony_ci	for memory in `hotpluggable_offline_memory`; do
22962306a36Sopenharmony_ci		echo "offline->online memory$memory"
23062306a36Sopenharmony_ci		if ! online_memory_expect_success $memory; then
23162306a36Sopenharmony_ci			retval=1
23262306a36Sopenharmony_ci		fi
23362306a36Sopenharmony_ci	done
23462306a36Sopenharmony_cielse
23562306a36Sopenharmony_ci	echo -e "\t\t SKIPPED - no hot-pluggable memory in offline state"
23662306a36Sopenharmony_cifi
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci#
23962306a36Sopenharmony_ci# Test with memory notifier error injection
24062306a36Sopenharmony_ci#
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ciDEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
24362306a36Sopenharmony_ciNOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/memory
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ciprerequisite_extra()
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	msg="skip extra tests:"
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/sbin/modprobe -q -r memory-notifier-error-inject
25062306a36Sopenharmony_ci	/sbin/modprobe -q memory-notifier-error-inject priority=$priority
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if [ ! -d "$DEBUGFS" ]; then
25362306a36Sopenharmony_ci		echo $msg debugfs is not mounted >&2
25462306a36Sopenharmony_ci		exit $retval
25562306a36Sopenharmony_ci	fi
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
25862306a36Sopenharmony_ci		echo $msg memory-notifier-error-inject module is not available >&2
25962306a36Sopenharmony_ci		exit $retval
26062306a36Sopenharmony_ci	fi
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ciecho -e "\t Test with memory notifier error injection"
26462306a36Sopenharmony_ciprerequisite_extra
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci#
26762306a36Sopenharmony_ci# Offline $ratio percent of hot-pluggable memory
26862306a36Sopenharmony_ci#
26962306a36Sopenharmony_ciecho 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
27062306a36Sopenharmony_cifor memory in `hotpluggable_online_memory`; do
27162306a36Sopenharmony_ci	if [ $((RANDOM % 100)) -lt $ratio ]; then
27262306a36Sopenharmony_ci		offline_memory_expect_success $memory &>/dev/null
27362306a36Sopenharmony_ci	fi
27462306a36Sopenharmony_cidone
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci#
27762306a36Sopenharmony_ci# Test memory hot-add error handling (offline => online)
27862306a36Sopenharmony_ci#
27962306a36Sopenharmony_ciecho $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
28062306a36Sopenharmony_cifor memory in `hotpluggable_offline_memory`; do
28162306a36Sopenharmony_ci	if ! online_memory_expect_fail $memory; then
28262306a36Sopenharmony_ci		retval=1
28362306a36Sopenharmony_ci	fi
28462306a36Sopenharmony_cidone
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci#
28762306a36Sopenharmony_ci# Online all hot-pluggable memory
28862306a36Sopenharmony_ci#
28962306a36Sopenharmony_ciecho 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
29062306a36Sopenharmony_cionline_all_offline_memory
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci#
29362306a36Sopenharmony_ci# Test memory hot-remove error handling (online => offline)
29462306a36Sopenharmony_ci#
29562306a36Sopenharmony_ciecho $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
29662306a36Sopenharmony_cifor memory in `hotpluggable_online_memory`; do
29762306a36Sopenharmony_ci	if [ $((RANDOM % 100)) -lt $ratio ]; then
29862306a36Sopenharmony_ci		if ! offline_memory_expect_fail $memory; then
29962306a36Sopenharmony_ci			retval=1
30062306a36Sopenharmony_ci		fi
30162306a36Sopenharmony_ci	fi
30262306a36Sopenharmony_cidone
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ciecho 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
30562306a36Sopenharmony_ci/sbin/modprobe -q -r memory-notifier-error-inject
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci#
30862306a36Sopenharmony_ci# Restore memory before exit
30962306a36Sopenharmony_ci#
31062306a36Sopenharmony_cionline_all_offline_memory
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ciexit $retval
313