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