2 # Routines for reflinking, deduping, and comparing parts of files.
3 #-----------------------------------------------------------------------
4 # Copyright (c) 2015 Oracle. All Rights Reserved.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 # Contact information: Oracle Corporation, 500 Oracle Parkway,
21 # Redwood Shores, CA 94065, USA, or: http://www.oracle.com/
22 #-----------------------------------------------------------------------
24 # Check that cp has a reflink argument
27 cp --help | grep -q reflink || \
28 _notrun "This test requires a cp with --reflink support."
31 # Can we reflink between arbitrary file sets?
32 # i.e. if we reflink a->b and c->d, can we later share
33 # blocks between b & c?
34 _require_arbitrary_fileset_reflink()
36 test "$FSTYP" = "ocfs2" && \
37 _notrun "reflink between arbitrary file groups not supported in $FSTYP"
40 # Given 2 files, verify that they have the same mapping but different
41 # inodes - i.e. an undisturbed reflink
42 # Silent if so, make noise if not
45 # not a hard link or symlink?
46 cmp -s <(stat -c '%i' $1) <(stat -c '%i' $2) \
47 && echo "$1 and $2 are not reflinks: same inode number"
50 diff -u <($XFS_IO_PROG -c "fiemap" $1 | grep -v $1) \
51 <($XFS_IO_PROG -c "fiemap" $2 | grep -v $2) \
52 || echo "$1 and $2 are not reflinks: different extents"
55 # New reflink/dedupe helpers
57 # this test requires the test fs support reflink...
58 _require_test_reflink()
61 _require_xfs_io_command "reflink"
63 rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
64 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$TEST_DIR/file1" > /dev/null
65 $XFS_IO_PROG -f -c "reflink $TEST_DIR/file1 0 0 65536" "$TEST_DIR/file2" > /dev/null
66 if [ ! -s "$TEST_DIR/file2" ]; then
67 rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
68 _notrun "Reflink not supported by test filesystem type: $FSTYP"
70 rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
73 # this test requires the scratch fs support reflink...
74 _require_scratch_reflink()
77 _require_xfs_io_command "reflink"
79 _scratch_mkfs > /dev/null
81 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$SCRATCH_MNT/file1" > /dev/null
82 $XFS_IO_PROG -f -c "reflink $SCRATCH_MNT/file1 0 0 65536" "$SCRATCH_MNT/file2" > /dev/null
83 if [ ! -s "$SCRATCH_MNT/file2" ]; then
85 _notrun "Reflink not supported by scratch filesystem type: $FSTYP"
90 # this test requires scratch fs to report explicit SHARED flag
95 # |<- On disk Extent-->|
99 # Fs supports explicit SHARED extent reporting should report fiemap like:
101 # Extent 0-4K: SHARED
104 # Extent 0-4K: SHARED
106 # Fs doesn't support explicit reporting will report fiemap like:
108 # Extent 0-8K: SHARED
110 # Extent 0-4K: SHARED
111 _require_scratch_explicit_shared_extents()
115 _require_scratch_reflink
116 _require_xfs_io_command "reflink"
119 _scratch_mkfs > /dev/null
122 _pwrite_byte 0x61 0 128k $SCRATCH_MNT/file1 >/dev/null
123 _reflink_range $SCRATCH_MNT/file1 0 $SCRATCH_MNT/file2 0 64k >/dev/null
127 nr_extents=$(_count_extents $SCRATCH_MNT/file1)
128 if [ $nr_extents -eq 1 ]; then
129 _notrun "Explicit SHARED flag reporting not support by filesystem type: $FSTYP"
134 # this test requires the test fs support dedupe...
135 _require_test_dedupe()
138 _require_xfs_io_command "dedupe"
140 rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
141 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$TEST_DIR/file1" > /dev/null
142 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$TEST_DIR/file2" > /dev/null
143 testio="$($XFS_IO_PROG -f -c "dedupe $TEST_DIR/file1 0 0 65536" "$TEST_DIR/file2" 2>&1)"
144 echo $testio | grep -q "Operation not supported" && \
145 _notrun "Dedupe not supported by test filesystem type: $FSTYP"
146 echo $testio | grep -q "Inappropriate ioctl for device" && \
147 _notrun "Dedupe not supported by test filesystem type: $FSTYP"
148 echo $testio | grep -q "Invalid argument" && \
149 _notrun "Dedupe not supported by test filesystem type: $FSTYP"
150 rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
153 # this test requires the scratch fs support dedupe...
154 _require_scratch_dedupe()
157 _require_xfs_io_command "dedupe"
159 _scratch_mkfs > /dev/null
161 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$SCRATCH_MNT/file1" > /dev/null
162 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 65536" "$SCRATCH_MNT/file2" > /dev/null
163 testio="$($XFS_IO_PROG -f -c "dedupe $SCRATCH_MNT/file1 0 0 65536" "$SCRATCH_MNT/file2" 2>&1)"
164 echo $testio | grep -q "Operation not supported" && \
165 _notrun "Dedupe not supported by test filesystem type: $FSTYP"
166 echo $testio | grep -q "Inappropriate ioctl for device" && \
167 _notrun "Dedupe not supported by test filesystem type: $FSTYP"
168 echo $testio | grep -q "Invalid argument" && \
169 _notrun "Dedupe not supported by test filesystem type: $FSTYP"
173 # Prints a range of a file as a hex dump
180 $XFS_IO_PROG $xfs_io_args -f -c "pread -q -v $offset $len" "$file" | cut -d ' ' -f '3-18'
183 # Compare ranges of two files
191 cmp -s <(_read_range "$file1" "$offset1" "$len") \
192 <(_read_range "$file2" "$offset2" "$len")
195 # Prints the md5 checksum of a hexdump of a part of a given file
196 _md5_range_checksum() {
201 md5sum <(_read_range "$file" "$offset" "$len") | cut -d ' ' -f 1
204 # Reflink some file1 into file2 via cp
209 cp --reflink=always -p -f "$file1" "$file2"
212 # Reflink some file1 into file2
217 $XFS_IO_PROG -f -c "reflink $file1" "$file2"
220 # Reflink some part of file1 into another part of file2
229 $XFS_IO_PROG $xfs_io_args -f -c "reflink $file1 $offset1 $offset2 $len" "$file2"
232 # Dedupe some part of file1 into another part of file2
241 $XFS_IO_PROG $xfs_io_args -f -c "dedupe $file1 $offset1 $offset2 $len" "$file2"
244 # Unify xfs_io dedupe ioctl error message prefix
245 _filter_dedupe_error()
247 sed -e 's/^dedupe:/XFS_IOC_FILE_EXTENT_SAME:/g'
250 # Create a file of interleaved unwritten and reflinked blocks
251 _weave_reflink_unwritten() {
257 _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
258 $XFS_IO_PROG -f -c "falloc 0 $((blksz * nr))" $dfile
259 _pwrite_byte 0x00 0 $((blksz * nr)) $dfile.chk
260 seq 0 2 $((nr - 1)) | while read i; do
261 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
262 _pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
266 # Create a file of interleaved holes and reflinked blocks
267 _weave_reflink_holes() {
273 _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
274 $XFS_IO_PROG -f -c "truncate $((blksz * nr))" $dfile
275 _pwrite_byte 0x00 0 $((blksz * nr)) $dfile.chk
276 seq 0 2 $((nr - 1)) | while read i; do
277 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
278 _pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
282 # For a file created with _weave_reflink_holes, fill the holes with delalloc
284 _weave_reflink_holes_delalloc() {
289 seq 1 2 $((nr - 1)) | while read i; do
290 _pwrite_byte 0x62 $((blksz * i)) $blksz $dfile
291 _pwrite_byte 0x62 $((blksz * i)) $blksz $dfile.chk
295 # Create a file of interleaved regular blocks and reflinked blocks
296 _weave_reflink_regular() {
302 _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
303 _pwrite_byte 0x62 0 $((blksz * nr)) $dfile
304 _pwrite_byte 0x62 0 $((blksz * nr)) $dfile.chk
305 seq 0 2 $((nr - 1)) | while read i; do
306 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
307 _pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
311 # Create a file of interleaved holes, unwritten blocks, regular blocks, and
313 _weave_reflink_rainbow() {
319 _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
320 $XFS_IO_PROG -f -c "truncate $((blksz * nr))" $dfile
321 _pwrite_byte 0x00 0 $((blksz * nr)) $dfile.chk
322 # 0 blocks are reflinked
323 seq 0 5 $((nr - 1)) | while read i; do
324 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
325 _pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
327 # 1 blocks are unwritten
328 seq 1 5 $((nr - 1)) | while read i; do
329 $XFS_IO_PROG -f -c "falloc $((blksz * i)) $blksz" $dfile
330 _pwrite_byte 0x00 $((blksz * i)) $blksz $dfile.chk
333 seq 2 5 $((nr - 1)) | while read i; do
334 _pwrite_byte 0x00 $((blksz * i)) $blksz $dfile.chk
336 # 3 blocks are regular
337 seq 3 5 $((nr - 1)) | while read i; do
338 _pwrite_byte 0x71 $((blksz * i)) $blksz $dfile
339 _pwrite_byte 0x71 $((blksz * i)) $blksz $dfile.chk
341 # 4 blocks will be delalloc later
344 # For a file created with _weave_reflink_rainbow, fill the holes with delalloc
346 _weave_reflink_rainbow_delalloc() {
351 # 4 blocks are delalloc (do later)
352 seq 4 5 $((nr - 1)) | while read i; do
353 _pwrite_byte 0x62 $((blksz * i)) $blksz $dfile
354 _pwrite_byte 0x62 $((blksz * i)) $blksz $dfile.chk
358 # Make the source file have interleaved regular blocks and reflinked blocks
359 _sweave_reflink_regular() {
365 _pwrite_byte 0x61 0 $((blksz * nr)) $sfile
366 _pwrite_byte 0x62 0 $((blksz * nr)) $dfile
367 _pwrite_byte 0x61 0 $((blksz * nr)) $sfile.chk
368 seq 1 2 $((nr - 1)) | while read i; do
369 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
373 # Make the source file have interleaved unwritten blocks and reflinked blocks
374 _sweave_reflink_unwritten() {
380 $XFS_IO_PROG -f -c "falloc 0 $((blksz * nr))" $sfile
381 _pwrite_byte 0x00 0 $((blksz * nr)) $sfile.chk
382 _pwrite_byte 0x62 0 $((blksz * nr)) $dfile
383 seq 1 2 $((nr - 1)) | while read i; do
384 _pwrite_byte 0x61 $((blksz * i)) $blksz $sfile
385 _pwrite_byte 0x61 $((blksz * i)) $blksz $sfile.chk
387 seq 1 2 $((nr - 1)) | while read i; do
388 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
392 # Make the source file have interleaved holes and reflinked blocks
393 _sweave_reflink_holes() {
399 $XFS_IO_PROG -f -c "truncate $((blksz * nr))" $sfile
400 _pwrite_byte 0x00 0 $((blksz * nr)) $sfile.chk
401 _pwrite_byte 0x62 0 $((blksz * nr)) $dfile
402 seq 1 2 $((nr - 1)) | while read i; do
403 _pwrite_byte 0x61 $((blksz * i)) $blksz $sfile
404 _pwrite_byte 0x61 $((blksz * i)) $blksz $sfile.chk
406 seq 1 2 $((nr - 1)) | while read i; do
407 _reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
411 # For a file created with _sweave_reflink_holes, fill the holes with delalloc
413 _sweave_reflink_holes_delalloc() {
418 seq 0 2 $((nr - 1)) | while read i; do
419 _pwrite_byte 0x64 $((blksz * i)) $blksz $sfile
420 _pwrite_byte 0x64 $((blksz * i)) $blksz $sfile.chk