2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2007 Silicon Graphics, Inc. All Rights Reserved.
5 # common functions for excersizing hole punches with extent size hints etc.
7 # source dmap_scratch_mount etc.
11 echo "# spawning test file with $*"
13 local file_size=`expr $2 \* $blksize`
14 local extent_size_hint=`expr $3 \* $blksize`
16 local reserve_space=$5
18 if [ $extent_size_hint -ne 0 ]; then
19 echo "+ setting extent size hint to $extent_size_hint"
21 -c "extsize $extent_size_hint" \
24 # print extent size hint for $test_file
29 if [ "$reserve_space" == "noresv" ]; then
30 echo "+ not using resvsp at file creation"
32 -c "truncate $file_size" \
36 -c "truncate $file_size" \
37 -c "resvsp 0 $file_size" \
43 echo "# punching with $*"
44 # punch or bite the ear off $test_file to create a hole
46 local punch_offset=`expr $2 \* $blksize`
47 local punch_size=`expr $3 \* $blksize`
48 local punch_type=$4 # u for unresvsp, d for dm_punch
51 if [ "$punch_type" == "u" ]; then
52 echo "+ hole punch using unresvsp"
54 -c "unresvsp $punch_offset $punch_size" \
57 if [ "$punch_type" == "d" ]; then
58 echo "+ hole punch using dmapi punch_hole"
59 ${DMAPI_QASUITE1_DIR}cmd/punch_hole -o $punch_offset -l $punch_size \
60 ${SCRATCH_MNT}/$test_file
65 echo "# writing with $*"
67 local write_offset=`expr $2 \* $blksize`
68 local write_size=`expr $3 \* $blksize`
72 -c "pwrite $write_offset $write_size" \
77 echo "# showing file state $*"
86 echo "# testing $* ..."
88 # all points and sizes below are in terms of filesystem blocks
89 local extsize_hint_blks=$2 # extent size hint in FS blocks, 0=do not set
90 local file_size_blks=$3 # the file size in blocks
91 local punch_points_blks=( $4 ) # array of places to punch holes in the file
92 local punch_sizes_blks=( $5 ) # array of size of each punch in blocks
93 local punch_types=( $6 ) # array of u=unresvsp or d=dm_punch
94 local write_points_blks=( $7 ) # array of places to pwrite in the file
95 local write_sizes_blks=( $8 ) # array of size of each write
97 local punch_write_order=( $9 ) # array of punch/write operation order
98 # e.g. "w p w w p" means: do 1st write...
99 # then 1st punch, 2nd & 3rd write, 2nd punch
100 local resvsp=${10} # if "noresv" then don't resvsp on file create
101 local filename=punch_test_file
104 _scratch_unmount >/dev/null 2>&1
106 _scratch_mkfs_xfs -bsize=$blksize >/dev/null 2>&1 \
107 || _fail "mkfs failed"
109 local this_punch_type=""
110 local dmap_punch_used=0
111 for this_punch_type in "${punch_types[@]}"; do
112 [ "$this_punch_type" == "d" ] && dmap_punch_used=1
114 if [ $dmap_punch_used -ne 0 ]; then
115 # a punch type of dm_punch has been specified, do a dmapi mount
116 echo "+ mounting with dmapi enabled"
119 # only unresvsp punch type is used, just do a normal mount
125 # check a size is specified for each punch
126 [ ${#punch_points_blks[*]} -eq ${#punch_sizes_blks[*]} ] \
127 || _fail "num punch points given does not equal num punch sizes"
129 # check a type is specified for each punch
130 [ ${#punch_points_blks[*]} -eq ${#punch_types[*]} ] \
131 || _fail "num punch points given does not equal num punch types"
133 # check a size is specified for each write
134 [ ${#write_points_blks[*]} -eq ${#write_sizes_blks[*]} ] \
135 || _fail "num write points given does not equal num write sizes"
137 # check punch_write_order operations match number of punches + writes
138 local total_pw_operations=`expr ${#punch_points_blks[*]} + ${#write_points_blks[*]}`
139 [ $total_pw_operations -eq ${#punch_write_order[*]} ] \
140 || _fail "punch_write_order ops doesn't match number of punches + writes"
142 # create the file and setup extent size hint
143 _spawn_test_file $blksize $file_size_blks $extsize_hint_blks $filename $resvsp
145 # do the writes and punches
149 for operation in "${punch_write_order[@]}"; do
150 if [ "$operation" == "p" ]; then
151 _do_punch $blksize ${punch_points_blks[$punch_index]} \
152 ${punch_sizes_blks[$punch_index]} ${punch_types[$punch_index]} \
154 punch_index=`expr $punch_index + 1`
156 if [ "$operation" == "w" ]; then
157 _do_write $blksize ${write_points_blks[$write_index]} \
158 ${write_sizes_blks[$write_index]} $filename
159 write_index=`expr $write_index + 1`
162 _do_bmap $filename # print out the state of the file
170 [[ -z $block_size ]] && block_size=512
172 awk -v block_size="$block_size" -F: '
177 split(range, bounds, "[\\[ \\.\\]]");
181 if (type != prev_type) {
183 printf("%u]:%s\n", (low * 512 / block_size) - 1,
185 printf("%u: [%u..", out_count++,
186 (low * 512) / block_size);
192 printf("%u]:%s\n", ((high + 1) * 512 / block_size) - 1,
206 $5 ~ /0x[[:xdigit:]]*8[[:xdigit:]][[:xdigit:]]/ {
207 print $1, $2, "unwritten";
210 $5 ~ /0x[[:xdigit:]]+/ {
211 print $1, $2, "data";
213 _coalesce_extents $block_size
216 _filter_fiemap_flags()
223 $5 ~ /0x[[:xdigit:]]*8[[:xdigit:]][[:xdigit:]]/ {
224 print $1, $2, "unwritten";
227 $5 ~ /0x[[:xdigit:]]+/ {
233 # Filters fiemap output to only print the
234 # file offset column and whether or not
235 # it is an extent or a hole
236 _filter_hole_fiemap()
243 $5 ~ /0x[[:xdigit:]]+/ {
244 print $1, $2, "extent";
249 # 10000 Unwritten preallocated extent
250 # 01000 Doesn't begin on stripe unit
251 # 00100 Doesn't end on stripe unit
252 # 00010 Doesn't begin on stripe width
253 # 00001 Doesn't end on stripe width
261 $7 ~ /1[01][01][01][01]/ {
262 print $1, $2, "unwritten";
265 $7 ~ /0[01][01][01][01]/ {
277 # test the different corner cases for zeroing a range:
280 # 2. into allocated space
281 # 3. into unwritten space
283 # 5. hole -> unwritten
285 # 7. data -> unwritten
286 # 8. unwritten -> hole
287 # 9. unwritten -> data
288 # 10. hole -> data -> hole
289 # 11. data -> hole -> data
290 # 12. unwritten -> data -> unwritten
291 # 13. data -> unwritten -> data
292 # 14. data -> hole @ EOF
293 # 15. data -> hole @ 0
294 # 16. data -> cache cold ->hole
295 # 17. data -> hole in single block file
297 # Test file is removed, created and sync'd between tests.
299 # Use -k flag to keep the file between tests. This will
300 # test the handling of pre-existing holes.
302 # Use the -d flag to not sync the file between tests.
303 # This will test the handling of delayed extents
305 # Use the -u flag to not run unwritten tests.
306 # This will eliminate some unnecessary information.
308 _test_generic_punch()
315 while getopts 'dku' OPTION
329 shift $(($OPTIND - 1))
333 zero_cmd=$3 #if not testing zero just set to punch
338 # The punch hole tests needs multiple of the largest extent size being
339 # tested, with multiple=16 it can test extent size upto 64k.
341 _4k="$((multiple * 4))k"
342 _8k="$((multiple * 8))k"
343 _12k="$((multiple * 12))k"
344 _20k="$((multiple * 20))k"
346 # initial test state must be defined, otherwise the first test can fail
347 # due ot stale file state left from previous tests.
350 echo " 1. into a hole"
351 $XFS_IO_PROG -f -c "truncate $_20k" \
352 -c "$zero_cmd $_4k $_8k" \
353 -c "$map_cmd -v" $testfile | $filter_cmd
354 [ $? -ne 0 ] && die_now
355 _md5_checksum $testfile
357 echo " 2. into allocated space"
358 if [ "$remove_testfile" ]; then
361 $XFS_IO_PROG -f -c "truncate $_20k" \
362 -c "pwrite 0 $_20k" $sync_cmd \
363 -c "$zero_cmd $_4k $_8k" \
364 -c "$map_cmd -v" $testfile | $filter_cmd
365 [ $? -ne 0 ] && die_now
366 _md5_checksum $testfile
368 if [ "$unwritten_tests" ]; then
369 echo " 3. into unwritten space"
370 if [ "$remove_testfile" ]; then
373 $XFS_IO_PROG -f -c "truncate $_20k" \
374 -c "$alloc_cmd 0 $_20k" \
375 -c "$zero_cmd $_4k $_8k" \
376 -c "$map_cmd -v" $testfile | $filter_cmd
377 [ $? -ne 0 ] && die_now
378 _md5_checksum $testfile
381 echo " 4. hole -> data"
382 if [ "$remove_testfile" ]; then
385 $XFS_IO_PROG -f -c "truncate $_20k" \
386 -c "pwrite $_8k $_8k" $sync_cmd \
387 -c "$zero_cmd $_4k $_8k" \
388 -c "$map_cmd -v" $testfile | $filter_cmd
389 [ $? -ne 0 ] && die_now
390 _md5_checksum $testfile
392 if [ "$unwritten_tests" ]; then
393 echo " 5. hole -> unwritten"
394 if [ "$remove_testfile" ]; then
397 $XFS_IO_PROG -f -c "truncate $_20k" \
398 -c "$alloc_cmd $_8k $_8k" \
399 -c "$zero_cmd $_4k $_8k" \
400 -c "$map_cmd -v" $testfile | $filter_cmd
401 [ $? -ne 0 ] && die_now
402 _md5_checksum $testfile
405 echo " 6. data -> hole"
406 if [ "$remove_testfile" ]; then
409 $XFS_IO_PROG -f -c "truncate $_20k" \
410 -c "pwrite 0 $_8k" $sync_cmd \
411 -c "$zero_cmd $_4k $_8k" \
412 -c "$map_cmd -v" $testfile | $filter_cmd
413 [ $? -ne 0 ] && die_now
414 _md5_checksum $testfile
416 if [ "$unwritten_tests" ]; then
417 echo " 7. data -> unwritten"
418 if [ "$remove_testfile" ]; then
421 $XFS_IO_PROG -f -c "truncate $_20k" \
422 -c "pwrite 0 $_8k" $sync_cmd \
423 -c "$alloc_cmd $_8k $_8k" \
424 -c "$zero_cmd $_4k $_8k" \
425 -c "$map_cmd -v" $testfile | $filter_cmd
426 [ $? -ne 0 ] && die_now
427 _md5_checksum $testfile
429 echo " 8. unwritten -> hole"
430 if [ "$remove_testfile" ]; then
433 $XFS_IO_PROG -f -c "truncate $_20k" \
434 -c "$alloc_cmd 0 $_8k" \
435 -c "$zero_cmd $_4k $_8k" \
436 -c "$map_cmd -v" $testfile | $filter_cmd
437 [ $? -ne 0 ] && die_now
438 _md5_checksum $testfile
440 echo " 9. unwritten -> data"
441 if [ "$remove_testfile" ]; then
444 $XFS_IO_PROG -f -c "truncate $_20k" \
445 -c "$alloc_cmd 0 $_8k" \
446 -c "pwrite $_8k $_8k" $sync_cmd \
447 -c "$zero_cmd $_4k $_8k" \
448 -c "$map_cmd -v" $testfile | $filter_cmd
449 [ $? -ne 0 ] && die_now
450 _md5_checksum $testfile
453 echo " 10. hole -> data -> hole"
454 if [ "$remove_testfile" ]; then
457 $XFS_IO_PROG -f -c "truncate $_20k" \
458 -c "pwrite $_8k $_4k" $sync_cmd \
459 -c "$zero_cmd $_4k $_12k" \
460 -c "$map_cmd -v" $testfile | $filter_cmd
461 [ $? -ne 0 ] && die_now
462 _md5_checksum $testfile
464 echo " 11. data -> hole -> data"
465 if [ "$remove_testfile" ]; then
468 $XFS_IO_PROG -f -c "truncate $_20k" \
469 -c "$alloc_cmd 0 $_20k" \
471 -c "pwrite $_12k $_8k" $sync_cmd \
472 -c "$punch_cmd $_8k $_4k" \
473 -c "$zero_cmd $_4k $_12k" \
474 -c "$map_cmd -v" $testfile | $filter_cmd
475 [ $? -ne 0 ] && die_now
476 _md5_checksum $testfile
478 if [ "$unwritten_tests" ]; then
479 echo " 12. unwritten -> data -> unwritten"
480 if [ "$remove_testfile" ]; then
483 $XFS_IO_PROG -f -c "truncate $_20k" \
484 -c "$alloc_cmd 0 $_20k" \
485 -c "pwrite $_8k $_4k" $sync_cmd \
486 -c "$zero_cmd $_4k $_12k" \
487 -c "$map_cmd -v" $testfile | $filter_cmd
488 [ $? -ne 0 ] && die_now
489 _md5_checksum $testfile
491 echo " 13. data -> unwritten -> data"
492 if [ "$remove_testfile" ]; then
495 $XFS_IO_PROG -f -c "truncate $_20k" \
496 -c "$alloc_cmd 0 $_20k" \
497 -c "pwrite 0k $_4k" $sync_cmd \
498 -c "pwrite $_12k $_8k" -c "fsync" \
499 -c "$zero_cmd $_4k $_12k" \
500 -c "$map_cmd -v" $testfile | $filter_cmd
501 [ $? -ne 0 ] && die_now
502 _md5_checksum $testfile
505 # Don't need to check EOF case for collapse range.
506 # VFS layer return invalid error in this case,
507 # So it is not a proper case for collapse range test of each local fs.
508 if [ "$zero_cmd" != "fcollapse" ]; then
509 echo " 14. data -> hole @ EOF"
511 $XFS_IO_PROG -f -c "truncate $_20k" \
512 -c "pwrite 0 $_20k" $sync_cmd \
513 -c "$zero_cmd $_12k $_8k" \
514 -c "$map_cmd -v" $testfile | $filter_cmd
515 [ $? -ne 0 ] && die_now
516 _md5_checksum $testfile
519 if [ "$zero_cmd" == "fcollapse" ]; then
520 echo " 14. data -> hole @ 0"
522 echo " 15. data -> hole @ 0"
525 if [ "$remove_testfile" ]; then
528 $XFS_IO_PROG -f -c "truncate $_20k" \
529 -c "pwrite 0 $_20k" $sync_cmd \
530 -c "$zero_cmd 0 $_8k" \
531 -c "$map_cmd -v" $testfile | $filter_cmd
532 [ $? -ne 0 ] && die_now
533 _md5_checksum $testfile
535 # If zero_cmd is fcollpase, don't check unaligned offsets
536 if [ "$zero_cmd" == "fcollapse" ]; then
540 # If zero_cmd is finsert, don't check unaligned offsets
541 if [ "$zero_cmd" == "finsert" ]; then
545 echo " 16. data -> cache cold ->hole"
546 if [ "$remove_testfile" ]; then
550 cp $testfile $testfile.2
552 $XFS_IO_PROG -f -c "truncate $_20k" \
553 -c "pwrite $_8k $_12k" -c "fsync" $testfile.2 \
555 $XFS_IO_PROG -f -c "truncate $_20k" \
556 -c "pwrite 0 $_20k" $sync_cmd \
557 -c "$zero_cmd 0k $_8k" \
559 -c "$map_cmd -v" $testfile | $filter_cmd
560 diff $testfile $testfile.2
561 [ $? -ne 0 ] && die_now
563 _md5_checksum $testfile
565 # different file sizes mean we can't use md5sum to check the hole is
566 # valid. Hence use hexdump to dump the contents and chop off the last
567 # line of output that indicates the file size. We also have to fudge
568 # the extent size as that will change with file size, too - that's what
569 # the sed line noise does - it will always result in an output of [0..7]
570 # so it matches 4k block size...
571 echo " 17. data -> hole in single block file"
572 if [ "$remove_testfile" ]; then
575 block_size=`_get_block_size $TEST_DIR`
576 $XFS_IO_PROG -f -c "truncate $block_size" \
577 -c "pwrite 0 $block_size" $sync_cmd \
578 -c "$zero_cmd 128 128" \
579 -c "$map_cmd -v" $testfile | $filter_cmd | \
580 sed -e "s/\.\.[0-9]*\]/..7\]/"
581 [ $? -ne 0 ] && die_now
582 od -x $testfile | head -n -1
585 _test_block_boundaries()
592 while getopts 'dk' OPTION
604 shift $(($OPTIND - 1))
619 # Block size multiplied by 2
622 # Block size divided by 2
626 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
627 -c "pwrite -S 0x42 $bs $bs" \
629 -c "pread -v 0 $bs_t2" \
630 $testfile | $filter_cmd
632 echo "zero 0, $bs_m1"
633 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
634 -c "pwrite -S 0x42 $bs $bs" \
635 -c "$zero_cmd 0 $bs_m1" \
636 -c "pread -v 0 $bs_t2" \
637 $testfile | $filter_cmd
640 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
641 -c "pwrite -S 0x42 $bs $bs" \
642 -c "$zero_cmd 0 $bs" \
643 -c "pread -v 0 $bs_t2" \
644 $testfile | $filter_cmd
646 echo "zero 0, $bs_p1"
647 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
648 -c "pwrite -S 0x42 $bs $bs" \
649 -c "$zero_cmd 0 $bs_p1" \
650 -c "pread -v 0 $bs_t2" \
651 $testfile | $filter_cmd
653 echo "zero $bs_m1, $bs"
654 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
655 -c "pwrite -S 0x42 $bs $bs" \
656 -c "$zero_cmd $bs_m1 $bs" \
657 -c "pread -v 0 $bs_t2" \
658 $testfile | $filter_cmd
660 echo "zero $bs_m1, $bs_p1"
661 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
662 -c "pwrite -S 0x42 $bs $bs" \
663 -c "$zero_cmd $bs_m1 $bs_p1" \
664 -c "pread -v 0 $bs_t2" \
665 $testfile | $filter_cmd
667 echo "zero $bs_m1, $bs_p2"
668 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
669 -c "pwrite -S 0x42 $bs $bs" \
670 -c "$zero_cmd $bs_m1 $bs_p2" \
671 -c "pread -v 0 $bs_t2" \
672 $testfile | $filter_cmd
676 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
677 -c "pwrite -S 0x42 $bs $bs" \
678 -c "$zero_cmd $bs $bs" \
679 -c "pread -v 0 $bs_t2" \
680 $testfile | $filter_cmd
683 echo "zero $bs_d2 , $bs"
684 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
685 -c "pwrite -S 0x42 $bs $bs" \
686 -c "$zero_cmd $bs_d2 $bs" \
687 -c "pread -v 0 $bs_t2" \
688 $testfile | $filter_cmd