From dc05bc7ee26495af613a1741d8c53e171862ddab Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Fri, 21 May 2010 18:28:42 +0200 Subject: tests: exercise more of the new FIEMAP copying code * tests/cp/sparse-fiemap: Ensure that a file with many extents (more than fit in copy.c's internal buffer) is copied properly. Don't require root access if current partition is btrfs or xfs. Use init.sh, not test-lib.sh. * tests/filefrag-extent-compare: New file. --- tests/cp/sparse-fiemap | 100 ++++++++++++++++++++++++++++++++++-------- tests/filefrag-extent-compare | 68 ++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 19 deletions(-) create mode 100644 tests/filefrag-extent-compare (limited to 'tests') diff --git a/tests/cp/sparse-fiemap b/tests/cp/sparse-fiemap index 21b02acac..dc0cf6059 100755 --- a/tests/cp/sparse-fiemap +++ b/tests/cp/sparse-fiemap @@ -1,7 +1,7 @@ #!/bin/sh # Test cp --sparse=always through fiemap copy -# Copyright (C) 2006-2010 Free Software Foundation, Inc. +# Copyright (C) 2010 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 @@ -21,29 +21,34 @@ if test "$VERBOSE" = yes; then cp --version fi -. $srcdir/test-lib.sh -require_root_ +. "${srcdir=.}/init.sh"; path_prepend_ ../src -cwd=`pwd` -cleanup_() { cd /; umount "$cwd/mnt"; } +if df -T -t btrfs -t xfs -t ext4 -t ocfs2 . ; then + : # Current dir is on a partition with working extents. Good! +else + # It's not; we need to create one, hence we need root access. + require_root_ -skip=0 -# Create an ext4 loopback file system -dd if=/dev/zero of=blob bs=8192 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 + cwd=$PWD + cleanup_() { cd /; umount "$cwd/mnt"; } -test $skip = 1 && - skip_test_ "insufficient mount/ext4 support" + 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 -# Create a 1TiB sparse file -dd if=/dev/zero of=mnt/sparse bs=1k count=1 seek=1G || framework_failure + test $skip = 1 && + skip_test_ "insufficient mount/ext4 support" +fi +# Create a 1TiB sparse file +dd if=/dev/zero of=sparse bs=1k count=1 seek=1G || framework_failure # It takes many minutes to copy this sparse file using the old method. # By contrast, it takes far less than 1 second using FIEMAP-copy. @@ -53,4 +58,61 @@ timeout 10 cp --sparse=always sparse fiemap || fail=1 # in bytes as the original. test $(stat --printf %s sparse) = $(stat --printf %s fiemap) || fail=1 +# ================================================= +# 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. + +$PERL -e 1 || skip_test_ 'skipping part of this test; you lack perl' + +# 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. +# That is required when that final extent has no number in the "expected" field. +f() +{ + sed 's/ eof$//' $@ \ + | 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 + # sync + cp --sparse=always j1 j2 || fail=1 + # sync + # Technically we may need the 'sync' uses above, but + # uncommenting them makes this test take much longer. + + cmp j1 j2 || fail=1 + filefrag -v j1 | grep extent \ + || skip_test_ 'skipping part of this test; you lack filefrag' + + # 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 || fail=1 + filefrag -v j2 > ff2 || fail=1 + { f ff1; f ff2; } \ + | $PERL $abs_top_srcdir/tests/filefrag-extent-compare \ + || { fail=1; break; } + done + test $fail = 1 && break +done + Exit $fail diff --git a/tests/filefrag-extent-compare b/tests/filefrag-extent-compare new file mode 100644 index 000000000..3c095d52f --- /dev/null +++ b/tests/filefrag-extent-compare @@ -0,0 +1,68 @@ +eval '(exit $?0)' && eval 'exec perl -wS "$0" ${1+"$@"}' + & eval 'exec perl -wS "$0" $argv:q' + if 0; +# Determine whether two files have the same extents by comparing +# the logical block numbers and lengths from filefrag -v for each. + +# Invoke like this: +# This helper function, f, extracts logical block number and lengths. +# f() { awk '/^ *[0-9]/ {printf "%d %d ",$2,NF<5?$NF:$5} END {print ""}'; } +# { filefrag -v j1 | f; filefrag -v j2 | f; } | ./filefrag-extent-compare + +use warnings; +use strict; +(my $ME = $0) =~ s|.*/||; + +my @line = <>; +my $n_lines = @line; +$n_lines == 2 + or die "$ME: expected exactly two input lines; got $n_lines\n"; + +my @A = split ' ', $line[0]; +my @B = split ' ', $line[1]; +@A % 2 || @B % 2 + and die "$ME: unexpected input: odd number of numbers; expected even\n"; + +my @a; +my @b; +foreach my $i (0..@A/2-1) { $a[$i] = { L_BLK => $A[2*$i], LEN => $A[2*$i+1] } }; +foreach my $i (0..@B/2-1) { $b[$i] = { L_BLK => $B[2*$i], LEN => $B[2*$i+1] } }; + +my $i = 0; +my $j = 0; +while (1) + { + !defined $a[$i] && !defined $b[$j] + and exit 0; + defined $a[$i] && defined $b[$j] + or die "\@a and \@b have different lengths, even after adjustment\n"; + ($a[$i]->{L_BLK} == $b[$j]->{L_BLK} + && $a[$i]->{LEN} == $b[$j]->{LEN}) + and next; + ($a[$i]->{LEN} < $b[$j]->{LEN} + && exists $a[$i+1] && $a[$i]->{LEN} + $a[$i+1]->{LEN} == $b[$j]->{LEN}) + and ++$i, next; + exists $b[$j+1] && $a[$i]->{LEN} == $b[$i]->{LEN} + $b[$i+1]->{LEN} + and ++$j, next; + die "differing extent:\n" + . " [$i]=$a[$i]->{L_BLK} $a[$i]->{LEN}\n" + . " [$j]=$b[$j]->{L_BLK} $b[$j]->{LEN}\n" + } +continue + { + ++$i; + ++$j; + } + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## mode: perl +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## perl-extra-newline-before-brace: t +## perl-merge-trailing-else: nil +## End: -- cgit v1.2.3-70-g09d2