Home | History | Annotate | Download | only in memory-hotplug
      1 #!/bin/bash
      2 # SPDX-License-Identifier: GPL-2.0
      3 
      4 SYSFS=
      5 
      6 prerequisite()
      7 {
      8 	msg="skip all tests:"
      9 
     10 	if [ $UID != 0 ]; then
     11 		echo $msg must be run as root >&2
     12 		exit 0
     13 	fi
     14 
     15 	SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
     16 
     17 	if [ ! -d "$SYSFS" ]; then
     18 		echo $msg sysfs is not mounted >&2
     19 		exit 0
     20 	fi
     21 
     22 	if ! ls $SYSFS/devices/system/memory/memory* > /dev/null 2>&1; then
     23 		echo $msg memory hotplug is not supported >&2
     24 		exit 0
     25 	fi
     26 
     27 	if ! grep -q 1 $SYSFS/devices/system/memory/memory*/removable; then
     28 		echo $msg no hot-pluggable memory >&2
     29 		exit 0
     30 	fi
     31 }
     32 
     33 #
     34 # list all hot-pluggable memory
     35 #
     36 hotpluggable_memory()
     37 {
     38 	local state=${1:-.\*}
     39 
     40 	for memory in $SYSFS/devices/system/memory/memory*; do
     41 		if grep -q 1 $memory/removable &&
     42 		   grep -q $state $memory/state; then
     43 			echo ${memory##/*/memory}
     44 		fi
     45 	done
     46 }
     47 
     48 hotpluggable_offline_memory()
     49 {
     50 	hotpluggable_memory offline
     51 }
     52 
     53 hotpluggable_online_memory()
     54 {
     55 	hotpluggable_memory online
     56 }
     57 
     58 memory_is_online()
     59 {
     60 	grep -q online $SYSFS/devices/system/memory/memory$1/state
     61 }
     62 
     63 memory_is_offline()
     64 {
     65 	grep -q offline $SYSFS/devices/system/memory/memory$1/state
     66 }
     67 
     68 online_memory()
     69 {
     70 	echo online > $SYSFS/devices/system/memory/memory$1/state
     71 }
     72 
     73 offline_memory()
     74 {
     75 	echo offline > $SYSFS/devices/system/memory/memory$1/state
     76 }
     77 
     78 online_memory_expect_success()
     79 {
     80 	local memory=$1
     81 
     82 	if ! online_memory $memory; then
     83 		echo $FUNCNAME $memory: unexpected fail >&2
     84 		return 1
     85 	elif ! memory_is_online $memory; then
     86 		echo $FUNCNAME $memory: unexpected offline >&2
     87 		return 1
     88 	fi
     89 	return 0
     90 }
     91 
     92 online_memory_expect_fail()
     93 {
     94 	local memory=$1
     95 
     96 	if online_memory $memory 2> /dev/null; then
     97 		echo $FUNCNAME $memory: unexpected success >&2
     98 		return 1
     99 	elif ! memory_is_offline $memory; then
    100 		echo $FUNCNAME $memory: unexpected online >&2
    101 		return 1
    102 	fi
    103 	return 0
    104 }
    105 
    106 offline_memory_expect_success()
    107 {
    108 	local memory=$1
    109 
    110 	if ! offline_memory $memory; then
    111 		echo $FUNCNAME $memory: unexpected fail >&2
    112 		return 1
    113 	elif ! memory_is_offline $memory; then
    114 		echo $FUNCNAME $memory: unexpected offline >&2
    115 		return 1
    116 	fi
    117 	return 0
    118 }
    119 
    120 offline_memory_expect_fail()
    121 {
    122 	local memory=$1
    123 
    124 	if offline_memory $memory 2> /dev/null; then
    125 		echo $FUNCNAME $memory: unexpected success >&2
    126 		return 1
    127 	elif ! memory_is_online $memory; then
    128 		echo $FUNCNAME $memory: unexpected offline >&2
    129 		return 1
    130 	fi
    131 	return 0
    132 }
    133 
    134 error=-12
    135 priority=0
    136 ratio=10
    137 retval=0
    138 
    139 while getopts e:hp:r: opt; do
    140 	case $opt in
    141 	e)
    142 		error=$OPTARG
    143 		;;
    144 	h)
    145 		echo "Usage $0 [ -e errno ] [ -p notifier-priority ] [ -r percent-of-memory-to-offline ]"
    146 		exit
    147 		;;
    148 	p)
    149 		priority=$OPTARG
    150 		;;
    151 	r)
    152 		ratio=$OPTARG
    153 		if [ "$ratio" -gt 100 ] || [ "$ratio" -lt 0 ]; then
    154 			echo "The percentage should be an integer within 0~100 range"
    155 			exit 1
    156 		fi
    157 		;;
    158 	esac
    159 done
    160 
    161 if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
    162 	echo "error code must be -4095 <= errno < 0" >&2
    163 	exit 1
    164 fi
    165 
    166 prerequisite
    167 
    168 echo "Test scope: $ratio% hotplug memory"
    169 
    170 #
    171 # Online all hot-pluggable memory
    172 #
    173 hotpluggable_num=`hotpluggable_offline_memory | wc -l`
    174 echo -e "\t online all hot-pluggable memory in offline state:"
    175 if [ "$hotpluggable_num" -gt 0 ]; then
    176 	for memory in `hotpluggable_offline_memory`; do
    177 		echo "offline->online memory$memory"
    178 		if ! online_memory_expect_success $memory; then
    179 			retval=1
    180 		fi
    181 	done
    182 else
    183 	echo -e "\t\t SKIPPED - no hot-pluggable memory in offline state"
    184 fi
    185 
    186 #
    187 # Offline $ratio percent of hot-pluggable memory
    188 #
    189 hotpluggable_num=`hotpluggable_online_memory | wc -l`
    190 target=`echo "a=$hotpluggable_num*$ratio; if ( a%100 ) a/100+1 else a/100" | bc`
    191 echo -e "\t offline $ratio% hot-pluggable memory in online state"
    192 echo -e "\t trying to offline $target out of $hotpluggable_num memory block(s):"
    193 for memory in `hotpluggable_online_memory`; do
    194 	if [ "$target" -gt 0 ]; then
    195 		echo "online->offline memory$memory"
    196 		if offline_memory_expect_success $memory; then
    197 			target=$(($target - 1))
    198 		fi
    199 	fi
    200 done
    201 if [ "$target" -gt 0 ]; then
    202 	retval=1
    203 	echo -e "\t\t FAILED - unable to offline some memory blocks, device busy?"
    204 fi
    205 
    206 #
    207 # Online all hot-pluggable memory again
    208 #
    209 hotpluggable_num=`hotpluggable_offline_memory | wc -l`
    210 echo -e "\t online all hot-pluggable memory in offline state:"
    211 if [ "$hotpluggable_num" -gt 0 ]; then
    212 	for memory in `hotpluggable_offline_memory`; do
    213 		echo "offline->online memory$memory"
    214 		if ! online_memory_expect_success $memory; then
    215 			retval=1
    216 		fi
    217 	done
    218 else
    219 	echo -e "\t\t SKIPPED - no hot-pluggable memory in offline state"
    220 fi
    221 
    222 #
    223 # Test with memory notifier error injection
    224 #
    225 
    226 DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
    227 NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/memory
    228 
    229 prerequisite_extra()
    230 {
    231 	msg="skip extra tests:"
    232 
    233 	/sbin/modprobe -q -r memory-notifier-error-inject
    234 	/sbin/modprobe -q memory-notifier-error-inject priority=$priority
    235 
    236 	if [ ! -d "$DEBUGFS" ]; then
    237 		echo $msg debugfs is not mounted >&2
    238 		exit $retval
    239 	fi
    240 
    241 	if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
    242 		echo $msg memory-notifier-error-inject module is not available >&2
    243 		exit $retval
    244 	fi
    245 }
    246 
    247 echo -e "\t Test with memory notifier error injection"
    248 prerequisite_extra
    249 
    250 #
    251 # Offline $ratio percent of hot-pluggable memory
    252 #
    253 echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
    254 for memory in `hotpluggable_online_memory`; do
    255 	if [ $((RANDOM % 100)) -lt $ratio ]; then
    256 		offline_memory_expect_success $memory
    257 	fi
    258 done
    259 
    260 #
    261 # Test memory hot-add error handling (offline => online)
    262 #
    263 echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
    264 for memory in `hotpluggable_offline_memory`; do
    265 	online_memory_expect_fail $memory
    266 done
    267 
    268 #
    269 # Online all hot-pluggable memory
    270 #
    271 echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
    272 for memory in `hotpluggable_offline_memory`; do
    273 	online_memory_expect_success $memory
    274 done
    275 
    276 #
    277 # Test memory hot-remove error handling (online => offline)
    278 #
    279 echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
    280 for memory in `hotpluggable_online_memory`; do
    281 	offline_memory_expect_fail $memory
    282 done
    283 
    284 echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
    285 /sbin/modprobe -q -r memory-notifier-error-inject
    286 
    287 exit $retval
    288