#!/bin/sh # Test cp --sparse=always through fiemap copy # Copyright (C) 2010-2011 Free Software Foundation, Inc. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . . "${srcdir=.}/init.sh"; path_prepend_ ../src print_ver_ cp $PERL -e 1 || skip_test_ 'you lack perl' # The test was seen to fail on ext3 so exclude that type # (or any file system where the type can't be determined) touch fiemap_chk if fiemap_capable_ fiemap_chk && ! df -t ext3 . >/dev/null; then : # Current partition has working extents. Good! else # It's not; we need to create one, hence we need root access. require_root_ cwd=$PWD cleanup_() { cd /; umount "$cwd/mnt"; } skip=0 # Create an ext4 loopback file system dd if=/dev/zero of=blob bs=32k count=1000 || skip=1 mkdir mnt mkfs -t ext4 -F blob || skip_test_ "failed to create ext4 file system" mount -oloop blob mnt || skip=1 cd mnt || skip=1 echo test > f || skip=1 test -s f || skip=1 test $skip = 1 && skip_test_ "insufficient mount/ext4 support" fi # ================================================= # Ensure that we exercise the FIEMAP-copying code enough # to provoke at least two iterations of the do...while loop # in which it calls ioctl (fd, FS_IOC_FIEMAP,... # This also verifies that non-trivial extents are preserved. # Extract logical block number and length pairs from filefrag -v output. # The initial sed is to remove the "eof" from the normally-empty "flags" field. # Similarly, remove flags values like "unknown,delalloc,eof". # That is required when that final extent has no number in the "expected" field. f() { sed 's/ [a-z,][a-z,]*$//' $@ \ | awk '/^ *[0-9]/ {printf "%d %d ", $2 ,NF < 5 ? $NF : $5 } END {print ""}' } for i in $(seq 1 2 21); do for j in 1 2 31 100; do $PERL -e 'BEGIN { $n = '$i' * 1024; *F = *STDOUT }' \ -e 'for (1..'$j') { sysseek (*F, $n, 1)' \ -e '&& syswrite (*F, chr($_)x$n) or die "$!"}' > j1 || fail=1 # Note there is an implicit sync performed by cp to # work around bugs in EXT4 and BTRFS before Linux 2.6.38 # Note also the -s parameter to the filefrag commands below # for the same reasons. cp --sparse=always j1 j2 || fail=1 cmp j1 j2 || fail=1 if ! filefrag -vs j1 | grep -F extent >/dev/null; then test $skip != 1 && warn_ 'skipping part; you lack filefrag' skip=1 else # Here is sample filefrag output: # $ perl -e 'BEGIN{$n=16*1024; *F=*STDOUT}' \ # -e 'for (1..5) { sysseek(*F,$n,1)' \ # -e '&& syswrite *F,"."x$n or die "$!"}' > j # $ filefrag -v j # File system type is: ef53 # File size of j is 163840 (40 blocks, blocksize 4096) # ext logical physical expected length flags # 0 4 6258884 4 # 1 12 6258892 6258887 4 # 2 20 6258900 6258895 4 # 3 28 6258908 6258903 4 # 4 36 6258916 6258911 4 eof # j: 6 extents found # exclude the physical block numbers; they always differ filefrag -v j1 > ff1 || framework_failure filefrag -vs j2 > ff2 || framework_failure { f ff1; f ff2; } | $PERL $abs_top_srcdir/tests/filefrag-extent-compare || fail=1 fi test $fail = 1 && break 2 done done Exit $fail