|  | #! /bin/bash | 
|  | # SPDX-License-Identifier: GPL-2.0 | 
|  | # Copyright (C) 2017 Synology Inc. All Rights Reserved. | 
|  | # | 
|  | # FS QA Test No. btrfs/135 | 
|  | # | 
|  | # Test that an incremental send operation works when in both snapshots there are | 
|  | # two directory inodes that have the same number but different generations and | 
|  | # have an entry with the same name that corresponds to different inodes in each | 
|  | # snapshot. | 
|  | # | 
|  | . ./common/preamble | 
|  | _begin_fstest auto quick send | 
|  |  | 
|  | # Override the default cleanup function. | 
|  | _cleanup() | 
|  | { | 
|  | cd / | 
|  | rm -fr $send_files_dir | 
|  | rm -f $tmp.* | 
|  | } | 
|  |  | 
|  | # Import common functions. | 
|  | . ./common/filter | 
|  |  | 
|  | # real QA test starts here | 
|  | _supported_fs btrfs | 
|  | _require_test | 
|  | _require_scratch | 
|  | _require_fssum | 
|  |  | 
|  | send_files_dir=$TEST_DIR/btrfs-test-$seq | 
|  |  | 
|  | rm -fr $send_files_dir | 
|  | mkdir $send_files_dir | 
|  |  | 
|  | _scratch_mkfs >>$seqres.full 2>&1 | 
|  | _scratch_mount | 
|  |  | 
|  | touch $SCRATCH_MNT/f | 
|  | mkdir $SCRATCH_MNT/d1 | 
|  | mkdir $SCRATCH_MNT/d259_old | 
|  | mv $SCRATCH_MNT/d1 $SCRATCH_MNT/d259_old/d1 | 
|  |  | 
|  | # Filesystem looks like: | 
|  | # | 
|  | # .                                                             (ino 256) | 
|  | # |--- f                                                        (ino 257) | 
|  | # | | 
|  | # |--- d259_old/                                                (ino 259) | 
|  | #         |--- d1/                                              (ino 258) | 
|  | # | 
|  | $BTRFS_UTIL_PROG subvolume snapshot -r $SCRATCH_MNT \ | 
|  | $SCRATCH_MNT/mysnap1 > /dev/null | 
|  |  | 
|  | $BTRFS_UTIL_PROG send -f $send_files_dir/1.snap \ | 
|  | $SCRATCH_MNT/mysnap1 2>&1 1>/dev/null | _filter_scratch | 
|  |  | 
|  | _scratch_unmount | 
|  | _scratch_mkfs >>$seqres.full 2>&1 | 
|  | _scratch_mount | 
|  | mkdir $SCRATCH_MNT/d1 | 
|  | mkdir $SCRATCH_MNT/dir258 | 
|  | mkdir $SCRATCH_MNT/dir259 | 
|  | mv $SCRATCH_MNT/d1 $SCRATCH_MNT/dir259/d1 | 
|  |  | 
|  | # Filesystem now looks like: | 
|  | # | 
|  | # .                                                             (ino 256) | 
|  | # |--- dir258/                                                  (ino 258) | 
|  | # | | 
|  | # |--- dir259/                                                  (ino 259) | 
|  | #        |--- d1/                                               (ino 257) | 
|  | # | 
|  | # Notice that at this point all inodes have a generation with value 7, which is | 
|  | # the generation value for a brand new filesystem. | 
|  |  | 
|  | # Now create the second snapshot. This makes the filesystem's current generation | 
|  | # value to increase to the value 8, due to a transaction commit performed by the | 
|  | # snapshot creation ioctl. | 
|  | $BTRFS_UTIL_PROG subvolume snapshot -r $SCRATCH_MNT \ | 
|  | $SCRATCH_MNT/mysnap2 > /dev/null | 
|  |  | 
|  | # Now receive the first snapshot created in the first filesystem. | 
|  | # Before creating any inodes, the receive command creates the first snapshot, | 
|  | # which causes a transaction commit and therefore bumps the filesystem's current | 
|  | # generation to the value 9. All the inodes created end up getting a generation | 
|  | # value of 9 and the snapshot's root inode (256) gets a generation value of 8. | 
|  | $BTRFS_UTIL_PROG receive -f $send_files_dir/1.snap $SCRATCH_MNT > /dev/null | 
|  | rm $send_files_dir/1.snap | 
|  |  | 
|  | $FSSUM_PROG -A -f -w $send_files_dir/1.fssum $SCRATCH_MNT/mysnap1 | 
|  | $FSSUM_PROG -A -f -w $send_files_dir/2.fssum $SCRATCH_MNT/mysnap2 | 
|  |  | 
|  | $BTRFS_UTIL_PROG send -f $send_files_dir/1.snap \ | 
|  | $SCRATCH_MNT/mysnap1 2>&1 1>/dev/null | _filter_scratch | 
|  | $BTRFS_UTIL_PROG send -p $SCRATCH_MNT/mysnap1 -f $send_files_dir/2.snap \ | 
|  | $SCRATCH_MNT/mysnap2 2>&1 1>/dev/null | _filter_scratch | 
|  |  | 
|  | # Now recreate the filesystem by receiving both send streams and verify we get | 
|  | # the same content that the original filesystem had. | 
|  | _scratch_unmount | 
|  | _scratch_mkfs >>$seqres.full 2>&1 | 
|  | _scratch_mount | 
|  |  | 
|  | $BTRFS_UTIL_PROG receive -f $send_files_dir/1.snap $SCRATCH_MNT > /dev/null | 
|  | $FSSUM_PROG -r $send_files_dir/1.fssum $SCRATCH_MNT/mysnap1 | 
|  | # The receive of the incremental send stream used to fail because it contained | 
|  | # a rmdir operation with an invalid path. The output of the receive command, | 
|  | # with verbose mode (argument -vv), was the following: | 
|  | # | 
|  | # utimes | 
|  | # unlink f | 
|  | # mkdir o257-7-0 | 
|  | # mkdir o259-7-0 | 
|  | # rename o257-7-0 -> o259-7-0/d1 | 
|  | # chown o259-7-0/d1 - uid=0, gid=0 | 
|  | # chmod o259-7-0/d1 - mode=0755 | 
|  | # utimes o259-7-0/d1 | 
|  | # rmdir o258-9-0 | 
|  | # ERROR: rmdir o258-9-0 failed: No such file or directory | 
|  | # | 
|  | # When the kernel was computing the send stream and processing inode 258, it | 
|  | # noticed that in both snapshots this inode is a direct child of inode 259, and | 
|  | # that in both snapshots inode 259 as an entry with the name "d1". Because of | 
|  | # that it decided (incorrectly) to issue an rmdir operation using the orphanized | 
|  | # name of the inode 258 from the parent snapshot (which has a generation of 9). | 
|  | # However that decision to send an rmdir operation due to the dentry collision | 
|  | # was incorrect because the inodes with number 259 in both snapshots are not the | 
|  | # same, they have different generations. | 
|  | # | 
|  | $BTRFS_UTIL_PROG receive -f $send_files_dir/2.snap $SCRATCH_MNT > /dev/null | 
|  | $FSSUM_PROG -r $send_files_dir/2.fssum $SCRATCH_MNT/mysnap2 | 
|  |  | 
|  | status=0 | 
|  | exit |