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 _require_arbitrary_fileset_reflink()
19 test "$FSTYP" = "ocfs2" && \
20 _notrun "reflink between arbitrary file groups not supported in $FSTYP"
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
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"
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"
38 # New reflink/dedupe helpers
40 # this test requires the test fs support reflink...
41 _require_test_reflink()
44 _require_xfs_io_command "reflink"
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"
53 rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
56 # this test requires the scratch fs support reflink...
57 _require_scratch_reflink()
60 _require_xfs_io_command "reflink"
62 _scratch_mkfs > /dev/null
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
68 _notrun "Reflink not supported by scratch filesystem type: $FSTYP"
73 # this test requires scratch fs to report explicit SHARED flag
78 # |<- On disk Extent-->|
82 # Fs supports explicit SHARED extent reporting should report fiemap like:
89 # Fs doesn't support explicit reporting will report fiemap like:
94 _require_scratch_explicit_shared_extents()
97 _require_xfs_io_command "fiemap"
98 _require_scratch_reflink
99 _require_xfs_io_command "reflink"
102 _scratch_mkfs > /dev/null
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
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"
117 # this test requires the test fs support dedupe...
118 _require_test_dedupe()
121 _require_xfs_io_command "dedupe"
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"
136 # this test requires the scratch fs support dedupe...
137 _require_scratch_dedupe()
140 _require_xfs_io_command "dedupe"
142 _scratch_mkfs > /dev/null
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 scratch filesystem type: $FSTYP"
149 echo $testio | grep -q "Inappropriate ioctl for device" && \
150 _notrun "Dedupe not supported by scratch filesystem type: $FSTYP"
151 echo $testio | grep -q "Invalid argument" && \
152 _notrun "Dedupe not supported by scratch filesystem type: $FSTYP"
156 # Prints a range of a file as a hex dump
163 $XFS_IO_PROG $xfs_io_args -f -c "pread -q -v $offset $len" "$file" | cut -d ' ' -f '3-18'
166 # Compare ranges of two files
174 cmp -s <(_read_range "$file1" "$offset1" "$len") \
175 <(_read_range "$file2" "$offset2" "$len")
178 # Prints the md5 checksum of a hexdump of a part of a given file
179 _md5_range_checksum() {
184 md5sum <(_read_range "$file" "$offset" "$len") | cut -d ' ' -f 1
187 # Reflink some file1 into file2 via cp
192 cp --reflink=always -p -f "$file1" "$file2"
195 # Reflink some file1 into file2
200 $XFS_IO_PROG -f -c "reflink $file1" "$file2"
203 # Reflink some part of file1 into another part of file2
212 $XFS_IO_PROG $xfs_io_args -f -c "reflink $file1 $offset1 $offset2 $len" "$file2"
215 # Dedupe some part of file1 into another part of file2
224 $XFS_IO_PROG $xfs_io_args -f -c "dedupe $file1 $offset1 $offset2 $len" "$file2"
227 # Unify xfs_io dedupe ioctl error message prefix
228 _filter_dedupe_error()
230 sed -e 's/^dedupe:/XFS_IOC_FILE_EXTENT_SAME:/g'
233 # Create a file of interleaved unwritten and reflinked blocks
234 _weave_reflink_unwritten() {
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
249 # Create a file of interleaved holes and reflinked blocks
250 _weave_reflink_holes() {
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
265 # For a file created with _weave_reflink_holes, fill the holes with delalloc
267 _weave_reflink_holes_delalloc() {
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
278 # Create a file of interleaved regular blocks and reflinked blocks
279 _weave_reflink_regular() {
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
294 # Create a file of interleaved holes, unwritten blocks, regular blocks, and
296 _weave_reflink_rainbow() {
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
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
316 seq 2 5 $((nr - 1)) | while read i; do
317 _pwrite_byte 0x00 $((blksz * i)) $blksz $dfile.chk
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
324 # 4 blocks will be delalloc later
327 # For a file created with _weave_reflink_rainbow, fill the holes with delalloc
329 _weave_reflink_rainbow_delalloc() {
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
341 # Make the source file have interleaved regular blocks and reflinked blocks
342 _sweave_reflink_regular() {
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
356 # Make the source file have interleaved unwritten blocks and reflinked blocks
357 _sweave_reflink_unwritten() {
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
370 seq 1 2 $((nr - 1)) | while read i; do
371 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
375 # Make the source file have interleaved holes and reflinked blocks
376 _sweave_reflink_holes() {
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
389 seq 1 2 $((nr - 1)) | while read i; do
390 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
394 # For a file created with _sweave_reflink_holes, fill the holes with delalloc
396 _sweave_reflink_holes_delalloc() {
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