#! /bin/bash # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2022 BingJing Chang. # # FS QA Test No. btrfs/278 # # Regression test for btrfs incremental send issue when processing inodes # with no links # # This issue is fixed by the following linux kernel btrfs patch: # # commit 9ed0a72e5b355d ("btrfs: send: fix failures when processing # inodes with no links") # . ./common/preamble _begin_fstest auto quick send # real QA test starts here _supported_fs btrfs _fixed_by_kernel_commit 9ed0a72e5b355d \ "btrfs: send: fix failures when processing inodes with no links" _require_test _require_scratch _require_btrfs_command "property" _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 _run_btrfs_util_prog subvolume create $SCRATCH_MNT/vol # Creating the first snapshot looks like: # # . (ino 256) # |--- deleted.file (ino 257) # |--- deleted.dir/ (ino 258) # |--- changed_subcase1.file (ino 259) # |--- changed_subcase2.file (ino 260) # |--- changed_subcase1.dir/ (ino 261) # | |---- foo (ino 262) # |--- changed_subcase2.dir/ (ino 263) # | |---- foo (ino 264) # touch $SCRATCH_MNT/vol/deleted.file mkdir $SCRATCH_MNT/vol/deleted.dir touch $SCRATCH_MNT/vol/changed_subcase1.file touch $SCRATCH_MNT/vol/changed_subcase2.file mkdir $SCRATCH_MNT/vol/changed_subcase1.dir touch $SCRATCH_MNT/vol/changed_subcase1.dir/foo mkdir $SCRATCH_MNT/vol/changed_subcase2.dir touch $SCRATCH_MNT/vol/changed_subcase2.dir/foo _run_btrfs_util_prog subvolume snapshot -r $SCRATCH_MNT/vol $SCRATCH_MNT/snap1 # Delete the deleted.*, create a new file and a new directory, and then # take the second snapshot looks like: # # . (ino 256) # |--- changed_subcase1.file (ino 259) # |--- changed_subcase2.file (ino 260) # |--- changed_subcase1.dir/ (ino 261) # | |---- foo (ino 262) # |--- changed_subcase2.dir/ (ino 263) # | |---- foo (ino 264) # |--- new.file (ino 265) # |--- new.dir/ (ino 266) # unlink $SCRATCH_MNT/vol/deleted.file rmdir $SCRATCH_MNT/vol/deleted.dir touch $SCRATCH_MNT/vol/new.file mkdir $SCRATCH_MNT/vol/new.dir _run_btrfs_util_prog subvolume snapshot -r $SCRATCH_MNT/vol $SCRATCH_MNT/snap2 # Set the snapshot "snap1" to read-write mode and turn several inodes to # orphans, so that the snapshot will look like this: # # . (ino 256) # |--- (orphan) deleted.file (ino 257) # |--- (orphan) deleted.dir/ (ino 258) # |--- (orphan) changed_subcase1.file (ino 259) # |--- changed_subcase2.file (ino 260) # |--- (orphan) changed_subcase1.dir/ (ino 261) # |--- changed_subcase2.dir/ (ino 263) # | |---- foo (ino 264) # # Note: To make an easy illustration, I just put a tag "(orphan)" in front of # their original names to indicate that they're deleted, but their inodes can # not be removed because of open file descriptors on them. Mention that orphan # inodes don't have names(paths). # $BTRFS_UTIL_PROG property set $SCRATCH_MNT/snap1 ro false exec 71<$SCRATCH_MNT/snap1/deleted.file exec 72<$SCRATCH_MNT/snap1/deleted.dir exec 73<$SCRATCH_MNT/snap1/changed_subcase1.file exec 74<$SCRATCH_MNT/snap1/changed_subcase1.dir unlink $SCRATCH_MNT/snap1/deleted.file rmdir $SCRATCH_MNT/snap1/deleted.dir unlink $SCRATCH_MNT/snap1/changed_subcase1.file unlink $SCRATCH_MNT/snap1/changed_subcase1.dir/foo rmdir $SCRATCH_MNT/snap1/changed_subcase1.dir # Turn the snapshot "snap1" back to read-only mode. $BTRFS_UTIL_PROG property set $SCRATCH_MNT/snap1 ro true # Set the snapshot "snap2" to read-write mode and turn several inodes to # orphans, so that the snapshot will look like this: # # . (ino 256) # |--- (orphan) changed_subcase1.file (ino 259) # |--- (orphan) changed_subcase2.file (ino 260) # |--- (orphan) changed_subcase1.dir/ (ino 261) # |--- (orphan) changed_subcase2.dir/ (ino 263) # |--- (orphan) new.file (ino 265) # |--- (orphan) new.dir/ (ino 266) # # Note: Same notice as above. Mention that orphan inodes don't have # names(paths). # $BTRFS_UTIL_PROG property set $SCRATCH_MNT/snap2 ro false exec 81<$SCRATCH_MNT/snap2/changed_subcase1.file exec 82<$SCRATCH_MNT/snap2/changed_subcase1.dir exec 83<$SCRATCH_MNT/snap2/changed_subcase2.file exec 84<$SCRATCH_MNT/snap2/changed_subcase2.dir exec 85<$SCRATCH_MNT/snap2/new.file exec 86<$SCRATCH_MNT/snap2/new.dir unlink $SCRATCH_MNT/snap2/changed_subcase1.file unlink $SCRATCH_MNT/snap2/changed_subcase1.dir/foo rmdir $SCRATCH_MNT/snap2/changed_subcase1.dir unlink $SCRATCH_MNT/snap2/changed_subcase2.file unlink $SCRATCH_MNT/snap2/changed_subcase2.dir/foo rmdir $SCRATCH_MNT/snap2/changed_subcase2.dir unlink $SCRATCH_MNT/snap2/new.file rmdir $SCRATCH_MNT/snap2/new.dir # Turn the snapshot "snap2" back to read-only mode. $BTRFS_UTIL_PROG property set $SCRATCH_MNT/snap2 ro true # Test that a full send operation can handle orphans with no paths _run_btrfs_util_prog send -f $send_files_dir/1.snap $SCRATCH_MNT/snap1 # Test that an incremental send operation can handle orphans. # # Here're descriptions for the details: # # Case 1: new.file and new.dir (BTRFS_COMPARE_TREE_NEW) # | send snapshot | action # -------------------------------- # nlink | 0 | ignore # # They are new inodes in the send snapshot ("snap2"), but they don't have # paths because they have no links. Test that the send operation can ignore # them in order not to generate the creation commands for them. Or it will # fail, with -ENOENT, when trying to generate paths for them. # # # Case 2: deleted.file and deleted.dir (BTRFS_COMPARE_TREE_DELETED) # | parent snapshot | action # ---------------------------------- # nlink | 0 | as usual # # They're deleted in the parent snapshot ("snap1") but become orphans which # have no paths. Test that no deletion commands will be generated as usual. # This case didn't fail before. # # # Case 3: changed_*.file and changed_*.dir (BTRFS_COMPARE_TREE_CHANGED) # | | parent snapshot | send snapshot | action # ----------------------------------------------------------------------- # subcase 1 | nlink | 0 | 0 | ignore # subcase 2 | nlink | >0 | 0 | new_gen(deletion) # # In subcase 1, test that the send operation can ignore them without trying # to generate any commands. # # In subcase 2, test that the send operation can generate an unlink command # for that file and test that it can generate a rename command for the # non-empty directory first and a rmdir command to remove it finally. Or # the receive operation will fail with a wrong unlink on a non-empty # directory. # _run_btrfs_util_prog send -p $SCRATCH_MNT/snap1 -f $send_files_dir/2.snap \ $SCRATCH_MNT/snap2 $FSSUM_PROG -A -f -w $send_files_dir/1.fssum $SCRATCH_MNT/snap1 $FSSUM_PROG -A -f -w $send_files_dir/2.fssum \ -x $SCRATCH_MNT/snap2/snap1 $SCRATCH_MNT/snap2 # Recreate the filesystem by receiving both send streams and verify we get # the same content that the original filesystem had. exec 71>&- exec 72>&- exec 73>&- exec 74>&- exec 81>&- exec 82>&- exec 83>&- exec 84>&- exec 85>&- exec 86>&- _scratch_unmount _scratch_mkfs >>$seqres.full 2>&1 _scratch_mount # Add the first snapshot to the new filesystem by applying the first send # stream. _run_btrfs_util_prog receive -f $send_files_dir/1.snap $SCRATCH_MNT # Test the incremental send stream _run_btrfs_util_prog receive -f $send_files_dir/2.snap $SCRATCH_MNT $FSSUM_PROG -r $send_files_dir/1.fssum $SCRATCH_MNT/snap1 $FSSUM_PROG -r $send_files_dir/2.fssum $SCRATCH_MNT/snap2 status=0 exit