3 # Copyright (c) 2007 Silicon Graphics, Inc. All Rights Reserved.
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License as
7 # published by the Free Software Foundation.
9 # This program is distributed in the hope that it would be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write the Free Software Foundation,
16 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 # common functions for excersizing hole punches with extent size hints etc.
21 # source dmap_scratch_mount etc.
25 echo "# spawning test file with $*"
27 local file_size=`expr $2 \* $blksize`
28 local extent_size_hint=`expr $3 \* $blksize`
30 local reserve_space=$5
32 if [ $extent_size_hint -ne 0 ]; then
33 echo "+ setting extent size hint to $extent_size_hint"
35 -c "extsize $extent_size_hint" \
38 # print extent size hint for $test_file
43 if [ "$reserve_space" == "noresv" ]; then
44 echo "+ not using resvsp at file creation"
46 -c "truncate $file_size" \
50 -c "truncate $file_size" \
51 -c "resvsp 0 $file_size" \
57 echo "# punching with $*"
58 # punch or bite the ear off $test_file to create a hole
60 local punch_offset=`expr $2 \* $blksize`
61 local punch_size=`expr $3 \* $blksize`
62 local punch_type=$4 # u for unresvsp, d for dm_punch
65 if [ "$punch_type" == "u" ]; then
66 echo "+ hole punch using unresvsp"
68 -c "unresvsp $punch_offset $punch_size" \
71 if [ "$punch_type" == "d" ]; then
72 echo "+ hole punch using dmapi punch_hole"
73 ${DMAPI_QASUITE1_DIR}cmd/punch_hole -o $punch_offset -l $punch_size \
74 ${SCRATCH_MNT}/$test_file
79 echo "# writing with $*"
81 local write_offset=`expr $2 \* $blksize`
82 local write_size=`expr $3 \* $blksize`
86 -c "pwrite $write_offset $write_size" \
91 echo "# showing file state $*"
100 echo "# testing $* ..."
102 # all points and sizes below are in terms of filesystem blocks
103 local extsize_hint_blks=$2 # extent size hint in FS blocks, 0=do not set
104 local file_size_blks=$3 # the file size in blocks
105 local punch_points_blks=( $4 ) # array of places to punch holes in the file
106 local punch_sizes_blks=( $5 ) # array of size of each punch in blocks
107 local punch_types=( $6 ) # array of u=unresvsp or d=dm_punch
108 local write_points_blks=( $7 ) # array of places to pwrite in the file
109 local write_sizes_blks=( $8 ) # array of size of each write
111 local punch_write_order=( $9 ) # array of punch/write operation order
112 # e.g. "w p w w p" means: do 1st write...
113 # then 1st punch, 2nd & 3rd write, 2nd punch
114 local resvsp=${10} # if "noresv" then don't resvsp on file create
115 local filename=punch_test_file
118 _scratch_unmount >/dev/null 2>&1
120 _scratch_mkfs_xfs -bsize=$blksize >/dev/null 2>&1 \
121 || _fail "mkfs failed"
123 local this_punch_type=""
124 local dmap_punch_used=0
125 for this_punch_type in "${punch_types[@]}"; do
126 [ "$this_punch_type" == "d" ] && dmap_punch_used=1
128 if [ $dmap_punch_used -ne 0 ]; then
129 # a punch type of dm_punch has been specified, do a dmapi mount
130 echo "+ mounting with dmapi enabled"
133 # only unresvsp punch type is used, just do a normal mount
134 _scratch_mount || _fail "mount failed"
139 # check a size is specified for each punch
140 [ ${#punch_points_blks[*]} -eq ${#punch_sizes_blks[*]} ] \
141 || _fail "num punch points given does not equal num punch sizes"
143 # check a type is specified for each punch
144 [ ${#punch_points_blks[*]} -eq ${#punch_types[*]} ] \
145 || _fail "num punch points given does not equal num punch types"
147 # check a size is specified for each write
148 [ ${#write_points_blks[*]} -eq ${#write_sizes_blks[*]} ] \
149 || _fail "num write points given does not equal num write sizes"
151 # check punch_write_order operations match number of punches + writes
152 local total_pw_operations=`expr ${#punch_points_blks[*]} + ${#write_points_blks[*]}`
153 [ $total_pw_operations -eq ${#punch_write_order[*]} ] \
154 || _fail "punch_write_order ops doesn't match number of punches + writes"
156 # create the file and setup extent size hint
157 _spawn_test_file $blksize $file_size_blks $extsize_hint_blks $filename $resvsp
159 # do the writes and punches
163 for operation in "${punch_write_order[@]}"; do
164 if [ "$operation" == "p" ]; then
165 _do_punch $blksize ${punch_points_blks[$punch_index]} \
166 ${punch_sizes_blks[$punch_index]} ${punch_types[$punch_index]} \
168 punch_index=`expr $punch_index + 1`
170 if [ "$operation" == "w" ]; then
171 _do_write $blksize ${write_points_blks[$write_index]} \
172 ${write_sizes_blks[$write_index]} $filename
173 write_index=`expr $write_index + 1`
176 _do_bmap $filename # print out the state of the file
187 split(range, bounds, "[\\[ \\.\\]]");
191 if (type != prev_type) {
193 printf("%u]:%s\n", low - 1, prev_type);
194 printf("%u: [%u..", out_count++, low);
200 printf("%u]:%s\n", high, prev_type);
211 $5 ~ /0x[[:xdigit:]]*8[[:xdigit:]][[:xdigit:]]/ {
212 print $1, $2, "unwritten";
215 $5 ~ /0x[[:xdigit:]]+/ {
216 print $1, $2, "data";
221 _filter_fiemap_flags()
228 $5 ~ /0x[[:xdigit:]]*8[[:xdigit:]][[:xdigit:]]/ {
229 print $1, $2, "unwritten";
232 $5 ~ /0x[[:xdigit:]]+/ {
238 # Filters fiemap output to only print the
239 # file offset column and whether or not
240 # it is an extent or a hole
241 _filter_hole_fiemap()
248 $5 ~ /0x[[:xdigit:]]+/ {
249 print $1, $2, "extent";
254 # 10000 Unwritten preallocated extent
255 # 01000 Doesn't begin on stripe unit
256 # 00100 Doesn't end on stripe unit
257 # 00010 Doesn't begin on stripe width
258 # 00001 Doesn't end on stripe width
266 $7 ~ /1[01][01][01][01]/ {
267 print $1, $2, "unwritten";
270 $7 ~ /0[01][01][01][01]/ {
282 # test the different corner cases for zeroing a range:
285 # 2. into allocated space
286 # 3. into unwritten space
288 # 5. hole -> unwritten
290 # 7. data -> unwritten
291 # 8. unwritten -> hole
292 # 9. unwritten -> data
293 # 10. hole -> data -> hole
294 # 11. data -> hole -> data
295 # 12. unwritten -> data -> unwritten
296 # 13. data -> unwritten -> data
297 # 14. data -> hole @ EOF
298 # 15. data -> hole @ 0
299 # 16. data -> cache cold ->hole
300 # 17. data -> hole in single block file
302 # Test file is removed, created and sync'd between tests.
304 # Use -k flag to keep the file between tests. This will
305 # test the handling of pre-existing holes.
307 # Use the -d flag to not sync the file between tests.
308 # This will test the handling of delayed extents
310 # Use the -u flag to not run unwritten tests.
311 # This will eliminate some unnecessary information.
313 _test_generic_punch()
320 while getopts 'dku' OPTION
334 shift $(($OPTIND - 1))
338 zero_cmd=$3 #if not testing zero just set to punch
345 # If we are testing collapse range, we increare all the offsets of this
346 # test by a factor of 4. We do this because unlike punch, collapse
347 # range also decreases the size of file hence require bigger offsets.
349 if [ "$zero_cmd" == "fcollapse" ]; then
353 _4k="$((multiple * 4))k"
354 _8k="$((multiple * 8))k"
355 _12k="$((multiple * 12))k"
356 _20k="$((multiple * 20))k"
358 # initial test state must be defined, otherwise the first test can fail
359 # due ot stale file state left from previous tests.
362 echo " 1. into a hole"
363 $XFS_IO_PROG -f -c "truncate $_20k" \
364 -c "$zero_cmd $_4k $_8k" \
365 -c "$map_cmd -v" $testfile | $filter_cmd
366 [ $? -ne 0 ] && die_now
367 _md5_checksum $testfile
369 echo " 2. into allocated space"
370 if [ "$remove_testfile" ]; then
373 $XFS_IO_PROG -f -c "truncate $_20k" \
374 -c "pwrite 0 $_20k" $sync_cmd \
375 -c "$zero_cmd $_4k $_8k" \
376 -c "$map_cmd -v" $testfile | $filter_cmd
377 [ $? -ne 0 ] && die_now
378 _md5_checksum $testfile
380 if [ "$unwritten_tests" ]; then
381 echo " 3. into unwritten space"
382 if [ "$remove_testfile" ]; then
385 $XFS_IO_PROG -f -c "truncate $_20k" \
386 -c "$alloc_cmd 0 $_20k" \
387 -c "$zero_cmd $_4k $_8k" \
388 -c "$map_cmd -v" $testfile | $filter_cmd
389 [ $? -ne 0 ] && die_now
390 _md5_checksum $testfile
393 echo " 4. hole -> data"
394 if [ "$remove_testfile" ]; then
397 $XFS_IO_PROG -f -c "truncate $_20k" \
398 -c "pwrite $_8k $_8k" $sync_cmd \
399 -c "$zero_cmd $_4k $_8k" \
400 -c "$map_cmd -v" $testfile | $filter_cmd
401 [ $? -ne 0 ] && die_now
402 _md5_checksum $testfile
404 if [ "$unwritten_tests" ]; then
405 echo " 5. hole -> unwritten"
406 if [ "$remove_testfile" ]; then
409 $XFS_IO_PROG -f -c "truncate $_20k" \
410 -c "$alloc_cmd $_8k $_8k" \
411 -c "$zero_cmd $_4k $_8k" \
412 -c "$map_cmd -v" $testfile | $filter_cmd
413 [ $? -ne 0 ] && die_now
414 _md5_checksum $testfile
417 echo " 6. data -> hole"
418 if [ "$remove_testfile" ]; then
421 $XFS_IO_PROG -f -c "truncate $_20k" \
422 -c "pwrite 0 $_8k" $sync_cmd \
423 -c "$zero_cmd $_4k $_8k" \
424 -c "$map_cmd -v" $testfile | $filter_cmd
425 [ $? -ne 0 ] && die_now
426 _md5_checksum $testfile
428 if [ "$unwritten_tests" ]; then
429 echo " 7. data -> unwritten"
430 if [ "$remove_testfile" ]; then
433 $XFS_IO_PROG -f -c "truncate $_20k" \
434 -c "pwrite 0 $_8k" $sync_cmd \
435 -c "$alloc_cmd $_8k $_8k" \
436 -c "$zero_cmd $_4k $_8k" \
437 -c "$map_cmd -v" $testfile | $filter_cmd
438 [ $? -ne 0 ] && die_now
439 _md5_checksum $testfile
441 echo " 8. unwritten -> hole"
442 if [ "$remove_testfile" ]; then
445 $XFS_IO_PROG -f -c "truncate $_20k" \
446 -c "$alloc_cmd 0 $_8k" \
447 -c "$zero_cmd $_4k $_8k" \
448 -c "$map_cmd -v" $testfile | $filter_cmd
449 [ $? -ne 0 ] && die_now
450 _md5_checksum $testfile
452 echo " 9. unwritten -> data"
453 if [ "$remove_testfile" ]; then
456 $XFS_IO_PROG -f -c "truncate $_20k" \
457 -c "$alloc_cmd 0 $_8k" \
458 -c "pwrite $_8k $_8k" $sync_cmd \
459 -c "$zero_cmd $_4k $_8k" \
460 -c "$map_cmd -v" $testfile | $filter_cmd
461 [ $? -ne 0 ] && die_now
462 _md5_checksum $testfile
465 echo " 10. hole -> data -> hole"
466 if [ "$remove_testfile" ]; then
469 $XFS_IO_PROG -f -c "truncate $_20k" \
470 -c "pwrite $_8k $_4k" $sync_cmd \
471 -c "$zero_cmd $_4k $_12k" \
472 -c "$map_cmd -v" $testfile | $filter_cmd
473 [ $? -ne 0 ] && die_now
474 _md5_checksum $testfile
476 echo " 11. data -> hole -> data"
477 if [ "$remove_testfile" ]; then
480 $XFS_IO_PROG -f -c "truncate $_20k" \
481 -c "$alloc_cmd 0 $_20k" \
483 -c "pwrite $_12k $_8k" $sync_cmd \
484 -c "$punch_cmd $_8k $_4k" \
485 -c "$zero_cmd $_4k $_12k" \
486 -c "$map_cmd -v" $testfile | $filter_cmd
487 [ $? -ne 0 ] && die_now
488 _md5_checksum $testfile
490 if [ "$unwritten_tests" ]; then
491 echo " 12. unwritten -> data -> unwritten"
492 if [ "$remove_testfile" ]; then
495 $XFS_IO_PROG -f -c "truncate $_20k" \
496 -c "$alloc_cmd 0 $_20k" \
497 -c "pwrite $_8k $_4k" $sync_cmd \
498 -c "$zero_cmd $_4k $_12k" \
499 -c "$map_cmd -v" $testfile | $filter_cmd
500 [ $? -ne 0 ] && die_now
501 _md5_checksum $testfile
503 echo " 13. data -> unwritten -> data"
504 if [ "$remove_testfile" ]; then
507 $XFS_IO_PROG -f -c "truncate $_20k" \
508 -c "$alloc_cmd 0 $_20k" \
509 -c "pwrite 0k $_4k" $sync_cmd \
510 -c "pwrite $_12k $_8k" -c "fsync" \
511 -c "$zero_cmd $_4k $_12k" \
512 -c "$map_cmd -v" $testfile | $filter_cmd
513 [ $? -ne 0 ] && die_now
514 _md5_checksum $testfile
517 # Don't need to check EOF case for collapse range.
518 # VFS layer return invalid error in this case,
519 # So it is not a proper case for collapse range test of each local fs.
520 if [ "$zero_cmd" != "fcollapse" ]; then
521 echo " 14. data -> hole @ EOF"
523 $XFS_IO_PROG -f -c "truncate $_20k" \
524 -c "pwrite 0 $_20k" $sync_cmd \
525 -c "$zero_cmd $_12k $_8k" \
526 -c "$map_cmd -v" $testfile | $filter_cmd
527 [ $? -ne 0 ] && die_now
528 _md5_checksum $testfile
531 if [ "$zero_cmd" == "fcollapse" ]; then
532 echo " 14. data -> hole @ 0"
534 echo " 15. data -> hole @ 0"
537 if [ "$remove_testfile" ]; then
540 $XFS_IO_PROG -f -c "truncate $_20k" \
541 -c "pwrite 0 $_20k" $sync_cmd \
542 -c "$zero_cmd 0 $_8k" \
543 -c "$map_cmd -v" $testfile | $filter_cmd
544 [ $? -ne 0 ] && die_now
545 _md5_checksum $testfile
547 # If zero_cmd is fcollpase, don't check unaligned offsets
548 if [ "$zero_cmd" == "fcollapse" ]; then
552 # If zero_cmd is finsert, don't check unaligned offsets
553 if [ "$zero_cmd" == "finsert" ]; then
557 echo " 16. data -> cache cold ->hole"
558 if [ "$remove_testfile" ]; then
562 cp $testfile $testfile.2
564 $XFS_IO_PROG -f -c "truncate $_20k" \
565 -c "pwrite $_8k $_12k" -c "fsync" $testfile.2 \
567 $XFS_IO_PROG -f -c "truncate $_20k" \
568 -c "pwrite 0 $_20k" $sync_cmd \
569 -c "$zero_cmd 0k $_8k" \
571 -c "$map_cmd -v" $testfile | $filter_cmd
572 diff $testfile $testfile.2
573 [ $? -ne 0 ] && die_now
575 _md5_checksum $testfile
577 # different file sizes mean we can't use md5sum to check the hole is
578 # valid. Hence use hexdump to dump the contents and chop off the last
579 # line of output that indicates the file size. We also have to fudge
580 # the extent size as that will change with file size, too - that's what
581 # the sed line noise does - it will always result in an output of [0..7]
582 # so it matches 4k block size...
583 echo " 17. data -> hole in single block file"
584 if [ "$remove_testfile" ]; then
587 block_size=`_get_block_size $TEST_DIR`
588 $XFS_IO_PROG -f -c "truncate $block_size" \
589 -c "pwrite 0 $block_size" $sync_cmd \
590 -c "$zero_cmd 128 128" \
591 -c "$map_cmd -v" $testfile | $filter_cmd | \
592 sed -e "s/\.\.[0-9]*\]/..7\]/"
593 [ $? -ne 0 ] && die_now
594 od -x $testfile | head -n -1
597 _test_block_boundaries()
604 while getopts 'dk' OPTION
616 shift $(($OPTIND - 1))
631 # Block size multiplied by 2
634 # Block size divided by 2
638 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
639 -c "pwrite -S 0x42 $bs $bs" \
641 -c "pread -v 0 $bs_t2" \
642 $testfile | $filter_cmd
644 echo "zero 0, $bs_m1"
645 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
646 -c "pwrite -S 0x42 $bs $bs" \
647 -c "$zero_cmd 0 $bs_m1" \
648 -c "pread -v 0 $bs_t2" \
649 $testfile | $filter_cmd
652 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
653 -c "pwrite -S 0x42 $bs $bs" \
654 -c "$zero_cmd 0 $bs" \
655 -c "pread -v 0 $bs_t2" \
656 $testfile | $filter_cmd
658 echo "zero 0, $bs_p1"
659 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
660 -c "pwrite -S 0x42 $bs $bs" \
661 -c "$zero_cmd 0 $bs_p1" \
662 -c "pread -v 0 $bs_t2" \
663 $testfile | $filter_cmd
665 echo "zero $bs_m1, $bs"
666 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
667 -c "pwrite -S 0x42 $bs $bs" \
668 -c "$zero_cmd $bs_m1 $bs" \
669 -c "pread -v 0 $bs_t2" \
670 $testfile | $filter_cmd
672 echo "zero $bs_m1, $bs_p1"
673 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
674 -c "pwrite -S 0x42 $bs $bs" \
675 -c "$zero_cmd $bs_m1 $bs_p1" \
676 -c "pread -v 0 $bs_t2" \
677 $testfile | $filter_cmd
679 echo "zero $bs_m1, $bs_p2"
680 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
681 -c "pwrite -S 0x42 $bs $bs" \
682 -c "$zero_cmd $bs_m1 $bs_p2" \
683 -c "pread -v 0 $bs_t2" \
684 $testfile | $filter_cmd
688 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
689 -c "pwrite -S 0x42 $bs $bs" \
690 -c "$zero_cmd $bs $bs" \
691 -c "pread -v 0 $bs_t2" \
692 $testfile | $filter_cmd
695 echo "zero $bs_d2 , $bs"
696 $XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
697 -c "pwrite -S 0x42 $bs $bs" \
698 -c "$zero_cmd $bs_d2 $bs" \
699 -c "pread -v 0 $bs_t2" \
700 $testfile | $filter_cmd