summaryrefslogtreecommitdiff
path: root/tests/cp/sparse-fiemap
blob: 907ccbdbc6db13296a82b97817aa551dc4c0a14e (plain)
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
#!/bin/sh
# Test cp --sparse=always through fiemap copy

# 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
# 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/>.

if test "$VERBOSE" = yes; then
  set -x
  cp --version
fi

. "${srcdir=.}/init.sh"; path_prepend_ ../src

if df -T -t btrfs -t xfs . ; 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 XFS loopback file system
  dd if=/dev/zero of=blob bs=32k count=1000 || skip=1
  mkdir mnt
  mkfs -t xfs blob ||
    skip_test_ "failed to create XFS 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/XFS 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.
timeout 10 cp --sparse=always sparse fiemap || fail=1

# Ensure that the sparse file copied through fiemap has the same size
# 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'

for i in $(seq 20); 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, "."x$n) or die "$!"}' > j1 || fail=1

    cp --sparse=always j1 j2 || fail=1
    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 | awk '/^ / {print $1,$2}' > ff1 || fail=1
    filefrag -v j2 | awk '/^ / {print $1,$2}' > ff2 || fail=1
    compare ff1 ff2 || fail=1
  done
done

Exit $fail