Merge branch 'filelock_assert_fix' of https://github.com/bardavid/fio into master
[fio.git] / t / zbd / test-zbd-support
1 #!/bin/bash
2 #
3 # Copyright (C) 2018 Western Digital Corporation or its affiliates.
4 #
5 # This file is released under the GPL.
6
7 usage() {
8     echo "Usage: $(basename "$0") [-d] [-e] [-l] [-r] [-v] [-t <test>] [-z] <SMR drive device node>"
9 }
10
11 max() {
12     if [ "$1" -gt "$2" ]; then
13         echo "$1"
14     else
15         echo "$2"
16     fi
17 }
18
19 min() {
20     if [ "$1" -lt "$2" ]; then
21         echo "$1"
22     else
23         echo "$2"
24     fi
25 }
26
27 ioengine() {
28         if [ -n "$use_libzbc" ]; then
29                 echo -n "--ioengine=libzbc"
30         else
31                 echo -n "--ioengine=$1"
32         fi
33 }
34
35 set_io_scheduler() {
36     local dev=$1 sched=$2
37
38     [ -e "/sys/block/$dev" ] || return $?
39     if [ -e "/sys/block/$dev/mq" ]; then
40         case "$sched" in
41             noop)        sched=none;;
42             deadline)    sched=mq-deadline;;
43         esac
44     else
45         case "$sched" in
46             none)        sched=noop;;
47             mq-deadline) sched=deadline;;
48         esac
49     fi
50
51     echo "$sched" >"/sys/block/$dev/queue/scheduler"
52 }
53
54 check_read() {
55     local read
56
57     read=$(fio_read <"${logfile}.${test_number}")
58     echo "read: $read <> $1" >> "${logfile}.${test_number}"
59     [ "$read" = "$1" ]
60 }
61
62 check_written() {
63     local written
64
65     written=$(fio_written <"${logfile}.${test_number}")
66     echo "written: $written <> $1" >> "${logfile}.${test_number}"
67     [ "$written" = "$1" ]
68 }
69
70 # Compare the reset count from the log file with reset count $2 using operator
71 # $1 (=, -ge, -gt, -le, -lt).
72 check_reset_count() {
73     local reset_count
74
75     reset_count=$(fio_reset_count <"${logfile}.${test_number}")
76     echo "reset_count: test $reset_count $1 $2" >> "${logfile}.${test_number}"
77     eval "[ '$reset_count' '$1' '$2' ]"
78 }
79
80 # Check log for failed assertions and crashes. Without these checks,
81 # a test can succeed even when these events happen, but it must fail.
82 check_log() {
83      [ ! -f "${logfile}.${1}" ] && return 0
84      ! grep -q -e "Assertion " -e "Aborted " "${logfile}.${1}"
85 }
86
87 # Whether or not $1 (/dev/...) is a SCSI device.
88 is_scsi_device() {
89     local d f
90
91     d=$(basename "$dev")
92     for f in /sys/class/scsi_device/*/device/block/"$d"; do
93         [ -e "$f" ] && return 0
94     done
95     return 1
96 }
97
98 run_fio() {
99     local fio opts
100
101     fio=$(dirname "$0")/../../fio
102
103     opts=("--max-jobs=16" "--aux-path=/tmp" "--allow_file_create=0" \
104           "--significant_figures=10" "$@")
105     opts+=(${var_opts[@]})
106     { echo; echo "fio ${opts[*]}"; echo; } >>"${logfile}.${test_number}"
107
108     "${dynamic_analyzer[@]}" "$fio" "${opts[@]}"
109 }
110
111 run_one_fio_job() {
112     local r
113
114     r=$(((RANDOM << 16) | RANDOM))
115     run_fio --name="$dev" --filename="$dev" "$@" --randseed="$r"        \
116             --thread=1 --direct=1
117 }
118
119 write_and_run_one_fio_job() {
120     local r
121     local write_offset="${1}"
122     local write_size="${2}"
123
124     shift 2
125     r=$(((RANDOM << 16) | RANDOM))
126     run_fio --filename="$dev" --randseed="$r"  --name="write_job" --rw=write \
127             "$(ioengine "psync")" --bs="${logical_block_size}" \
128             --zonemode=zbd --zonesize="${zone_size}" --thread=1 --direct=1 \
129             --offset="${write_offset}" --size="${write_size}" \
130             --name="$dev" --wait_for="write_job" "$@" --thread=1 --direct=1
131 }
132
133 # Run fio on the first four sequential zones of the disk.
134 run_fio_on_seq() {
135     local opts=()
136
137     opts+=("--offset=$((first_sequential_zone_sector * 512))")
138     opts+=("--size=$((4 * zone_size))" "--zonemode=zbd")
139     if [ -z "$is_zbd" ]; then
140         opts+=("--zonesize=${zone_size}")
141     fi
142     run_one_fio_job "${opts[@]}" "$@"
143 }
144
145 # Check whether buffered writes are refused.
146 test1() {
147     run_fio --name=job1 --filename="$dev" --rw=write --direct=0 --bs=4K \
148             "$(ioengine "psync")" --size="${zone_size}" --thread=1      \
149             --zonemode=zbd --zonesize="${zone_size}" 2>&1 |
150         tee -a "${logfile}.${test_number}" |
151         grep -q 'Using direct I/O is mandatory for writing to ZBD drives'
152     local fio_rc=${PIPESTATUS[0]} grep_rc=${PIPESTATUS[2]}
153     case "$fio_rc" in
154         0|1) ;;
155         *)   return "$fio_rc"
156     esac
157     if [ -n "$is_zbd" ]; then
158         [ "$grep_rc" = 0 ]
159     else
160         [ "$grep_rc" != 0 ]
161     fi
162 }
163
164 # Block size exceeds zone size.
165 test2() {
166     local bs off opts=() rc
167
168     off=$(((first_sequential_zone_sector + 2 * sectors_per_zone) * 512))
169     bs=$((2 * zone_size))
170     opts+=("$(ioengine "psync")")
171     opts+=("--name=job1" "--filename=$dev" "--rw=write" "--direct=1")
172     opts+=("--zonemode=zbd" "--offset=$off" "--bs=$bs" "--size=$bs")
173     if [ -z "$is_zbd" ]; then
174         opts+=("--zonesize=${zone_size}")
175     fi
176     run_fio "${opts[@]}" >> "${logfile}.${test_number}" 2>&1 || return $?
177     ! grep -q 'WRITE:' "${logfile}.${test_number}"
178 }
179
180 # Run fio against an empty zone. This causes fio to report "No I/O performed".
181 test3() {
182     local off opts=() rc
183
184     off=$((first_sequential_zone_sector * 512 + 128 * zone_size))
185     size=$((zone_size))
186     [ -n "$is_zbd" ] && reset_zone "$dev" $((off / 512))
187     opts+=("--name=$dev" "--filename=$dev" "--offset=$off" "--bs=4K")
188     opts+=("--size=$size" "--zonemode=zbd")
189     opts+=("$(ioengine "psync")" "--rw=read" "--direct=1" "--thread=1")
190     if [ -z "$is_zbd" ]; then
191         opts+=("--zonesize=${zone_size}")
192     fi
193     run_fio "${opts[@]}" >> "${logfile}.${test_number}" 2>&1 || return $?
194     ! grep -q 'READ:' "${logfile}.${test_number}"
195 }
196
197 # Run fio with --read_beyond_wp=1 against an empty zone.
198 test4() {
199     local off opts=()
200
201     off=$((first_sequential_zone_sector * 512 + 129 * zone_size))
202     size=$((zone_size))
203     [ -n "$is_zbd" ] && reset_zone "$dev" $((off / 512))
204     opts+=("--name=$dev" "--filename=$dev" "--offset=$off" "--bs=$size")
205     opts+=("--size=$size" "--thread=1" "--read_beyond_wp=1")
206     opts+=("$(ioengine "psync")" "--rw=read" "--direct=1" "--disable_lat=1")
207     opts+=("--zonemode=zbd" "--zonesize=${zone_size}")
208     run_fio "${opts[@]}" >> "${logfile}.${test_number}" 2>&1 || return $?
209     check_read $size || return $?
210 }
211
212 # Sequential write to sequential zones.
213 test5() {
214     local size off capacity
215
216     off=$((first_sequential_zone_sector * 512))
217     capacity=$(total_zone_capacity 4 $off $dev)
218     size=$((4 * zone_size))
219     run_fio_on_seq "$(ioengine "psync")" --iodepth=1 --rw=write \
220                    --bs="$(max $((zone_size / 64)) "$logical_block_size")"\
221                    --do_verify=1 --verify=md5                           \
222                    >>"${logfile}.${test_number}" 2>&1 || return $?
223     check_written $capacity || return $?
224     check_read $capacity || return $?
225 }
226
227 # Sequential read from sequential zones.
228 test6() {
229     local size off capacity
230
231     off=$((first_sequential_zone_sector * 512))
232     capacity=$(total_zone_capacity 4 $off $dev)
233     size=$((4 * zone_size))
234     write_and_run_one_fio_job \
235             $((first_sequential_zone_sector * 512)) "${size}" \
236             --offset="${off}" \
237             --size="${size}" --zonemode=zbd --zonesize="${zone_size}" \
238             "$(ioengine "psync")" --iodepth=1 --rw=read \
239             --bs="$(max $((zone_size / 64)) "$logical_block_size")" \
240             >>"${logfile}.${test_number}" 2>&1 || return $?
241     check_read $capacity || return $?
242 }
243
244 # Random write to sequential zones, libaio, queue depth 1.
245 test7() {
246     local size=$((zone_size))
247     local off capacity
248
249     off=$((first_sequential_zone_sector * 512))
250     capacity=$(total_zone_capacity 1 $off $dev)
251     run_fio_on_seq "$(ioengine "libaio")" --iodepth=1 --rw=randwrite    \
252                    --bs="$(min 16384 "${zone_size}")"                   \
253                    --do_verify=1 --verify=md5 --size="$size"            \
254                    >>"${logfile}.${test_number}" 2>&1 || return $?
255     check_written $capacity || return $?
256     check_read $capacity || return $?
257 }
258
259 # Random write to sequential zones, libaio, queue depth 64.
260 test8() {
261     local size off capacity
262
263     size=$((4 * zone_size))
264     off=$((first_sequential_zone_sector * 512))
265     capacity=$(total_zone_capacity 4 $off $dev)
266     run_fio_on_seq "$(ioengine "libaio")" --iodepth=64 --rw=randwrite   \
267                    --bs="$(min 16384 "${zone_size}")"                   \
268                    --do_verify=1 --verify=md5                           \
269                    >>"${logfile}.${test_number}" 2>&1 || return $?
270     check_written $capacity || return $?
271     check_read $capacity || return $?
272 }
273
274 # Random write to sequential zones, sg, queue depth 1.
275 test9() {
276     local size
277
278     if ! is_scsi_device "$dev"; then
279         echo "$dev is not a SCSI device" >>"${logfile}.${test_number}"
280         return 0
281     fi
282
283     size=$((4 * zone_size))
284     run_fio_on_seq --ioengine=sg                                        \
285                    --iodepth=1 --rw=randwrite --bs=16K                  \
286                    --do_verify=1 --verify=md5                           \
287                    >>"${logfile}.${test_number}" 2>&1 || return $?
288     check_written $size || return $?
289     check_read $size || return $?
290 }
291
292 # Random write to sequential zones, sg, queue depth 64.
293 test10() {
294     local size
295
296     if ! is_scsi_device "$dev"; then
297         echo "$dev is not a SCSI device" >>"${logfile}.${test_number}"
298         return 0
299     fi
300
301     size=$((4 * zone_size))
302     run_fio_on_seq --ioengine=sg                                        \
303                    --iodepth=64 --rw=randwrite --bs=16K                 \
304                    --do_verify=1 --verify=md5                           \
305                    >>"${logfile}.${test_number}" 2>&1 || return $?
306     check_written $size || return $?
307     check_read $size || return $?
308 }
309
310 # Random write to sequential zones, libaio, queue depth 64, random block size.
311 test11() {
312     local size off capacity
313
314     size=$((4 * zone_size))
315     off=$((first_sequential_zone_sector * 512))
316     capacity=$(total_zone_capacity 4 $off $dev)
317     run_fio_on_seq "$(ioengine "libaio")" --iodepth=64 --rw=randwrite   \
318                    --bsrange=4K-64K --do_verify=1 --verify=md5          \
319                    --debug=zbd >>"${logfile}.${test_number}" 2>&1 || return $?
320     check_written $capacity || return $?
321     check_read $capacity || return $?
322 }
323
324 # Random write to sequential zones, libaio, queue depth 64, max 1 open zone.
325 test12() {
326     local size off capacity
327
328     size=$((8 * zone_size))
329     off=$((first_sequential_zone_sector * 512))
330     capacity=$(total_zone_capacity 8 $off $dev)
331     run_fio_on_seq "$(ioengine "libaio")" --iodepth=64 --rw=randwrite --bs=16K \
332                    --max_open_zones=1 --size=$size --do_verify=1 --verify=md5 \
333                    --debug=zbd >>"${logfile}.${test_number}" 2>&1 || return $?
334     check_written $capacity || return $?
335     check_read $capacity || return $?
336 }
337
338 # Random write to sequential zones, libaio, queue depth 64, max 4 open zones.
339 test13() {
340     local size off capacity
341
342     size=$((8 * zone_size))
343     off=$((first_sequential_zone_sector * 512))
344     capacity=$(total_zone_capacity 8 $off $dev)
345     run_fio_on_seq "$(ioengine "libaio")" --iodepth=64 --rw=randwrite --bs=16K \
346                    --max_open_zones=4 --size=$size --do_verify=1 --verify=md5 \
347                    --debug=zbd                                                \
348                    >>"${logfile}.${test_number}" 2>&1 || return $?
349     check_written $capacity || return $?
350     check_read $capacity || return $?
351 }
352
353 # Random write to conventional zones.
354 test14() {
355     local size
356
357     size=$((16 * 2**20)) # 20 MB
358     if [ $size -gt $((first_sequential_zone_sector * 512)) ]; then
359         echo "$dev does not have enough sequential zones" \
360              >>"${logfile}.${test_number}"
361         return 0
362     fi
363     run_one_fio_job "$(ioengine "libaio")" --iodepth=64 --rw=randwrite --bs=16K \
364                     --zonemode=zbd --zonesize="${zone_size}" --do_verify=1 \
365                     --verify=md5 --size=$size                              \
366                     >>"${logfile}.${test_number}" 2>&1 || return $?
367     check_written $((size)) || return $?
368     check_read $((size)) || return $?
369 }
370
371 # Sequential read on a mix of empty and full zones.
372 test15() {
373     local i off size
374     local w_off w_size w_capacity
375
376     for ((i=0;i<4;i++)); do
377         [ -n "$is_zbd" ] &&
378             reset_zone "$dev" $((first_sequential_zone_sector +
379                                  i*sectors_per_zone))
380     done
381     w_off=$(((first_sequential_zone_sector + 2 * sectors_per_zone) * 512))
382     w_size=$((2 * zone_size))
383     w_capacity=$(total_zone_capacity 2 $w_off $dev)
384     off=$((first_sequential_zone_sector * 512))
385     size=$((4 * zone_size))
386     write_and_run_one_fio_job "${w_off}" "${w_size}" \
387                     "$(ioengine "psync")" --rw=read --bs=$((zone_size / 16)) \
388                     --zonemode=zbd --zonesize="${zone_size}" --offset=$off \
389                     --size=$((size)) >>"${logfile}.${test_number}" 2>&1 ||
390         return $?
391     check_written $((w_capacity)) || return $?
392     check_read $((w_capacity))
393 }
394
395 # Random read on a mix of empty and full zones.
396 test16() {
397     local off size
398     local i w_off w_size w_capacity
399
400     for ((i=0;i<4;i++)); do
401         [ -n "$is_zbd" ] &&
402             reset_zone "$dev" $((first_sequential_zone_sector +
403                                  i*sectors_per_zone))
404     done
405     w_off=$(((first_sequential_zone_sector + 2 * sectors_per_zone) * 512))
406     w_size=$((2 * zone_size))
407     w_capacity=$(total_zone_capacity 2 $w_off $dev)
408     off=$((first_sequential_zone_sector * 512))
409     size=$((4 * zone_size))
410     write_and_run_one_fio_job "${w_off}" "${w_size}" \
411                     "$(ioengine "libaio")" --iodepth=64 --rw=randread --bs=16K \
412                     --zonemode=zbd --zonesize="${zone_size}" --offset=$off \
413                     --size=$size >>"${logfile}.${test_number}" 2>&1 || return $?
414     check_written $w_capacity || return $?
415     check_read $size || return $?
416 }
417
418 # Random reads and writes in the last zone.
419 test17() {
420     local io off read size written
421
422     off=$(((disk_size / zone_size - 1) * zone_size))
423     size=$((disk_size - off))
424     if [ -n "$is_zbd" ]; then
425         reset_zone "$dev" $((off / 512)) || return $?
426     fi
427     run_one_fio_job "$(ioengine "libaio")" --iodepth=8 --rw=randrw --bs=4K \
428                     --zonemode=zbd --zonesize="${zone_size}"            \
429                     --offset=$off --loops=2 --norandommap=1\
430                     >>"${logfile}.${test_number}" 2>&1 || return $?
431     written=$(fio_written <"${logfile}.${test_number}")
432     read=$(fio_read <"${logfile}.${test_number}")
433     io=$((written + read))
434     echo "Total number of bytes read and written: $io <> $size" \
435          >>"${logfile}.${test_number}"
436     [ $io = $((size * 2)) ];
437 }
438
439 # Out-of-range zone reset threshold and frequency parameters.
440 test18() {
441     run_fio_on_seq --zone_reset_threshold=-1 |&
442         tee -a "${logfile}.${test_number}"   |
443             grep -q 'value out of range' || return $?
444 }
445
446 test19() {
447     run_fio_on_seq --zone_reset_threshold=2  |&
448         tee -a "${logfile}.${test_number}"   |
449         grep -q 'value out of range' || return $?
450 }
451
452 test20() {
453     run_fio_on_seq --zone_reset_threshold=.4:.6 |&
454         tee -a "${logfile}.${test_number}"   |
455         grep -q 'the list exceeding max length' || return $?
456 }
457
458 test21() {
459     run_fio_on_seq --zone_reset_frequency=-1 |&
460         tee -a "${logfile}.${test_number}"   |
461         grep -q 'value out of range' || return $?
462 }
463
464 test22() {
465     run_fio_on_seq --zone_reset_frequency=2  |&
466         tee -a "${logfile}.${test_number}"   |
467         grep -q 'value out of range' || return $?
468 }
469
470 test23() {
471     run_fio_on_seq --zone_reset_frequency=.4:.6  |&
472         tee -a "${logfile}.${test_number}"   |
473         grep -q 'the list exceeding max length' || return $?
474 }
475
476 test24() {
477     local bs loops=9 size=$((zone_size))
478     local off capacity
479
480     off=$((first_sequential_zone_sector * 512))
481     capacity=$(total_zone_capacity 1 $off $dev)
482
483     bs=$(min $((256*1024)) "$zone_size")
484     run_fio_on_seq "$(ioengine "psync")" --rw=write --bs="$bs"          \
485                    --size=$size --loops=$loops                          \
486                    --zone_reset_frequency=.01 --zone_reset_threshold=.90 \
487                    >> "${logfile}.${test_number}" 2>&1 || return $?
488     check_written $((capacity * loops)) || return $?
489     check_reset_count -eq 8 ||
490         check_reset_count -eq 9 ||
491         check_reset_count -eq 10 || return $?
492 }
493
494 # Multiple non-overlapping sequential write jobs for the same drive.
495 test25() {
496     local i opts=()
497
498     for ((i=0;i<16;i++)); do
499         [ -n "$is_zbd" ] &&
500             reset_zone "$dev" $((first_sequential_zone_sector + i*sectors_per_zone))
501     done
502     for ((i=0;i<16;i++)); do
503         opts+=("--name=job$i" "--filename=$dev" "--thread=1" "--direct=1")
504         opts+=("--offset=$((first_sequential_zone_sector*512 + zone_size*i))")
505         opts+=("--size=$zone_size" "$(ioengine "psync")" "--rw=write" "--bs=16K")
506         opts+=("--zonemode=zbd" "--zonesize=${zone_size}" "--group_reporting=1")
507         opts+=(${var_opts[@]})
508     done
509     run_fio "${opts[@]}" >> "${logfile}.${test_number}" 2>&1 || return $?
510 }
511
512 write_to_first_seq_zone() {
513     local loops=4 r
514     local off capacity
515
516     off=$((first_sequential_zone_sector * 512))
517     capacity=$(total_zone_capacity 1 $off $dev)
518
519     r=$(((RANDOM << 16) | RANDOM))
520     run_fio --name="$dev" --filename="$dev" "$(ioengine "psync")" --rw="$1" \
521             --thread=1 --do_verify=1 --verify=md5 --direct=1 --bs=4K    \
522             --offset=$off                                               \
523             --size=$zone_size --loops=$loops --randseed="$r"            \
524             --zonemode=zbd --zonesize="${zone_size}" --group_reporting=1        \
525             --gtod_reduce=1 >> "${logfile}.${test_number}" 2>&1 || return $?
526     check_written $((loops * capacity)) || return $?
527 }
528
529 # Overwrite the first sequential zone four times sequentially.
530 test26() {
531     write_to_first_seq_zone write
532 }
533
534 # Overwrite the first sequential zone four times using random writes.
535 test27() {
536     write_to_first_seq_zone randwrite
537 }
538
539 # Multiple overlapping random write jobs for the same drive.
540 test28() {
541     local i jobs=16 off opts
542
543     off=$((first_sequential_zone_sector * 512 + 64 * zone_size))
544     [ -n "$is_zbd" ] && reset_zone "$dev" $((off / 512))
545     opts=("--debug=zbd")
546     capacity=$(total_zone_capacity 1 $off $dev)
547     for ((i=0;i<jobs;i++)); do
548         opts+=("--name=job$i" "--filename=$dev" "--offset=$off" "--bs=16K")
549         opts+=("--size=$zone_size" "--io_size=$capacity" "$(ioengine "psync")" "--rw=randwrite")
550         opts+=("--thread=1" "--direct=1" "--zonemode=zbd")
551         opts+=("--zonesize=${zone_size}" "--group_reporting=1")
552         opts+=(${var_opts[@]})
553     done
554     run_fio "${opts[@]}" >> "${logfile}.${test_number}" 2>&1 || return $?
555     check_written $((jobs * $capacity)) || return $?
556     check_reset_count -eq $jobs ||
557         check_reset_count -eq $((jobs - 1)) ||
558         return $?
559 }
560
561 # Multiple overlapping random write jobs for the same drive and with a limited
562 # number of open zones.
563 test29() {
564     local i jobs=16 off opts=()
565
566     off=$((first_sequential_zone_sector * 512 + 64 * zone_size))
567     size=$((16*zone_size))
568     [ -n "$is_zbd" ] && reset_zone "$dev" $((off / 512))
569     opts=("--debug=zbd")
570     for ((i=0;i<jobs;i++)); do
571         opts+=("--name=job$i" "--filename=$dev" "--offset=$off" "--bs=16K")
572         opts+=("--size=$size" "--io_size=$zone_size" "--thread=1")
573         opts+=("$(ioengine "psync")" "--rw=randwrite" "--direct=1")
574         opts+=("--max_open_zones=4" "--group_reporting=1")
575         opts+=("--zonemode=zbd" "--zonesize=${zone_size}")
576         opts+=(${var_opts[@]})
577     done
578     run_fio "${opts[@]}" >> "${logfile}.${test_number}" 2>&1 || return $?
579     check_written $((jobs * zone_size)) || return $?
580 }
581
582 # Random reads and writes across the entire disk for 30s.
583 test30() {
584     local off
585
586     off=$((first_sequential_zone_sector * 512))
587     run_one_fio_job "$(ioengine "libaio")" --iodepth=8 --rw=randrw      \
588                     --bs="$(max $((zone_size / 128)) "$logical_block_size")"\
589                     --zonemode=zbd --zonesize="${zone_size}" --offset=$off\
590                     --loops=2 --time_based --runtime=30s --norandommap=1\
591                     >>"${logfile}.${test_number}" 2>&1
592 }
593
594 # Random reads across all sequential zones for 30s. This is not only a fio
595 # test but also allows to verify the performance of a drive.
596 test31() {
597     local bs inc nz off opts size
598
599     # Start with writing 128 KB to 128 sequential zones.
600     bs=128K
601     nz=128
602     # shellcheck disable=SC2017
603     inc=$(((disk_size - (first_sequential_zone_sector * 512)) / (nz * zone_size)
604            * zone_size))
605     opts=()
606     for ((off = first_sequential_zone_sector * 512; off < disk_size;
607           off += inc)); do
608         opts+=("--name=$dev" "--filename=$dev" "--offset=$off" "--io_size=$bs")
609         opts+=("--bs=$bs" "--size=$zone_size" "$(ioengine "libaio")")
610         opts+=("--rw=write" "--direct=1" "--thread=1" "--stats=0")
611         opts+=("--zonemode=zbd" "--zonesize=${zone_size}")
612         opts+=(${var_opts[@]})
613     done
614     "$(dirname "$0")/../../fio" "${opts[@]}" >> "${logfile}.${test_number}" 2>&1
615     # Next, run the test.
616     off=$((first_sequential_zone_sector * 512))
617     size=$((disk_size - off))
618     opts=("--name=$dev" "--filename=$dev" "--offset=$off" "--size=$size")
619     opts+=("--bs=$bs" "$(ioengine "psync")" "--rw=randread" "--direct=1")
620     opts+=("--thread=1" "--time_based" "--runtime=30" "--zonemode=zbd")
621     opts+=("--zonesize=${zone_size}")
622     run_fio "${opts[@]}" >> "${logfile}.${test_number}" 2>&1 || return $?
623 }
624
625 # Random writes across all sequential zones. This is not only a fio test but
626 # also allows to verify the performance of a drive.
627 test32() {
628     local off opts=() size
629
630     off=$((first_sequential_zone_sector * 512))
631     size=$((disk_size - off))
632     opts+=("--name=$dev" "--filename=$dev" "--offset=$off" "--size=$size")
633     opts+=("--bs=128K" "$(ioengine "psync")" "--rw=randwrite" "--direct=1")
634     opts+=("--thread=1" "--time_based" "--runtime=30")
635     opts+=("--max_open_zones=$max_open_zones" "--zonemode=zbd")
636     opts+=("--zonesize=${zone_size}")
637     run_fio "${opts[@]}" >> "${logfile}.${test_number}" 2>&1 || return $?
638 }
639
640 # Write to sequential zones with a block size that is not a divisor of the
641 # zone size.
642 test33() {
643     local bs io_size size
644     local off capacity=0;
645
646     off=$((first_sequential_zone_sector * 512))
647     capacity=$(total_zone_capacity 1 $off $dev)
648     size=$((2 * zone_size))
649     io_size=$((5 * capacity))
650     bs=$((3 * capacity / 4))
651     run_fio_on_seq "$(ioengine "psync")" --iodepth=1 --rw=write \
652                    --size=$size --io_size=$io_size --bs=$bs     \
653                    >> "${logfile}.${test_number}" 2>&1 || return $?
654     check_written $(((io_size + bs - 1) / bs * bs)) || return $?
655 }
656
657 # Write to sequential zones with a block size that is not a divisor of the
658 # zone size and with data verification enabled.
659 test34() {
660     local size
661
662     size=$((2 * zone_size))
663     run_fio_on_seq "$(ioengine "psync")" --iodepth=1 --rw=write --size=$size \
664                    --do_verify=1 --verify=md5 --bs=$((3 * zone_size / 4)) \
665                    >> "${logfile}.${test_number}" 2>&1 && return 1
666     grep -q 'not a divisor of' "${logfile}.${test_number}"
667 }
668
669 # Test 1/4 for the I/O boundary rounding code: $size < $zone_size.
670 test35() {
671     local bs off io_size size
672
673     off=$(((first_sequential_zone_sector + 1) * 512))
674     size=$((zone_size - 2 * 512))
675     bs=$((zone_size / 4))
676     run_one_fio_job --offset=$off --size=$size "$(ioengine "psync")"    \
677                     --iodepth=1 --rw=write --do_verify=1 --verify=md5   \
678                     --bs=$bs --zonemode=zbd --zonesize="${zone_size}"   \
679                     >> "${logfile}.${test_number}" 2>&1 && return 1
680     grep -q 'io_size must be at least one zone' "${logfile}.${test_number}"
681 }
682
683 # Test 2/4 for the I/O boundary rounding code: $size < $zone_size.
684 test36() {
685     local bs off io_size size
686
687     off=$(((first_sequential_zone_sector) * 512))
688     size=$((zone_size - 512))
689     bs=$((zone_size / 4))
690     run_one_fio_job --offset=$off --size=$size "$(ioengine "psync")"    \
691                     --iodepth=1 --rw=write --do_verify=1 --verify=md5   \
692                     --bs=$bs --zonemode=zbd --zonesize="${zone_size}"   \
693                     >> "${logfile}.${test_number}" 2>&1 && return 1
694     grep -q 'io_size must be at least one zone' "${logfile}.${test_number}"
695 }
696
697 # Test 3/4 for the I/O boundary rounding code: $size > $zone_size.
698 test37() {
699     local bs off size capacity
700
701     capacity=$(total_zone_capacity 1 $first_sequential_zone_sector $dev)
702     if [ "$first_sequential_zone_sector" = 0 ]; then
703         off=0
704     else
705         off=$(((first_sequential_zone_sector - 1) * 512))
706     fi
707     size=$((zone_size + 2 * 512))
708     bs=$((zone_size / 4))
709     run_one_fio_job --offset=$off --size=$size "$(ioengine "psync")"    \
710                     --iodepth=1 --rw=write --do_verify=1 --verify=md5   \
711                     --bs=$bs --zonemode=zbd --zonesize="${zone_size}"   \
712                     >> "${logfile}.${test_number}" 2>&1
713     check_written $capacity || return $?
714 }
715
716 # Test 4/4 for the I/O boundary rounding code: $offset > $disk_size - $zone_size
717 test38() {
718     local bs off size
719
720     size=$((logical_block_size))
721     off=$((disk_size - logical_block_size))
722     bs=$((logical_block_size))
723     run_one_fio_job --offset=$off --size=$size "$(ioengine "psync")"    \
724                     --iodepth=1 --rw=write --do_verify=1 --verify=md5   \
725                     --bs=$bs --zonemode=zbd --zonesize="${zone_size}"   \
726                     >> "${logfile}.${test_number}" 2>&1 && return 1
727     grep -q 'io_size must be at least one zone' "${logfile}.${test_number}"
728 }
729
730 # Read one block from a block device.
731 read_one_block() {
732     local bs
733
734     bs=$((logical_block_size))
735     run_one_fio_job --rw=read "$(ioengine "psync")" --bs=$bs --size=$bs "$@" 2>&1 |
736         tee -a "${logfile}.${test_number}"
737 }
738
739 # Check whether fio accepts --zonemode=none for zoned block devices.
740 test39() {
741     [ -n "$is_zbd" ] || return 0
742     read_one_block --zonemode=none >/dev/null || return $?
743     check_read $((logical_block_size)) || return $?
744 }
745
746 # Check whether fio accepts --zonemode=strided for zoned block devices.
747 test40() {
748     local bs
749
750     bs=$((logical_block_size))
751     [ -n "$is_zbd" ] || return 0
752     read_one_block --zonemode=strided |
753         grep -q 'fio: --zonesize must be specified when using --zonemode=strided' ||
754         return $?
755     read_one_block --zonemode=strided --zonesize=$bs >/dev/null || return $?
756     check_read $bs || return $?
757 }
758
759 # Check whether fio checks the zone size for zoned block devices.
760 test41() {
761     [ -n "$is_zbd" ] || return 0
762     read_one_block --zonemode=zbd --zonesize=$((2 * zone_size)) |
763         grep -q 'job parameter zonesize.*does not match disk zone size'
764 }
765
766 # Check whether fio handles --zonesize=0 correctly for regular block devices.
767 test42() {
768     [ -n "$is_zbd" ] && return 0
769     read_one_block --zonemode=zbd --zonesize=0 |
770         grep -q 'Specifying the zone size is mandatory for regular block devices with --zonemode=zbd'
771 }
772
773 # Check whether fio handles --zonesize=1 correctly for regular block devices.
774 test43() {
775     [ -n "$is_zbd" ] && return 0
776     read_one_block --zonemode=zbd --zonesize=1 |
777         grep -q 'zone size must be at least 512 bytes for --zonemode=zbd'
778 }
779
780 # Check whether fio handles --zonemode=none --zonesize=1 correctly.
781 test44() {
782     read_one_block --zonemode=none --zonesize=1 |
783         grep -q 'fio: --zonemode=none and --zonesize are not compatible'
784 }
785
786 test45() {
787     local bs i
788
789     [ -z "$is_zbd" ] && return 0
790     bs=$((logical_block_size))
791     run_one_fio_job "$(ioengine "psync")" --iodepth=1 --rw=randwrite --bs=$bs\
792                     --offset=$((first_sequential_zone_sector * 512)) \
793                     --size="$zone_size" --do_verify=1 --verify=md5 2>&1 |
794         tee -a "${logfile}.${test_number}" |
795         grep -q "fio: first I/O failed. If .* is a zoned block device, consider --zonemode=zbd"
796 }
797
798 # Random write to sequential zones, libaio, 8 jobs, queue depth 64 per job
799 test46() {
800     local size
801
802     size=$((4 * zone_size))
803     run_fio_on_seq "$(ioengine "libaio")" --iodepth=64 --rw=randwrite --bs=4K \
804                    --group_reporting=1 --numjobs=8 \
805                    >> "${logfile}.${test_number}" 2>&1 || return $?
806     check_written $((size * 8)) || return $?
807 }
808
809 # Check whether fio handles --zonemode=zbd --zoneskip=1 correctly.
810 test47() {
811     local bs
812
813     bs=$((logical_block_size))
814     run_fio_on_seq "$(ioengine "psync")" --rw=write --bs=$bs --zoneskip=1 \
815                     >> "${logfile}.${test_number}" 2>&1 && return 1
816     grep -q 'zoneskip 1 is not a multiple of the device zone size' "${logfile}.${test_number}"
817 }
818
819 # Multiple overlapping random write jobs for the same drive and with a
820 # limited number of open zones. This is similar to test29, but uses libaio
821 # to stress test zone locking.
822 test48() {
823     local i jobs=16 off opts=()
824
825     off=$((first_sequential_zone_sector * 512 + 64 * zone_size))
826     size=$((16*zone_size))
827     [ -n "$is_zbd" ] && reset_zone "$dev" $((off / 512))
828     opts=("--aux-path=/tmp" "--allow_file_create=0" "--significant_figures=10")
829     opts+=("--debug=zbd")
830     opts+=("$(ioengine "libaio")" "--rw=randwrite" "--direct=1")
831     opts+=("--time_based" "--runtime=30")
832     opts+=("--zonemode=zbd" "--zonesize=${zone_size}")
833     opts+=("--max_open_zones=4")
834     for ((i=0;i<jobs;i++)); do
835         opts+=("--name=job$i" "--filename=$dev" "--offset=$off" "--bs=16K")
836         opts+=("--io_size=$zone_size" "--iodepth=256" "--thread=1")
837         opts+=("--group_reporting=1")
838     done
839
840     fio=$(dirname "$0")/../../fio
841
842     { echo; echo "fio ${opts[*]}"; echo; } >>"${logfile}.${test_number}"
843
844     timeout -v -s KILL 45s \
845             "${dynamic_analyzer[@]}" "$fio" "${opts[@]}" \
846             >> "${logfile}.${test_number}" 2>&1 || return $?
847 }
848
849 # Check if fio handles --zonecapacity on a normal block device correctly
850 test49() {
851
852     if [ -n "$is_zbd" ]; then
853         echo "$dev is not a regular block device" \
854              >>"${logfile}.${test_number}"
855         return 0
856     fi
857
858     size=$((2 * zone_size))
859     capacity=$((zone_size * 3 / 4))
860
861     run_one_fio_job "$(ioengine "psync")" --rw=write \
862                     --zonemode=zbd --zonesize="${zone_size}" \
863                     --zonecapacity=${capacity} \
864                     --verify=md5  --size=${size} >>"${logfile}.${test_number}" 2>&1 ||
865         return $?
866     check_written $((capacity * 2)) || return $?
867     check_read $((capacity * 2)) || return $?
868 }
869
870 tests=()
871 dynamic_analyzer=()
872 reset_all_zones=
873 use_libzbc=
874 zbd_debug=
875
876 while [ "${1#-}" != "$1" ]; do
877   case "$1" in
878     -d) dynamic_analyzer=(valgrind "--read-var-info=yes" "--tool=drd"
879                           "--show-confl-seg=no");
880         shift;;
881     -e) dynamic_analyzer=(valgrind "--read-var-info=yes" "--tool=helgrind");
882         shift;;
883     -l) use_libzbc=1; shift;;
884     -r) reset_all_zones=1; shift;;
885     -t) tests+=("$2"); shift; shift;;
886     -v) dynamic_analyzer=(valgrind "--read-var-info=yes");
887         shift;;
888     -z) zbd_debug=1; shift;;
889     --) shift; break;;
890   esac
891 done
892
893 if [ $# != 1 ]; then
894     usage
895     exit 1
896 fi
897
898 # shellcheck source=functions
899 source "$(dirname "$0")/functions" || exit $?
900
901 var_opts=()
902 if [ -n "$zbd_debug" ]; then
903     var_opts+=("--debug=zbd")
904 fi
905 dev=$1
906 realdev=$(readlink -f "$dev")
907 basename=$(basename "$realdev")
908
909 if [[ -b "$realdev" ]]; then
910         major=$((0x$(stat -L -c '%t' "$realdev"))) || exit $?
911         minor=$((0x$(stat -L -c '%T' "$realdev"))) || exit $?
912         disk_size=$(($(<"/sys/dev/block/$major:$minor/size")*512))
913
914         # When the target is a partition device, get basename of its
915         # holder device to access sysfs path of the holder device
916         if [[ -r "/sys/dev/block/$major:$minor/partition" ]]; then
917                 realsysfs=$(readlink "/sys/dev/block/$major:$minor")
918                 basename=$(basename "${realsysfs%/*}")
919         fi
920         logical_block_size=$(<"/sys/block/$basename/queue/logical_block_size")
921         case "$(<"/sys/class/block/$basename/queue/zoned")" in
922         host-managed|host-aware)
923                 is_zbd=true
924                 if ! check_blkzone "${dev}"; then
925                         exit 1
926                 fi
927                 if ! result=($(first_sequential_zone "$dev")); then
928                         echo "Failed to determine first sequential zone"
929                         exit 1
930                 fi
931                 first_sequential_zone_sector=${result[0]}
932                 sectors_per_zone=${result[1]}
933                 zone_size=$((sectors_per_zone * 512))
934                 if ! max_open_zones=$(max_open_zones "$dev"); then
935                         echo "Failed to determine maximum number of open zones"
936                         exit 1
937                 fi
938                 set_io_scheduler "$basename" deadline || exit $?
939                 if [ -n "$reset_all_zones" ]; then
940                         reset_zone "$dev" -1
941                 fi
942                 ;;
943         *)
944                 first_sequential_zone_sector=$(((disk_size / 2) &
945                                                 (logical_block_size - 1)))
946                 zone_size=$(max 65536 "$logical_block_size")
947                 sectors_per_zone=$((zone_size / 512))
948                 max_open_zones=128
949                 set_io_scheduler "$basename" none || exit $?
950                 ;;
951         esac
952 elif [[ -c "$realdev" ]]; then
953         # For an SG node, we must have libzbc option specified
954         if [[ ! -n "$use_libzbc" ]]; then
955                 echo "Character device files can only be used with -l (libzbc) option"
956                 exit 1
957         fi
958
959         if ! $(is_zbc "$dev"); then
960                 echo "Device is not a ZBC disk"
961                 exit 1
962         fi
963         is_zbd=true
964
965         if ! disk_size=($(( $(zbc_disk_sectors "$dev") * 512))); then
966                 echo "Failed to determine disk size"
967                 exit 1
968         fi
969         if ! logical_block_size=($(zbc_logical_block_size "$dev")); then
970                 echo "Failed to determine logical block size"
971                 exit 1
972         fi
973         if ! result=($(first_sequential_zone "$dev")); then
974                 echo "Failed to determine first sequential zone"
975                 exit 1
976         fi
977         first_sequential_zone_sector=${result[0]}
978         sectors_per_zone=${result[1]}
979         zone_size=$((sectors_per_zone * 512))
980         if ! max_open_zones=$(max_open_zones "$dev"); then
981                 echo "Failed to determine maximum number of open zones"
982                 exit 1
983         fi
984         if [ -n "$reset_all_zones" ]; then
985                 reset_zone "$dev" -1
986         fi
987 fi
988
989 echo -n "First sequential zone starts at sector $first_sequential_zone_sector;"
990 echo " zone size: $((zone_size >> 20)) MB"
991
992 if [ "${#tests[@]}" = 0 ]; then
993     readarray -t tests < <(declare -F | grep "test[0-9]*" | \
994                                    tr -c -d "[:digit:]\n" | sort -n)
995 fi
996
997 logfile=$0.log
998
999 passed=0
1000 failed=0
1001 if [ -t 1 ]; then
1002     red="\e[1;31m"
1003     green="\e[1;32m"
1004     end="\e[m"
1005 else
1006     red=""
1007     green=""
1008     end=""
1009 fi
1010 rc=0
1011
1012 intr=0
1013 trap 'intr=1' SIGINT
1014
1015 for test_number in "${tests[@]}"; do
1016     rm -f "${logfile}.${test_number}"
1017     echo -n "Running test $(printf "%02d" $test_number) ... "
1018     if eval "test$test_number" && check_log $test_number; then
1019         status="PASS"
1020         cc_status="${green}${status}${end}"
1021         ((passed++))
1022     else
1023         status="FAIL"
1024         cc_status="${red}${status}${end}"
1025         ((failed++))
1026         rc=1
1027     fi
1028     echo -e "$cc_status"
1029     echo "$status" >> "${logfile}.${test_number}"
1030     [ $intr -ne 0 ] && exit 1
1031 done
1032
1033 echo "$passed tests passed"
1034 if [ $failed -gt 0 ]; then
1035     echo " and $failed tests failed"
1036 fi
1037 exit $rc