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