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