1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
#!/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 <http://www.gnu.org/licenses/>.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
print_ver_ cp
if fiemap_capable_ . ; 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_
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.
$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.
# 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
# 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
|