shared,generic: move tests using duperemove to generic/
[xfstests-dev.git] / common / reflink
1 ##/bin/bash
2 # SPDX-License-Identifier: GPL-2.0+
3 # Copyright (c) 2015 Oracle.  All Rights Reserved.
4 #
5 # Routines for reflinking, deduping, and comparing parts of files.
6
7 # Check that cp has a reflink argument
8 _require_cp_reflink()
9 {
10        cp --help | grep -q reflink || \
11                _notrun "This test requires a cp with --reflink support."
12 }
13
14 # Can we reflink between arbitrary file sets?
15 # i.e. if we reflink a->b and c->d, can we later share
16 # blocks between b & c?
17 _supports_arbitrary_fileset_reflink()
18 {
19         test "$FSTYP" != "ocfs2"
20 }
21
22 _require_arbitrary_fileset_reflink()
23 {
24         _supports_arbitrary_fileset_reflink ||
25                 _notrun "reflink between arbitrary file groups not supported in $FSTYP"
26 }
27
28 # Given 2 files, verify that they have the same mapping but different
29 # inodes - i.e. an undisturbed reflink
30 # Silent if so, make noise if not
31 _verify_reflink()
32 {
33        # not a hard link or symlink?
34        cmp -s  <(stat -c '%i' $1) <(stat -c '%i' $2) \
35                && echo "$1 and $2 are not reflinks: same inode number"
36
37        # same mapping?
38        diff -u <($XFS_IO_PROG -c "fiemap" $1 | grep -v $1) \
39                <($XFS_IO_PROG -c "fiemap" $2 | grep -v $2) \
40                || echo "$1 and $2 are not reflinks: different extents"
41 }
42
43 # New reflink/dedupe helpers
44
45 # this test requires the test fs support reflink...
46 _require_test_reflink()
47 {
48         _require_test
49         _require_xfs_io_command "reflink"
50
51         rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
52         $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$TEST_DIR/file1" > /dev/null
53         $XFS_IO_PROG -f -c "reflink $TEST_DIR/file1 0 0 65536" "$TEST_DIR/file2" > /dev/null
54         if [ ! -s "$TEST_DIR/file2" ]; then
55                 rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
56                 _notrun "Reflink not supported by test filesystem type: $FSTYP"
57         fi
58         rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
59 }
60
61 # this test requires the scratch fs support reflink...
62 _require_scratch_reflink()
63 {
64         _require_scratch
65         _require_xfs_io_command "reflink"
66
67         _scratch_mkfs > /dev/null
68         _scratch_mount
69         $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$SCRATCH_MNT/file1" > /dev/null
70         $XFS_IO_PROG -f -c "reflink $SCRATCH_MNT/file1 0 0 65536" "$SCRATCH_MNT/file2" > /dev/null
71         if [ ! -s "$SCRATCH_MNT/file2" ]; then
72                 _scratch_unmount
73                 _notrun "Reflink not supported by scratch filesystem type: $FSTYP"
74         fi
75         _scratch_unmount
76 }
77
78 # this test requires duperemove working for the file system
79 _require_scratch_duperemove()
80 {
81         _require_scratch
82         _require_command "$DUPEREMOVE_PROG" duperemove
83
84         _scratch_mkfs > /dev/null
85         _scratch_mount
86         dd if=/dev/zero of="$SCRATCH_MNT/file1" bs=128k count=1 >& /dev/null
87         dd if=/dev/zero of="$SCRATCH_MNT/file2" bs=128k count=1 >& /dev/null
88         if ! "$DUPEREMOVE_PROG" -d "$SCRATCH_MNT/file1" \
89             "$SCRATCH_MNT/file2" >& /dev/null ; then
90                 _scratch_unmount
91                 _notrun "duperemove does not support file system type: $FSTYP"
92         fi
93         _scratch_unmount
94 }
95
96 # this test requires scratch fs to report explicit SHARED flag
97 # e.g.
98 #   0         4K         8K
99 #    / File1: Extent 0  \
100 #   /                    \
101 #   |<- On disk Extent-->|
102 #   |        /
103 #   | File2 /
104 #     Extent: 0
105 # Fs supports explicit SHARED extent reporting should report fiemap like:
106 # File1: 2 extents
107 # Extent 0-4K: SHARED
108 # Extent 4-8K:
109 # File2: 1 extents
110 # Extent 0-4K: SHARED
111 #
112 # Fs doesn't support explicit reporting will report fiemap like:
113 # File1: 1 extent
114 # Extent 0-8K: SHARED
115 # File2: 1 extent
116 # Extent 0-4K: SHARED
117 _require_scratch_explicit_shared_extents()
118 {
119         _require_scratch
120         _require_xfs_io_command "fiemap"
121         _require_scratch_reflink
122         _require_xfs_io_command "reflink"
123         local nr_extents
124
125         _scratch_mkfs > /dev/null
126         _scratch_mount
127
128         _pwrite_byte 0x61 0 128k $SCRATCH_MNT/file1 >/dev/null
129         _reflink_range $SCRATCH_MNT/file1 0 $SCRATCH_MNT/file2 0 64k >/dev/null
130
131         _scratch_cycle_mount
132
133         nr_extents=$(_count_extents $SCRATCH_MNT/file1)
134         if [ $nr_extents -eq 1 ]; then
135                 _notrun "Explicit SHARED flag reporting not support by filesystem type: $FSTYP"
136         fi
137         _scratch_unmount
138 }
139
140 # this test requires the test fs support dedupe...
141 _require_test_dedupe()
142 {
143         _require_test
144         _require_xfs_io_command "dedupe"
145
146         rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
147         $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$TEST_DIR/file1" > /dev/null
148         $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$TEST_DIR/file2" > /dev/null
149         testio="$($XFS_IO_PROG -f -c "dedupe $TEST_DIR/file1 0 0 65536" "$TEST_DIR/file2" 2>&1)"
150         echo $testio | grep -q "Operation not supported" && \
151                 _notrun "Dedupe not supported by test filesystem type: $FSTYP"
152         echo $testio | grep -q "Inappropriate ioctl for device" && \
153                 _notrun "Dedupe not supported by test filesystem type: $FSTYP"
154         echo $testio | grep -q "Invalid argument" && \
155                 _notrun "Dedupe not supported by test filesystem type: $FSTYP"
156         rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
157 }
158
159 # this test requires the scratch fs support dedupe...
160 _require_scratch_dedupe()
161 {
162         _require_scratch
163         _require_xfs_io_command "dedupe"
164
165         _scratch_mkfs > /dev/null
166         _scratch_mount
167         $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$SCRATCH_MNT/file1" > /dev/null
168         $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$SCRATCH_MNT/file2" > /dev/null
169         testio="$($XFS_IO_PROG -f -c "dedupe $SCRATCH_MNT/file1 0 0 65536" "$SCRATCH_MNT/file2" 2>&1)"
170         echo $testio | grep -q "Operation not supported" && \
171                 _notrun "Dedupe not supported by scratch filesystem type: $FSTYP"
172         echo $testio | grep -q "Inappropriate ioctl for device" && \
173                 _notrun "Dedupe not supported by scratch filesystem type: $FSTYP"
174         echo $testio | grep -q "Invalid argument" && \
175                 _notrun "Dedupe not supported by scratch filesystem type: $FSTYP"
176         _scratch_unmount
177 }
178
179 # Prints a range of a file as a hex dump
180 _read_range() {
181         file="$1"
182         offset="$2"
183         len="$3"
184         xfs_io_args="$4"
185
186         $XFS_IO_PROG $xfs_io_args -f -c "pread -q -v $offset $len" "$file" | cut -d ' ' -f '3-18'
187 }
188
189 # Compare ranges of two files
190 _compare_range() {
191         file1="$1"
192         offset1="$2"
193         file2="$3"
194         offset2="$4"
195         len="$5"
196
197         cmp -s <(_read_range "$file1" "$offset1" "$len") \
198                <(_read_range "$file2" "$offset2" "$len")
199 }
200
201 # Prints the md5 checksum of a hexdump of a part of a given file
202 _md5_range_checksum() {
203         file="$1"
204         offset="$2"
205         len="$3"
206
207         md5sum <(_read_range "$file" "$offset" "$len") | cut -d ' ' -f 1
208 }
209
210 # Reflink some file1 into file2 via cp
211 _cp_reflink() {
212         file1="$1"
213         file2="$2"
214
215         cp --reflink=always -p -f "$file1" "$file2"
216 }
217
218 # Reflink some file1 into file2
219 _reflink() {
220         file1="$1"
221         file2="$2"
222
223         $XFS_IO_PROG -f -c "reflink $file1" "$file2"
224 }
225
226 # Reflink some part of file1 into another part of file2
227 _reflink_range() {
228         file1="$1"
229         offset1="$2"
230         file2="$3"
231         offset2="$4"
232         len="$5"
233         xfs_io_args="$6"
234
235         $XFS_IO_PROG $xfs_io_args -f -c "reflink $file1 $offset1 $offset2 $len" "$file2"
236 }
237
238 # Dedupe some part of file1 into another part of file2
239 _dedupe_range() {
240         file1="$1"
241         offset1="$2"
242         file2="$3"
243         offset2="$4"
244         len="$5"
245         xfs_io_args="$6"
246
247         $XFS_IO_PROG $xfs_io_args -f -c "dedupe $file1 $offset1 $offset2 $len" "$file2"
248 }
249
250 # Unify xfs_io dedupe ioctl error message prefix
251 _filter_dedupe_error()
252 {
253         sed -e 's/^dedupe:/XFS_IOC_FILE_EXTENT_SAME:/g'
254 }
255
256 # Create a file of interleaved unwritten and reflinked blocks
257 _weave_reflink_unwritten() {
258         blksz=$1
259         nr=$2
260         sfile=$3
261         dfile=$4
262
263         _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
264         $XFS_IO_PROG -f -c "falloc 0 $((blksz * nr))" $dfile
265         _pwrite_byte 0x00 0 $((blksz * nr)) $dfile.chk
266         seq 0 2 $((nr - 1)) | while read i; do
267                 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
268                 _pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
269         done
270 }
271
272 # Create a file of interleaved holes and reflinked blocks
273 _weave_reflink_holes() {
274         blksz=$1
275         nr=$2
276         sfile=$3
277         dfile=$4
278
279         _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
280         $XFS_IO_PROG -f -c "truncate $((blksz * nr))" $dfile
281         _pwrite_byte 0x00 0 $((blksz * nr)) $dfile.chk
282         seq 0 2 $((nr - 1)) | while read i; do
283                 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
284                 _pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
285         done
286 }
287
288 # For a file created with _weave_reflink_holes, fill the holes with delalloc
289 # extents
290 _weave_reflink_holes_delalloc() {
291         blksz=$1
292         nr=$2
293         dfile=$3
294
295         seq 1 2 $((nr - 1)) | while read i; do
296                 _pwrite_byte 0x62 $((blksz * i)) $blksz $dfile
297                 _pwrite_byte 0x62 $((blksz * i)) $blksz $dfile.chk
298         done
299 }
300
301 # Create a file of interleaved regular blocks and reflinked blocks
302 _weave_reflink_regular() {
303         blksz=$1
304         nr=$2
305         sfile=$3
306         dfile=$4
307
308         _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
309         _pwrite_byte 0x62 0 $((blksz * nr)) $dfile
310         _pwrite_byte 0x62 0 $((blksz * nr)) $dfile.chk
311         seq 0 2 $((nr - 1)) | while read i; do
312                 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
313                 _pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
314         done
315 }
316
317 # Create a file of interleaved holes, unwritten blocks, regular blocks, and
318 # reflinked blocks
319 _weave_reflink_rainbow() {
320         blksz=$1
321         nr=$2
322         sfile=$3
323         dfile=$4
324
325         _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
326         $XFS_IO_PROG -f -c "truncate $((blksz * nr))" $dfile
327         _pwrite_byte 0x00 0 $((blksz * nr)) $dfile.chk
328         # 0 blocks are reflinked
329         seq 0 5 $((nr - 1)) | while read i; do
330                 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
331                 _pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
332         done
333         # 1 blocks are unwritten
334         seq 1 5 $((nr - 1)) | while read i; do
335                 $XFS_IO_PROG -f -c "falloc $((blksz * i)) $blksz" $dfile
336                 _pwrite_byte 0x00 $((blksz * i)) $blksz $dfile.chk
337         done
338         # 2 blocks are holes
339         seq 2 5 $((nr - 1)) | while read i; do
340                 _pwrite_byte 0x00 $((blksz * i)) $blksz $dfile.chk
341         done
342         # 3 blocks are regular
343         seq 3 5 $((nr - 1)) | while read i; do
344                 _pwrite_byte 0x71 $((blksz * i)) $blksz $dfile
345                 _pwrite_byte 0x71 $((blksz * i)) $blksz $dfile.chk
346         done
347         # 4 blocks will be delalloc later
348 }
349
350 # For a file created with _weave_reflink_rainbow, fill the holes with delalloc
351 # extents
352 _weave_reflink_rainbow_delalloc() {
353         blksz=$1
354         nr=$2
355         dfile=$3
356
357         # 4 blocks are delalloc (do later)
358         seq 4 5 $((nr - 1)) | while read i; do
359                 _pwrite_byte 0x62 $((blksz * i)) $blksz $dfile
360                 _pwrite_byte 0x62 $((blksz * i)) $blksz $dfile.chk
361         done
362 }
363
364 # Make the source file have interleaved regular blocks and reflinked blocks
365 _sweave_reflink_regular() {
366         blksz=$1
367         nr=$2
368         sfile=$3
369         dfile=$4
370
371         _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
372         _pwrite_byte 0x62 0 $((blksz * nr)) $dfile
373         _pwrite_byte 0x61 0 $((blksz * nr)) $sfile.chk
374         seq 1 2 $((nr - 1)) | while read i; do
375                 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
376         done
377 }
378
379 # Make the source file have interleaved unwritten blocks and reflinked blocks
380 _sweave_reflink_unwritten() {
381         blksz=$1
382         nr=$2
383         sfile=$3
384         dfile=$4
385
386         $XFS_IO_PROG -f -c "falloc 0 $((blksz * nr))" $sfile
387         _pwrite_byte 0x00 0 $((blksz * nr)) $sfile.chk
388         _pwrite_byte 0x62 0 $((blksz * nr)) $dfile
389         seq 1 2 $((nr - 1)) | while read i; do
390                 _pwrite_byte 0x61 $((blksz * i)) $blksz $sfile
391                 _pwrite_byte 0x61 $((blksz * i)) $blksz $sfile.chk
392         done
393         seq 1 2 $((nr - 1)) | while read i; do
394                 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
395         done
396 }
397
398 # Make the source file have interleaved holes and reflinked blocks
399 _sweave_reflink_holes() {
400         blksz=$1
401         nr=$2
402         sfile=$3
403         dfile=$4
404
405         $XFS_IO_PROG -f -c "truncate $((blksz * nr))" $sfile
406         _pwrite_byte 0x00 0 $((blksz * nr)) $sfile.chk
407         _pwrite_byte 0x62 0 $((blksz * nr)) $dfile
408         seq 1 2 $((nr - 1)) | while read i; do
409                 _pwrite_byte 0x61 $((blksz * i)) $blksz $sfile
410                 _pwrite_byte 0x61 $((blksz * i)) $blksz $sfile.chk
411         done
412         seq 1 2 $((nr - 1)) | while read i; do
413                 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
414         done
415 }
416
417 # For a file created with _sweave_reflink_holes, fill the holes with delalloc
418 # extents
419 _sweave_reflink_holes_delalloc() {
420         blksz=$1
421         nr=$2
422         sfile=$3
423
424         seq 0 2 $((nr - 1)) | while read i; do
425                 _pwrite_byte 0x64 $((blksz * i)) $blksz $sfile
426                 _pwrite_byte 0x64 $((blksz * i)) $blksz $sfile.chk
427         done
428 }