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 scratch fs to report explicit SHARED flag
83 # |<- On disk Extent-->|
87 # Fs supports explicit SHARED extent reporting should report fiemap like:
94 # Fs doesn't support explicit reporting will report fiemap like:
99 _require_scratch_explicit_shared_extents()
102 _require_xfs_io_command "fiemap"
103 _require_scratch_reflink
104 _require_xfs_io_command "reflink"
107 _scratch_mkfs > /dev/null
110 _pwrite_byte 0x61 0 128k $SCRATCH_MNT/file1 >/dev/null
111 _reflink_range $SCRATCH_MNT/file1 0 $SCRATCH_MNT/file2 0 64k >/dev/null
115 nr_extents=$(_count_extents $SCRATCH_MNT/file1)
116 if [ $nr_extents -eq 1 ]; then
117 _notrun "Explicit SHARED flag reporting not support by filesystem type: $FSTYP"
122 # this test requires the test fs support dedupe...
123 _require_test_dedupe()
126 _require_xfs_io_command "dedupe"
128 rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
129 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$TEST_DIR/file1" > /dev/null
130 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$TEST_DIR/file2" > /dev/null
131 testio="$($XFS_IO_PROG -f -c "dedupe $TEST_DIR/file1 0 0 65536" "$TEST_DIR/file2" 2>&1)"
132 echo $testio | grep -q "Operation not supported" && \
133 _notrun "Dedupe not supported by test filesystem type: $FSTYP"
134 echo $testio | grep -q "Inappropriate ioctl for device" && \
135 _notrun "Dedupe not supported by test filesystem type: $FSTYP"
136 echo $testio | grep -q "Invalid argument" && \
137 _notrun "Dedupe not supported by test filesystem type: $FSTYP"
138 rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
141 # this test requires the scratch fs support dedupe...
142 _require_scratch_dedupe()
145 _require_xfs_io_command "dedupe"
147 _scratch_mkfs > /dev/null
149 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$SCRATCH_MNT/file1" > /dev/null
150 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$SCRATCH_MNT/file2" > /dev/null
151 testio="$($XFS_IO_PROG -f -c "dedupe $SCRATCH_MNT/file1 0 0 65536" "$SCRATCH_MNT/file2" 2>&1)"
152 echo $testio | grep -q "Operation not supported" && \
153 _notrun "Dedupe not supported by scratch filesystem type: $FSTYP"
154 echo $testio | grep -q "Inappropriate ioctl for device" && \
155 _notrun "Dedupe not supported by scratch filesystem type: $FSTYP"
156 echo $testio | grep -q "Invalid argument" && \
157 _notrun "Dedupe not supported by scratch filesystem type: $FSTYP"
161 # Prints a range of a file as a hex dump
168 $XFS_IO_PROG $xfs_io_args -f -c "pread -q -v $offset $len" "$file" | cut -d ' ' -f '3-18'
171 # Compare ranges of two files
179 cmp -s <(_read_range "$file1" "$offset1" "$len") \
180 <(_read_range "$file2" "$offset2" "$len")
183 # Prints the md5 checksum of a hexdump of a part of a given file
184 _md5_range_checksum() {
189 md5sum <(_read_range "$file" "$offset" "$len") | cut -d ' ' -f 1
192 # Reflink some file1 into file2 via cp
197 cp --reflink=always -p -f "$file1" "$file2"
200 # Reflink some file1 into file2
205 $XFS_IO_PROG -f -c "reflink $file1" "$file2"
208 # Reflink some part of file1 into another part of file2
217 $XFS_IO_PROG $xfs_io_args -f -c "reflink $file1 $offset1 $offset2 $len" "$file2"
220 # Dedupe some part of file1 into another part of file2
229 $XFS_IO_PROG $xfs_io_args -f -c "dedupe $file1 $offset1 $offset2 $len" "$file2"
232 # Unify xfs_io dedupe ioctl error message prefix
233 _filter_dedupe_error()
235 sed -e 's/^dedupe:/XFS_IOC_FILE_EXTENT_SAME:/g'
238 # Create a file of interleaved unwritten and reflinked blocks
239 _weave_reflink_unwritten() {
245 _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
246 $XFS_IO_PROG -f -c "falloc 0 $((blksz * nr))" $dfile
247 _pwrite_byte 0x00 0 $((blksz * nr)) $dfile.chk
248 seq 0 2 $((nr - 1)) | while read i; do
249 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
250 _pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
254 # Create a file of interleaved holes and reflinked blocks
255 _weave_reflink_holes() {
261 _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
262 $XFS_IO_PROG -f -c "truncate $((blksz * nr))" $dfile
263 _pwrite_byte 0x00 0 $((blksz * nr)) $dfile.chk
264 seq 0 2 $((nr - 1)) | while read i; do
265 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
266 _pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
270 # For a file created with _weave_reflink_holes, fill the holes with delalloc
272 _weave_reflink_holes_delalloc() {
277 seq 1 2 $((nr - 1)) | while read i; do
278 _pwrite_byte 0x62 $((blksz * i)) $blksz $dfile
279 _pwrite_byte 0x62 $((blksz * i)) $blksz $dfile.chk
283 # Create a file of interleaved regular blocks and reflinked blocks
284 _weave_reflink_regular() {
290 _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
291 _pwrite_byte 0x62 0 $((blksz * nr)) $dfile
292 _pwrite_byte 0x62 0 $((blksz * nr)) $dfile.chk
293 seq 0 2 $((nr - 1)) | while read i; do
294 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
295 _pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
299 # Create a file of interleaved holes, unwritten blocks, regular blocks, and
301 _weave_reflink_rainbow() {
307 _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
308 $XFS_IO_PROG -f -c "truncate $((blksz * nr))" $dfile
309 _pwrite_byte 0x00 0 $((blksz * nr)) $dfile.chk
310 # 0 blocks are reflinked
311 seq 0 5 $((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
315 # 1 blocks are unwritten
316 seq 1 5 $((nr - 1)) | while read i; do
317 $XFS_IO_PROG -f -c "falloc $((blksz * i)) $blksz" $dfile
318 _pwrite_byte 0x00 $((blksz * i)) $blksz $dfile.chk
321 seq 2 5 $((nr - 1)) | while read i; do
322 _pwrite_byte 0x00 $((blksz * i)) $blksz $dfile.chk
324 # 3 blocks are regular
325 seq 3 5 $((nr - 1)) | while read i; do
326 _pwrite_byte 0x71 $((blksz * i)) $blksz $dfile
327 _pwrite_byte 0x71 $((blksz * i)) $blksz $dfile.chk
329 # 4 blocks will be delalloc later
332 # For a file created with _weave_reflink_rainbow, fill the holes with delalloc
334 _weave_reflink_rainbow_delalloc() {
339 # 4 blocks are delalloc (do later)
340 seq 4 5 $((nr - 1)) | while read i; do
341 _pwrite_byte 0x62 $((blksz * i)) $blksz $dfile
342 _pwrite_byte 0x62 $((blksz * i)) $blksz $dfile.chk
346 # Make the source file have interleaved regular blocks and reflinked blocks
347 _sweave_reflink_regular() {
353 _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
354 _pwrite_byte 0x62 0 $((blksz * nr)) $dfile
355 _pwrite_byte 0x61 0 $((blksz * nr)) $sfile.chk
356 seq 1 2 $((nr - 1)) | while read i; do
357 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
361 # Make the source file have interleaved unwritten blocks and reflinked blocks
362 _sweave_reflink_unwritten() {
368 $XFS_IO_PROG -f -c "falloc 0 $((blksz * nr))" $sfile
369 _pwrite_byte 0x00 0 $((blksz * nr)) $sfile.chk
370 _pwrite_byte 0x62 0 $((blksz * nr)) $dfile
371 seq 1 2 $((nr - 1)) | while read i; do
372 _pwrite_byte 0x61 $((blksz * i)) $blksz $sfile
373 _pwrite_byte 0x61 $((blksz * i)) $blksz $sfile.chk
375 seq 1 2 $((nr - 1)) | while read i; do
376 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
380 # Make the source file have interleaved holes and reflinked blocks
381 _sweave_reflink_holes() {
387 $XFS_IO_PROG -f -c "truncate $((blksz * nr))" $sfile
388 _pwrite_byte 0x00 0 $((blksz * nr)) $sfile.chk
389 _pwrite_byte 0x62 0 $((blksz * nr)) $dfile
390 seq 1 2 $((nr - 1)) | while read i; do
391 _pwrite_byte 0x61 $((blksz * i)) $blksz $sfile
392 _pwrite_byte 0x61 $((blksz * i)) $blksz $sfile.chk
394 seq 1 2 $((nr - 1)) | while read i; do
395 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
399 # For a file created with _sweave_reflink_holes, fill the holes with delalloc
401 _sweave_reflink_holes_delalloc() {
406 seq 0 2 $((nr - 1)) | while read i; do
407 _pwrite_byte 0x64 $((blksz * i)) $blksz $sfile
408 _pwrite_byte 0x64 $((blksz * i)) $blksz $sfile.chk