1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4UBLK_SKIP_CODE=4 5 6_have_program() { 7 if command -v "$1" >/dev/null 2>&1; then 8 return 0 9 fi 10 return 1 11} 12 13_get_disk_dev_t() { 14 local dev_id=$1 15 local dev 16 local major 17 local minor 18 19 dev=/dev/ublkb"${dev_id}" 20 major="0x"$(stat -c '%t' "$dev") 21 minor="0x"$(stat -c '%T' "$dev") 22 23 echo $(( (major & 0xfff) << 20 | (minor & 0xfffff) )) 24} 25 26_run_fio_verify_io() { 27 fio --name=verify --rw=randwrite --direct=1 --ioengine=libaio \ 28 --bs=8k --iodepth=32 --verify=crc32c --do_verify=1 \ 29 --verify_state_save=0 "$@" > /dev/null 30} 31 32_create_backfile() { 33 local index=$1 34 local new_size=$2 35 local old_file 36 local new_file 37 38 old_file="${UBLK_BACKFILES[$index]}" 39 [ -f "$old_file" ] && rm -f "$old_file" 40 41 new_file=$(mktemp ublk_file_"${new_size}"_XXXXX) 42 truncate -s "${new_size}" "${new_file}" 43 UBLK_BACKFILES["$index"]="$new_file" 44} 45 46_remove_files() { 47 local file 48 49 for file in "${UBLK_BACKFILES[@]}"; do 50 [ -f "$file" ] && rm -f "$file" 51 done 52 [ -f "$UBLK_TMP" ] && rm -f "$UBLK_TMP" 53} 54 55_create_tmp_dir() { 56 local my_file; 57 58 my_file=$(mktemp -d ublk_dir_XXXXX) 59 echo "$my_file" 60} 61 62_remove_tmp_dir() { 63 local dir=$1 64 65 [ -d "$dir" ] && rmdir "$dir" 66} 67 68_mkfs_mount_test() 69{ 70 local dev=$1 71 local err_code=0 72 local mnt_dir; 73 74 mnt_dir=$(_create_tmp_dir) 75 mkfs.ext4 -F "$dev" > /dev/null 2>&1 76 err_code=$? 77 if [ $err_code -ne 0 ]; then 78 return $err_code 79 fi 80 81 mount -t ext4 "$dev" "$mnt_dir" > /dev/null 2>&1 82 umount "$dev" 83 err_code=$? 84 _remove_tmp_dir "$mnt_dir" 85 if [ $err_code -ne 0 ]; then 86 return $err_code 87 fi 88} 89 90_check_root() { 91 local ksft_skip=4 92 93 if [ $UID != 0 ]; then 94 echo please run this as root >&2 95 exit $ksft_skip 96 fi 97} 98 99_remove_ublk_devices() { 100 ${UBLK_PROG} del -a 101 modprobe -r ublk_drv > /dev/null 2>&1 102} 103 104_get_ublk_dev_state() { 105 ${UBLK_PROG} list -n "$1" | grep "state" | awk '{print $11}' 106} 107 108_get_ublk_daemon_pid() { 109 ${UBLK_PROG} list -n "$1" | grep "pid" | awk '{print $7}' 110} 111 112_prep_test() { 113 _check_root 114 local type=$1 115 shift 1 116 modprobe ublk_drv > /dev/null 2>&1 117 UBLK_TMP=$(mktemp ublk_test_XXXXX) 118 [ "$UBLK_TEST_QUIET" -eq 0 ] && echo "ublk $type: $*" 119} 120 121_remove_test_files() 122{ 123 local files=$* 124 125 for file in ${files}; do 126 [ -f "${file}" ] && rm -f "${file}" 127 done 128} 129 130_show_result() 131{ 132 if [ "$UBLK_TEST_SHOW_RESULT" -ne 0 ]; then 133 if [ "$2" -eq 0 ]; then 134 echo "$1 : [PASS]" 135 elif [ "$2" -eq 4 ]; then 136 echo "$1 : [SKIP]" 137 else 138 echo "$1 : [FAIL]" 139 fi 140 fi 141 if [ "$2" -ne 0 ]; then 142 _remove_files 143 exit "$2" 144 fi 145 return 0 146} 147 148# don't call from sub-shell, otherwise can't exit 149_check_add_dev() 150{ 151 local tid=$1 152 local code=$2 153 154 if [ "${code}" -ne 0 ]; then 155 _show_result "${tid}" "${code}" 156 fi 157} 158 159_cleanup_test() { 160 "${UBLK_PROG}" del -a 161 162 _remove_files 163} 164 165_have_feature() 166{ 167 if $UBLK_PROG "features" | grep "$1" > /dev/null 2>&1; then 168 return 0 169 fi 170 return 1 171} 172 173_create_ublk_dev() { 174 local dev_id; 175 local cmd=$1 176 177 shift 1 178 179 if [ ! -c /dev/ublk-control ]; then 180 return ${UBLK_SKIP_CODE} 181 fi 182 if echo "$@" | grep -q "\-z"; then 183 if ! _have_feature "ZERO_COPY"; then 184 return ${UBLK_SKIP_CODE} 185 fi 186 fi 187 188 if ! dev_id=$("${UBLK_PROG}" "$cmd" "$@" | grep "dev id" | awk -F '[ :]' '{print $3}'); then 189 echo "fail to add ublk dev $*" 190 return 255 191 fi 192 udevadm settle 193 194 if [[ "$dev_id" =~ ^[0-9]+$ ]]; then 195 echo "${dev_id}" 196 else 197 return 255 198 fi 199} 200 201_add_ublk_dev() { 202 _create_ublk_dev "add" "$@" 203} 204 205_recover_ublk_dev() { 206 local dev_id 207 local state 208 209 dev_id=$(_create_ublk_dev "recover" "$@") 210 for ((j=0;j<20;j++)); do 211 state=$(_get_ublk_dev_state "${dev_id}") 212 [ "$state" == "LIVE" ] && break 213 sleep 1 214 done 215 echo "$state" 216} 217 218# kill the ublk daemon and return ublk device state 219__ublk_kill_daemon() 220{ 221 local dev_id=$1 222 local exp_state=$2 223 local daemon_pid 224 local state 225 226 daemon_pid=$(_get_ublk_daemon_pid "${dev_id}") 227 state=$(_get_ublk_dev_state "${dev_id}") 228 229 for ((j=0;j<50;j++)); do 230 [ "$state" == "$exp_state" ] && break 231 kill -9 "$daemon_pid" > /dev/null 2>&1 232 sleep 1 233 state=$(_get_ublk_dev_state "${dev_id}") 234 done 235 echo "$state" 236} 237 238__remove_ublk_dev_return() { 239 local dev_id=$1 240 241 ${UBLK_PROG} del -n "${dev_id}" 242 local res=$? 243 udevadm settle 244 return ${res} 245} 246 247__run_io_and_remove() 248{ 249 local dev_id=$1 250 local size=$2 251 local kill_server=$3 252 253 fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio \ 254 --rw=readwrite --iodepth=256 --size="${size}" --numjobs=4 \ 255 --runtime=20 --time_based > /dev/null 2>&1 & 256 sleep 2 257 if [ "${kill_server}" = "yes" ]; then 258 local state 259 state=$(__ublk_kill_daemon "${dev_id}" "DEAD") 260 if [ "$state" != "DEAD" ]; then 261 echo "device isn't dead($state) after killing daemon" 262 return 255 263 fi 264 fi 265 if ! __remove_ublk_dev_return "${dev_id}"; then 266 echo "delete dev ${dev_id} failed" 267 return 255 268 fi 269 wait 270} 271 272run_io_and_remove() 273{ 274 local size=$1 275 local dev_id 276 shift 1 277 278 dev_id=$(_add_ublk_dev "$@") 279 _check_add_dev "$TID" $? 280 281 [ "$UBLK_TEST_QUIET" -eq 0 ] && echo "run ublk IO vs. remove device(ublk add $*)" 282 if ! __run_io_and_remove "$dev_id" "${size}" "no"; then 283 echo "/dev/ublkc$dev_id isn't removed" 284 exit 255 285 fi 286} 287 288run_io_and_kill_daemon() 289{ 290 local size=$1 291 local dev_id 292 shift 1 293 294 dev_id=$(_add_ublk_dev "$@") 295 _check_add_dev "$TID" $? 296 297 [ "$UBLK_TEST_QUIET" -eq 0 ] && echo "run ublk IO vs kill ublk server(ublk add $*)" 298 if ! __run_io_and_remove "$dev_id" "${size}" "yes"; then 299 echo "/dev/ublkc$dev_id isn't removed res ${res}" 300 exit 255 301 fi 302} 303 304run_io_and_recover() 305{ 306 local state 307 local dev_id 308 309 dev_id=$(_add_ublk_dev "$@") 310 _check_add_dev "$TID" $? 311 312 fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio \ 313 --rw=readwrite --iodepth=256 --size="${size}" --numjobs=4 \ 314 --runtime=20 --time_based > /dev/null 2>&1 & 315 sleep 4 316 317 state=$(__ublk_kill_daemon "${dev_id}" "QUIESCED") 318 if [ "$state" != "QUIESCED" ]; then 319 echo "device isn't quiesced($state) after killing daemon" 320 return 255 321 fi 322 323 state=$(_recover_ublk_dev -n "$dev_id" "$@") 324 if [ "$state" != "LIVE" ]; then 325 echo "faile to recover to LIVE($state)" 326 return 255 327 fi 328 329 if ! __remove_ublk_dev_return "${dev_id}"; then 330 echo "delete dev ${dev_id} failed" 331 return 255 332 fi 333 wait 334} 335 336 337_ublk_test_top_dir() 338{ 339 cd "$(dirname "$0")" && pwd 340} 341 342UBLK_PROG=$(_ublk_test_top_dir)/kublk 343UBLK_TEST_QUIET=1 344UBLK_TEST_SHOW_RESULT=1 345UBLK_BACKFILES=() 346export UBLK_PROG 347export UBLK_TEST_QUIET 348export UBLK_TEST_SHOW_RESULT 349