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