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 137error=-12 138priority=0 139# Run with default of ratio=2 for Kselftest run 140ratio=2 141retval=0 142 143while getopts e:hp:r: opt; do 144 case $opt in 145 e) 146 error=$OPTARG 147 ;; 148 h) 149 echo "Usage $0 [ -e errno ] [ -p notifier-priority ] [ -r percent-of-memory-to-offline ]" 150 exit 151 ;; 152 p) 153 priority=$OPTARG 154 ;; 155 r) 156 ratio=$OPTARG 157 if [ "$ratio" -gt 100 ] || [ "$ratio" -lt 0 ]; then 158 echo "The percentage should be an integer within 0~100 range" 159 exit 1 160 fi 161 ;; 162 esac 163done 164 165if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then 166 echo "error code must be -4095 <= errno < 0" >&2 167 exit 1 168fi 169 170prerequisite 171 172echo "Test scope: $ratio% hotplug memory" 173 174# 175# Online all hot-pluggable memory 176# 177hotpluggable_num=`hotpluggable_offline_memory | wc -l` 178echo -e "\t online all hot-pluggable memory in offline state:" 179if [ "$hotpluggable_num" -gt 0 ]; then 180 for memory in `hotpluggable_offline_memory`; do 181 echo "offline->online memory$memory" 182 if ! online_memory_expect_success $memory; then 183 retval=1 184 fi 185 done 186else 187 echo -e "\t\t SKIPPED - no hot-pluggable memory in offline state" 188fi 189 190# 191# Offline $ratio percent of hot-pluggable memory 192# 193hotpluggable_num=`hotpluggable_online_memory | wc -l` 194target=`echo "a=$hotpluggable_num*$ratio; if ( a%100 ) a/100+1 else a/100" | bc` 195echo -e "\t offline $ratio% hot-pluggable memory in online state" 196echo -e "\t trying to offline $target out of $hotpluggable_num memory block(s):" 197for memory in `hotpluggable_online_memory`; do 198 if [ "$target" -gt 0 ]; then 199 echo "online->offline memory$memory" 200 if offline_memory_expect_success $memory; then 201 target=$(($target - 1)) 202 fi 203 fi 204done 205if [ "$target" -gt 0 ]; then 206 retval=1 207 echo -e "\t\t FAILED - unable to offline some memory blocks, device busy?" 208fi 209 210# 211# Online all hot-pluggable memory again 212# 213hotpluggable_num=`hotpluggable_offline_memory | wc -l` 214echo -e "\t online all hot-pluggable memory in offline state:" 215if [ "$hotpluggable_num" -gt 0 ]; then 216 for memory in `hotpluggable_offline_memory`; do 217 echo "offline->online memory$memory" 218 if ! online_memory_expect_success $memory; then 219 retval=1 220 fi 221 done 222else 223 echo -e "\t\t SKIPPED - no hot-pluggable memory in offline state" 224fi 225 226# 227# Test with memory notifier error injection 228# 229 230DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'` 231NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/memory 232 233prerequisite_extra() 234{ 235 msg="skip extra tests:" 236 237 /sbin/modprobe -q -r memory-notifier-error-inject 238 /sbin/modprobe -q memory-notifier-error-inject priority=$priority 239 240 if [ ! -d "$DEBUGFS" ]; then 241 echo $msg debugfs is not mounted >&2 242 exit $retval 243 fi 244 245 if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then 246 echo $msg memory-notifier-error-inject module is not available >&2 247 exit $retval 248 fi 249} 250 251echo -e "\t Test with memory notifier error injection" 252prerequisite_extra 253 254# 255# Offline $ratio percent of hot-pluggable memory 256# 257echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error 258for memory in `hotpluggable_online_memory`; do 259 if [ $((RANDOM % 100)) -lt $ratio ]; then 260 offline_memory_expect_success $memory 261 fi 262done 263 264# 265# Test memory hot-add error handling (offline => online) 266# 267echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error 268for memory in `hotpluggable_offline_memory`; do 269 online_memory_expect_fail $memory 270done 271 272# 273# Online all hot-pluggable memory 274# 275echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error 276for memory in `hotpluggable_offline_memory`; do 277 online_memory_expect_success $memory 278done 279 280# 281# Test memory hot-remove error handling (online => offline) 282# 283echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error 284for memory in `hotpluggable_online_memory`; do 285 offline_memory_expect_fail $memory 286done 287 288echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error 289/sbin/modprobe -q -r memory-notifier-error-inject 290 291exit $retval 292