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 umount $SCRATCH_MNT >/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:]]{2}/ {
212 print $1, $2, "unwritten";
215 $5 ~ /0x[[:xdigit:]]+/ {
216 print $1, $2, "data";
221 # Filters fiemap output to only print the
222 # file offset column and whether or not
223 # it is an extent or a hole
224 _filter_hole_fiemap()
231 $5 ~ /0x[[:xdigit:]]+/ {
232 print $1, $2, "extent";
238 # Prints the md5 checksum of a given file
241 md5sum $1 | cut -d ' ' -f1
252 print $1, $2, "unwritten";
267 # test the different corner cases for zeroing a range:
270 # 2. into allocated space
271 # 3. into unwritten space
273 # 5. hole -> unwritten
275 # 7. data -> unwritten
276 # 8. unwritten -> hole
277 # 9. unwritten -> data
278 # 10. hole -> data -> hole
279 # 11. data -> hole -> data
280 # 12. unwritten -> data -> unwritten
281 # 13. data -> unwritten -> data
282 # 14. data -> hole @ EOF
283 # 15. data -> hole @ 0
284 # 16. data -> cache cold ->hole
285 # 17. data -> hole in single block file
287 # Test file is removed, created and sync'd between tests.
289 # Use -k flag to keep the file between tests. This will
290 # test the handling of pre-existing holes.
292 # Use the -d flag to not sync the file between tests.
293 # This will test the handling of delayed extents
295 _test_generic_punch()
301 while getopts 'dk' OPTION
313 shift $(($OPTIND - 1))
317 zero_cmd=$3 #if not testing zero just set to punch
321 xfs_io_opt=$7 #needs to be -F if not testing xfs
323 echo " 1. into a hole"
324 if [ "$remove_testfile" ]; then
327 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
328 -c "$zero_cmd 4k 8k" \
329 -c "$map_cmd -v" $testfile | $filter_cmd
330 [ $? -ne 0 ] && die_now
331 _md5_checksum $testfile
333 echo " 2. into allocated space"
334 if [ "$remove_testfile" ]; then
337 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
338 -c "pwrite 0 20k" $sync_cmd \
339 -c "$zero_cmd 4k 8k" \
340 -c "$map_cmd -v" $testfile | $filter_cmd
341 [ $? -ne 0 ] && die_now
342 _md5_checksum $testfile
344 echo " 3. into unwritten space"
345 if [ "$remove_testfile" ]; then
348 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
349 -c "$alloc_cmd 0 20k" \
350 -c "$zero_cmd 4k 8k" \
351 -c "$map_cmd -v" $testfile | $filter_cmd
352 [ $? -ne 0 ] && die_now
353 _md5_checksum $testfile
355 echo " 4. hole -> data"
356 if [ "$remove_testfile" ]; then
359 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
360 -c "pwrite 8k 8k" $sync_cmd \
361 -c "$zero_cmd 4k 8k" \
362 -c "$map_cmd -v" $testfile | $filter_cmd
363 [ $? -ne 0 ] && die_now
364 _md5_checksum $testfile
366 echo " 5. hole -> unwritten"
367 if [ "$remove_testfile" ]; then
370 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
371 -c "$alloc_cmd 8k 8k" \
372 -c "$zero_cmd 4k 8k" \
373 -c "$map_cmd -v" $testfile | $filter_cmd
374 [ $? -ne 0 ] && die_now
375 _md5_checksum $testfile
377 echo " 6. data -> hole"
378 if [ "$remove_testfile" ]; then
381 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
382 -c "pwrite 0 8k" $sync_cmd \
383 -c "$zero_cmd 4k 8k" \
384 -c "$map_cmd -v" $testfile | $filter_cmd
385 [ $? -ne 0 ] && die_now
386 _md5_checksum $testfile
388 echo " 7. data -> unwritten"
389 if [ "$remove_testfile" ]; then
392 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
393 -c "pwrite 0 8k" $sync_cmd \
394 -c "$alloc_cmd 8k 8k" \
395 -c "$zero_cmd 4k 8k" \
396 -c "$map_cmd -v" $testfile | $filter_cmd
397 [ $? -ne 0 ] && die_now
398 _md5_checksum $testfile
400 echo " 8. unwritten -> hole"
401 if [ "$remove_testfile" ]; then
404 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
405 -c "$alloc_cmd 0 8k" \
406 -c "$zero_cmd 4k 8k" \
407 -c "$map_cmd -v" $testfile | $filter_cmd
408 [ $? -ne 0 ] && die_now
409 _md5_checksum $testfile
411 echo " 9. unwritten -> data"
412 if [ "$remove_testfile" ]; then
415 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
416 -c "$alloc_cmd 0 8k" \
417 -c "pwrite 8k 8k" $sync_cmd \
418 -c "$zero_cmd 4k 8k" \
419 -c "$map_cmd -v" $testfile | $filter_cmd
420 [ $? -ne 0 ] && die_now
421 _md5_checksum $testfile
423 echo " 10. hole -> data -> hole"
424 if [ "$remove_testfile" ]; then
427 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
428 -c "pwrite 8k 4k" $sync_cmd \
429 -c "$zero_cmd 4k 12k" \
430 -c "$map_cmd -v" $testfile | $filter_cmd
431 [ $? -ne 0 ] && die_now
432 _md5_checksum $testfile
434 echo " 11. data -> hole -> data"
435 if [ "$remove_testfile" ]; then
438 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
439 -c "$alloc_cmd 0 20k" \
441 -c "pwrite 12k 8k" $sync_cmd \
442 -c "$punch_cmd 8k 4k" \
443 -c "$zero_cmd 4k 12k" \
444 -c "$map_cmd -v" $testfile | $filter_cmd
445 [ $? -ne 0 ] && die_now
446 _md5_checksum $testfile
448 echo " 12. unwritten -> data -> unwritten"
449 if [ "$remove_testfile" ]; then
452 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
453 -c "$alloc_cmd 0 20k" \
454 -c "pwrite 8k 4k" $sync_cmd \
455 -c "$zero_cmd 4k 12k" \
456 -c "$map_cmd -v" $testfile | $filter_cmd
457 [ $? -ne 0 ] && die_now
458 _md5_checksum $testfile
460 echo " 13. data -> unwritten -> data"
461 if [ "$remove_testfile" ]; then
464 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
465 -c "$alloc_cmd 0 20k" \
466 -c "pwrite 0k 8k" $sync_cmd \
467 -c "pwrite 12k 8k" -c "fsync" \
468 -c "$zero_cmd 4k 12k" \
469 -c "$map_cmd -v" $testfile | $filter_cmd
470 [ $? -ne 0 ] && die_now
471 _md5_checksum $testfile
473 echo " 14. data -> hole @ EOF"
475 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
476 -c "pwrite 0 20k" $sync_cmd \
477 -c "$zero_cmd 12k 8k" \
478 -c "$map_cmd -v" $testfile | $filter_cmd
479 [ $? -ne 0 ] && die_now
480 _md5_checksum $testfile
482 echo " 15. data -> hole @ 0"
483 if [ "$remove_testfile" ]; then
486 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
487 -c "pwrite 0 20k" $sync_cmd \
488 -c "$zero_cmd 0k 8k" \
489 -c "$map_cmd -v" $testfile | $filter_cmd
490 [ $? -ne 0 ] && die_now
491 _md5_checksum $testfile
493 echo " 16. data -> cache cold ->hole"
494 if [ "$remove_testfile" ]; then
498 cp $testfile $testfile.2
500 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
501 -c "pwrite 8k 12k" -c "fsync" $testfile.2 \
503 $XFS_IO_PROG $xfs_io_opt -f -c "truncate 20k" \
504 -c "pwrite 0 20k" $sync_cmd \
505 -c "$zero_cmd 0k 8k" \
507 -c "$map_cmd -v" $testfile | $filter_cmd
508 diff $testfile $testfile.2
509 [ $? -ne 0 ] && die_now
511 _md5_checksum $testfile
513 echo " 17. data -> hole in single block file"
514 if [ "$remove_testfile" ]; then
517 block_size=`stat -f $TEST_DEV | grep "Block size" | cut -d " " -f3`
518 $XFS_IO_PROG $xfs_io_opt -f -c "truncate $block_size" \
519 -c "pwrite 0 $block_size" $sync_cmd \
520 -c "$zero_cmd 128 128" \
521 -c "$map_cmd -v" $testfile | $filter_cmd
522 [ $? -ne 0 ] && die_now
523 _md5_checksum $testfile