test_common.sh 8.4 KB

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