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=$(stat -c '%Hr' "$dev") 21 minor=$(stat -c '%Lr' "$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_TEST_QUIET" -eq 0 ] && echo "ublk $type: $*" 118} 119 120_remove_test_files() 121{ 122 local files=$* 123 124 for file in ${files}; do 125 [ -f "${file}" ] && rm -f "${file}" 126 done 127} 128 129_show_result() 130{ 131 if [ "$UBLK_TEST_SHOW_RESULT" -ne 0 ]; then 132 if [ "$2" -eq 0 ]; then 133 echo "$1 : [PASS]" 134 elif [ "$2" -eq 4 ]; then 135 echo "$1 : [SKIP]" 136 else 137 echo "$1 : [FAIL]" 138 fi 139 fi 140 if [ "$2" -ne 0 ]; then 141 _remove_files 142 exit "$2" 143 fi 144 return 0 145} 146 147# don't call from sub-shell, otherwise can't exit 148_check_add_dev() 149{ 150 local tid=$1 151 local code=$2 152 153 if [ "${code}" -ne 0 ]; then 154 _show_result "${tid}" "${code}" 155 fi 156} 157 158_cleanup_test() { 159 "${UBLK_PROG}" del -a 160 161 _remove_files 162} 163 164_have_feature() 165{ 166 if $UBLK_PROG "features" | grep "$1" > /dev/null 2>&1; then 167 return 0 168 fi 169 return 1 170} 171 172_add_ublk_dev() { 173 local dev_id; 174 175 if [ ! -c /dev/ublk-control ]; then 176 return ${UBLK_SKIP_CODE} 177 fi 178 if echo "$@" | grep -q "\-z"; then 179 if ! _have_feature "ZERO_COPY"; then 180 return ${UBLK_SKIP_CODE} 181 fi 182 fi 183 184 if ! dev_id=$("${UBLK_PROG}" add "$@" | grep "dev id" | awk -F '[ :]' '{print $3}'); then 185 echo "fail to add ublk dev $*" 186 return 255 187 fi 188 udevadm settle 189 190 if [[ "$dev_id" =~ ^[0-9]+$ ]]; then 191 echo "${dev_id}" 192 else 193 return 255 194 fi 195} 196 197# kill the ublk daemon and return ublk device state 198__ublk_kill_daemon() 199{ 200 local dev_id=$1 201 local exp_state=$2 202 local daemon_pid 203 local state 204 205 daemon_pid=$(_get_ublk_daemon_pid "${dev_id}") 206 state=$(_get_ublk_dev_state "${dev_id}") 207 208 for ((j=0;j<50;j++)); do 209 [ "$state" == "$exp_state" ] && break 210 kill -9 "$daemon_pid" > /dev/null 2>&1 211 sleep 1 212 state=$(_get_ublk_dev_state "${dev_id}") 213 done 214 echo "$state" 215} 216 217__remove_ublk_dev_return() { 218 local dev_id=$1 219 220 ${UBLK_PROG} del -n "${dev_id}" 221 local res=$? 222 udevadm settle 223 return ${res} 224} 225 226__run_io_and_remove() 227{ 228 local dev_id=$1 229 local size=$2 230 local kill_server=$3 231 232 fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio \ 233 --rw=readwrite --iodepth=256 --size="${size}" --numjobs=4 \ 234 --runtime=20 --time_based > /dev/null 2>&1 & 235 sleep 2 236 if [ "${kill_server}" = "yes" ]; then 237 local state 238 state=$(__ublk_kill_daemon "${dev_id}" "DEAD") 239 if [ "$state" != "DEAD" ]; then 240 echo "device isn't dead($state) after killing daemon" 241 return 255 242 fi 243 fi 244 if ! __remove_ublk_dev_return "${dev_id}"; then 245 echo "delete dev ${dev_id} failed" 246 return 255 247 fi 248 wait 249} 250 251run_io_and_remove() 252{ 253 local size=$1 254 local dev_id 255 shift 1 256 257 dev_id=$(_add_ublk_dev "$@") 258 _check_add_dev "$TID" $? 259 260 [ "$UBLK_TEST_QUIET" -eq 0 ] && echo "run ublk IO vs. remove device(ublk add $*)" 261 if ! __run_io_and_remove "$dev_id" "${size}" "no"; then 262 echo "/dev/ublkc$dev_id isn't removed" 263 exit 255 264 fi 265} 266 267run_io_and_kill_daemon() 268{ 269 local size=$1 270 local dev_id 271 shift 1 272 273 dev_id=$(_add_ublk_dev "$@") 274 _check_add_dev "$TID" $? 275 276 [ "$UBLK_TEST_QUIET" -eq 0 ] && echo "run ublk IO vs kill ublk server(ublk add $*)" 277 if ! __run_io_and_remove "$dev_id" "${size}" "yes"; then 278 echo "/dev/ublkc$dev_id isn't removed res ${res}" 279 exit 255 280 fi 281} 282 283_ublk_test_top_dir() 284{ 285 cd "$(dirname "$0")" && pwd 286} 287 288UBLK_TMP=$(mktemp ublk_test_XXXXX) 289UBLK_PROG=$(_ublk_test_top_dir)/kublk 290UBLK_TEST_QUIET=1 291UBLK_TEST_SHOW_RESULT=1 292UBLK_BACKFILES=() 293export UBLK_PROG 294export UBLK_TEST_QUIET 295export UBLK_TEST_SHOW_RESULT 296