btrfs: incremental send after replacing a file
authorFilipe Manana <>
Wed, 14 Oct 2015 03:07:42 +0000 (14:07 +1100)
committerDave Chinner <>
Wed, 14 Oct 2015 03:07:42 +0000 (14:07 +1100)
Test that an incremental send works after a file from the parent snapshot
gets replaced in the send snapshot by another one at the same exact
location, with the same name and with the same inode number.

This test used to fail after the linux kernel commit 8b191a684968
("Btrfs: incremental send, check if orphanized dir inode needs delayed
rename") and it's fixed by patch titled:

  "Btrfs: send, fix corner case for reference overwrite detection"

Signed-off-by: Martin Raiber <>
Signed-off-by: Filipe Manana <>
Reviewed-by: Eryu Guan <>
Signed-off-by: Dave Chinner <>
tests/btrfs/105 [new file with mode: 0755]
tests/btrfs/105.out [new file with mode: 0644]

diff --git a/tests/btrfs/105 b/tests/btrfs/105
new file mode 100755 (executable)
index 0000000..be051fe
--- /dev/null
@@ -0,0 +1,112 @@
+#! /bin/bash
+# FS QA Test No. btrfs/105
+# Test that an incremental send works after a file from the parent snapshot
+# gets replaced in the send snapshot by another one at the same exact location,
+# with the same name and with the same inode number.
+# Copyright (C) 2015 SUSE Linux Products GmbH. All Rights Reserved.
+# Author: Filipe Manana <>
+# Copyright (C) 2015 Martin Raiber <>
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+seq=`basename $0`
+echo "QA output created by $seq"
+status=1       # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+       cd /
+       rm -fr $send_files_dir
+       rm -f $tmp.*
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+# real QA test starts here
+_supported_fs btrfs
+_supported_os Linux
+rm -f $seqres.full
+rm -fr $send_files_dir
+mkdir $send_files_dir
+_scratch_mkfs >>$seqres.full 2>&1
+# Create our test file with a single extent of 64K.
+mkdir -p $SCRATCH_MNT/foo
+$XFS_IO_PROG -f -c "pwrite -S 0xaa 0 64K" $SCRATCH_MNT/foo/bar | _filter_xfs_io
+_run_btrfs_util_prog subvolume snapshot -r $SCRATCH_MNT $SCRATCH_MNT/mysnap1
+_run_btrfs_util_prog subvolume snapshot $SCRATCH_MNT $SCRATCH_MNT/mysnap2
+echo "File digest before being replaced:"
+md5sum $SCRATCH_MNT/mysnap1/foo/bar | _filter_scratch
+# Remove the file and then create a new one in the same location with the same
+# name but with different content. This new file ends up getting the same inode
+# number as the previous one, because that inode number was the highest inode
+# number used by the snapshot's root and therefore when attempting to find the
+# a new inode number for the new file, we end up reusing the same inode number.
+# This happens because currently btrfs uses the highest inode number summed by 1
+# for the first inode created once a snapshot's root is loaded (done at
+# fs/btrfs/inode-map.c:btrfs_find_free_objectid in the linux kernel tree).
+# Having these two different files in the snapshots with the same inode number
+# (but different generation numbers) caused the btrfs send code to emit an
+# incorrect path for the file when issuing an unlink operation because it failed
+# to realize they were different files.
+rm -f $SCRATCH_MNT/mysnap2/foo/bar
+$XFS_IO_PROG -f -c "pwrite -S 0xbb 0 96K" \
+       $SCRATCH_MNT/mysnap2/foo/bar | _filter_xfs_io
+_run_btrfs_util_prog subvolume snapshot -r $SCRATCH_MNT/mysnap2 \
+       $SCRATCH_MNT/mysnap2_ro
+_run_btrfs_util_prog send $SCRATCH_MNT/mysnap1 -f $send_files_dir/1.snap
+_run_btrfs_util_prog send -p $SCRATCH_MNT/mysnap1 $SCRATCH_MNT/mysnap2_ro \
+       -f $send_files_dir/2.snap
+echo "File digest in the original filesystem after being replaced:"
+md5sum $SCRATCH_MNT/mysnap2_ro/foo/bar | _filter_scratch
+# Now recreate the filesystem by receiving both send streams and verify we get
+# the same file contents that the original filesystem had.
+_scratch_mkfs >>$seqres.full 2>&1
+_run_btrfs_util_prog receive $SCRATCH_MNT -f $send_files_dir/1.snap
+_run_btrfs_util_prog receive $SCRATCH_MNT -f $send_files_dir/2.snap
+echo "File digest in the new filesystem:"
+# Must match the digest from the new file.
+md5sum $SCRATCH_MNT/mysnap2_ro/foo/bar | _filter_scratch
\ No newline at end of file
diff --git a/tests/btrfs/105.out b/tests/btrfs/105.out
new file mode 100644 (file)
index 0000000..09e11ed
--- /dev/null
@@ -0,0 +1,11 @@
+QA output created by 105
+wrote 65536/65536 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File digest before being replaced:
+9802287a6faa01a1fd0e01732b732fca  SCRATCH_MNT/mysnap1/foo/bar
+wrote 98304/98304 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File digest in the original filesystem after being replaced:
+de277dfac706c359613033120349cf88  SCRATCH_MNT/mysnap2_ro/foo/bar
+File digest in the new filesystem:
+de277dfac706c359613033120349cf88  SCRATCH_MNT/mysnap2_ro/foo/bar
index 6218adfa3a5cc80785e03cbbc3d208481f285ce2..02d94dc8e76a49a35d5ffd96949d42e093201855 100644 (file)
 102 auto quick metadata enospc
 103 auto quick clone compress
 104 auto qgroup
+105 auto quick send