2 # SPDX-License-Identifier: GPL-2.0+
3 # Copyright (c) 2015 Oracle. All Rights Reserved.
5 # Routines for reflinking, deduping, and comparing parts of files.
7 # Check that cp has a reflink argument
10 cp --help | grep -q reflink || \
11 _notrun "This test requires a cp with --reflink support."
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()
19 test "$FSTYP" != "ocfs2"
22 _require_arbitrary_fileset_reflink()
24 _supports_arbitrary_fileset_reflink ||
25 _notrun "reflink between arbitrary file groups not supported in $FSTYP"
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
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"
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"
43 # New reflink/dedupe helpers
45 # this test requires the test fs support reflink...
46 _require_test_reflink()
49 _require_xfs_io_command "reflink"
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"
58 rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
61 # this test requires the scratch fs support reflink...
62 _require_scratch_reflink()
65 _require_xfs_io_command "reflink"
67 _scratch_mkfs > /dev/null
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
73 _notrun "Reflink not supported by scratch filesystem type: $FSTYP"
78 # this test requires duperemove working for the file system
79 _require_scratch_duperemove()
82 _require_command "$DUPEREMOVE_PROG" duperemove
84 _scratch_mkfs > /dev/null
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
91 _notrun "duperemove does not support file system type: $FSTYP"
96 # this test requires scratch fs to report explicit SHARED flag
101 # |<- On disk Extent-->|
105 # Fs supports explicit SHARED extent reporting should report fiemap like:
107 # Extent 0-4K: SHARED
110 # Extent 0-4K: SHARED
112 # Fs doesn't support explicit reporting will report fiemap like:
114 # Extent 0-8K: SHARED
116 # Extent 0-4K: SHARED
117 _require_scratch_explicit_shared_extents()
120 _require_xfs_io_command "fiemap"
121 _require_scratch_reflink
122 _require_xfs_io_command "reflink"
125 _scratch_mkfs > /dev/null
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
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"
140 # this test requires the test fs support dedupe...
141 _require_test_dedupe()
144 _require_xfs_io_command "dedupe"
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"
159 # this test requires the scratch fs support dedupe...
160 _require_scratch_dedupe()
163 _require_xfs_io_command "dedupe"
165 _scratch_mkfs > /dev/null
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"
179 # Prints a range of a file as a hex dump
186 $XFS_IO_PROG $xfs_io_args -f -c "pread -q -v $offset $len" "$file" | cut -d ' ' -f '3-18'
189 # Compare ranges of two files
197 cmp -s <(_read_range "$file1" "$offset1" "$len") \
198 <(_read_range "$file2" "$offset2" "$len")
201 # Prints the md5 checksum of a hexdump of a part of a given file
202 _md5_range_checksum() {
207 md5sum <(_read_range "$file" "$offset" "$len") | cut -d ' ' -f 1
210 # Reflink some file1 into file2 via cp
215 cp --reflink=always -p -f "$file1" "$file2"
218 # Reflink some file1 into file2
223 $XFS_IO_PROG -f -c "reflink $file1" "$file2"
226 # Reflink some part of file1 into another part of file2
235 $XFS_IO_PROG $xfs_io_args -f -c "reflink $file1 $offset1 $offset2 $len" "$file2"
238 # Dedupe some part of file1 into another part of file2
247 $XFS_IO_PROG $xfs_io_args -f -c "dedupe $file1 $offset1 $offset2 $len" "$file2"
250 # Unify xfs_io dedupe ioctl error message prefix
251 _filter_dedupe_error()
253 sed -e 's/^dedupe:/XFS_IOC_FILE_EXTENT_SAME:/g'
256 # Create a file of interleaved unwritten and reflinked blocks
257 _weave_reflink_unwritten() {
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
272 # Create a file of interleaved holes and reflinked blocks
273 _weave_reflink_holes() {
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
288 # For a file created with _weave_reflink_holes, fill the holes with delalloc
290 _weave_reflink_holes_delalloc() {
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
301 # Create a file of interleaved regular blocks and reflinked blocks
302 _weave_reflink_regular() {
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
317 # Create a file of interleaved holes, unwritten blocks, regular blocks, and
319 _weave_reflink_rainbow() {
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
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
339 seq 2 5 $((nr - 1)) | while read i; do
340 _pwrite_byte 0x00 $((blksz * i)) $blksz $dfile.chk
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
347 # 4 blocks will be delalloc later
350 # For a file created with _weave_reflink_rainbow, fill the holes with delalloc
352 _weave_reflink_rainbow_delalloc() {
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
364 # Make the source file have interleaved regular blocks and reflinked blocks
365 _sweave_reflink_regular() {
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
379 # Make the source file have interleaved unwritten blocks and reflinked blocks
380 _sweave_reflink_unwritten() {
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
393 seq 1 2 $((nr - 1)) | while read i; do
394 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
398 # Make the source file have interleaved holes and reflinked blocks
399 _sweave_reflink_holes() {
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
412 seq 1 2 $((nr - 1)) | while read i; do
413 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
417 # For a file created with _sweave_reflink_holes, fill the holes with delalloc
419 _sweave_reflink_holes_delalloc() {
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