mirror of
https://github.com/kdave/btrfs-progs
synced 2024-12-17 20:05:24 +00:00
btrfs-progs: receive: cannot find clone source subvol when receiving in reverse direction
process_clone() only searches the received_uuid, but could exist in an earlier uuid that isn't the received_uuid. Mirror what process_snapshot does and search both the received_uuid and if that fails look up by normal uuid. Fixes: https://github.com/kdave/btrfs-progs/issues/606 Issue: #606 Pull-request: #643 Pull-request: #862 Signed-off-by: Arsenii Skvortsov <ettavolt@gmail.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
957b614088
commit
28eb473c51
@ -221,6 +221,25 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search for the @subvol_uuid, try received_uuid and subvolume as a fallback
|
||||||
|
* if it's not found.
|
||||||
|
*/
|
||||||
|
static struct subvol_info *search_source_subvol(int mnt_fd, const u8 *subvol_uuid,
|
||||||
|
u64 transid)
|
||||||
|
{
|
||||||
|
struct subvol_info *found;
|
||||||
|
|
||||||
|
found = subvol_uuid_search(mnt_fd, 0, subvol_uuid, transid, NULL,
|
||||||
|
subvol_search_by_received_uuid);
|
||||||
|
if (IS_ERR_OR_NULL(found)) {
|
||||||
|
found = subvol_uuid_search(mnt_fd, 0, subvol_uuid, transid,
|
||||||
|
NULL, subvol_search_by_uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
|
static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
|
||||||
const u8 *parent_uuid, u64 parent_ctransid,
|
const u8 *parent_uuid, u64 parent_ctransid,
|
||||||
void *user)
|
void *user)
|
||||||
@ -283,14 +302,8 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
|
|||||||
memset(&args_v2, 0, sizeof(args_v2));
|
memset(&args_v2, 0, sizeof(args_v2));
|
||||||
strncpy_null(args_v2.name, path, sizeof(args_v2.name));
|
strncpy_null(args_v2.name, path, sizeof(args_v2.name));
|
||||||
|
|
||||||
parent_subvol = subvol_uuid_search(rctx->mnt_fd, 0, parent_uuid,
|
parent_subvol = search_source_subvol(rctx->mnt_fd, parent_uuid,
|
||||||
parent_ctransid, NULL,
|
parent_ctransid);
|
||||||
subvol_search_by_received_uuid);
|
|
||||||
if (IS_ERR_OR_NULL(parent_subvol)) {
|
|
||||||
parent_subvol = subvol_uuid_search(rctx->mnt_fd, 0, parent_uuid,
|
|
||||||
parent_ctransid, NULL,
|
|
||||||
subvol_search_by_uuid);
|
|
||||||
}
|
|
||||||
if (IS_ERR_OR_NULL(parent_subvol)) {
|
if (IS_ERR_OR_NULL(parent_subvol)) {
|
||||||
if (!parent_subvol)
|
if (!parent_subvol)
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
@ -745,9 +758,8 @@ static int process_clone(const char *path, u64 offset, u64 len,
|
|||||||
BTRFS_UUID_SIZE) == 0) {
|
BTRFS_UUID_SIZE) == 0) {
|
||||||
subvol_path = rctx->cur_subvol_path;
|
subvol_path = rctx->cur_subvol_path;
|
||||||
} else {
|
} else {
|
||||||
si = subvol_uuid_search(rctx->mnt_fd, 0, clone_uuid, clone_ctransid,
|
si = search_source_subvol(rctx->mnt_fd, clone_uuid,
|
||||||
NULL,
|
clone_ctransid);
|
||||||
subvol_search_by_received_uuid);
|
|
||||||
if (IS_ERR_OR_NULL(si)) {
|
if (IS_ERR_OR_NULL(si)) {
|
||||||
char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
|
char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
|
||||||
|
|
||||||
|
99
tests/misc-tests/064-reverse-receive/test.sh
Executable file
99
tests/misc-tests/064-reverse-receive/test.sh
Executable file
@ -0,0 +1,99 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Receive in reverse direction must not throw an error if it can find an
|
||||||
|
# earlier "sent" parent. In general, shows a backup+sync setup between two (or
|
||||||
|
# more) PCs with an external drive.
|
||||||
|
|
||||||
|
source "$TEST_TOP/common"
|
||||||
|
|
||||||
|
check_prereq mkfs.btrfs
|
||||||
|
check_prereq btrfs
|
||||||
|
check_global_prereq dd
|
||||||
|
|
||||||
|
declare -a roots
|
||||||
|
i_pc1=1
|
||||||
|
# An external drive used to backup and carry profile.
|
||||||
|
i_ext=2
|
||||||
|
i_pc2=3
|
||||||
|
roots[$i_pc1]="$TEST_MNT/pc1"
|
||||||
|
roots[$i_ext]="$TEST_MNT/external"
|
||||||
|
roots[$i_pc2]="$TEST_MNT/pc2"
|
||||||
|
|
||||||
|
setup_root_helper
|
||||||
|
mkdir -p "${roots[@]}"
|
||||||
|
setup_loopdevs 3
|
||||||
|
prepare_loopdevs
|
||||||
|
for i in `seq 3`; do
|
||||||
|
TEST_DEV="${loopdevs[$i]}"
|
||||||
|
TEST_MNT="${roots[$i]}"
|
||||||
|
run_check_mkfs_test_dev
|
||||||
|
run_check_mount_test_dev
|
||||||
|
run_check $SUDO_HELPER mkdir -p "$TEST_MNT/.snapshots"
|
||||||
|
done
|
||||||
|
|
||||||
|
run_check_update_file()
|
||||||
|
{
|
||||||
|
run_check $SUDO_HELPER cp --reflink "${roots[$1]}/profile/$2" "${roots[$1]}/profile/staging"
|
||||||
|
run_check $SUDO_HELPER dd if=/dev/urandom conv=notrunc bs=4K count=4 seek=$3 "of=${roots[$1]}/profile/staging"
|
||||||
|
run_check $SUDO_HELPER mv "${roots[$1]}/profile/staging" "${roots[$1]}/profile/$2"
|
||||||
|
}
|
||||||
|
run_check_copy_snapshot_with_diff()
|
||||||
|
{
|
||||||
|
_mktemp_local send.data
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" send -f send.data -p "${roots[$1]}/.snapshots/$2" "${roots[$1]}/.snapshots/$3"
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" receive -f send.data "${roots[$4]}/.snapshots"
|
||||||
|
}
|
||||||
|
run_check_backup_profile()
|
||||||
|
{
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" subvolume snapshot -r "${roots[$1]}/profile" "${roots[$1]}/.snapshots/$3"
|
||||||
|
run_check_copy_snapshot_with_diff "$1" "$2" "$3" "$i_ext"
|
||||||
|
# Don't keep old snapshot in pc
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" subvolume delete "${roots[$1]}/.snapshots/$2"
|
||||||
|
}
|
||||||
|
run_check_restore_profile()
|
||||||
|
{
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" subvolume snapshot "${roots[$1]}/.snapshots/$2" "${roots[$1]}/profile"
|
||||||
|
}
|
||||||
|
run_check_copy_fresh_backup_and_replace_profile()
|
||||||
|
{
|
||||||
|
run_check_copy_snapshot_with_diff "$i_ext" "$2" "$3" "$1"
|
||||||
|
# IRL, it would be a nice idea to make a backup snapshot before deleting.
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" subvolume delete "${roots[$1]}/profile"
|
||||||
|
run_check_restore_profile "$1" "$3"
|
||||||
|
# Don't keep old snapshot in pc
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" subvolume delete "${roots[$1]}/.snapshots/$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" subvolume create "${roots[$i_pc1]}/profile"
|
||||||
|
run_check $SUDO_HELPER dd if=/dev/urandom bs=4K count=16 "of=${roots[$i_pc1]}/profile/day1"
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" subvolume snapshot -r "${roots[$i_pc1]}/profile" "${roots[$i_pc1]}/.snapshots/day1"
|
||||||
|
_mktemp_local send.data
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" send -f send.data "${roots[$i_pc1]}/.snapshots/day1"
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" receive -f send.data "${roots[$i_ext]}/.snapshots"
|
||||||
|
|
||||||
|
run_check_update_file "$i_pc1" day1 2
|
||||||
|
run_check_backup_profile "$i_pc1" day1 day2
|
||||||
|
|
||||||
|
_mktemp_local send.data
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" send -f send.data "${roots[$i_ext]}/.snapshots/day2"
|
||||||
|
run_check $SUDO_HELPER "$TOP/btrfs" receive -f send.data "${roots[$i_pc2]}/.snapshots"
|
||||||
|
run_check_restore_profile "$i_pc2" day2
|
||||||
|
run_check_update_file "$i_pc2" day1 3
|
||||||
|
run_check_backup_profile "$i_pc2" day2 day3
|
||||||
|
|
||||||
|
run_check_update_file "$i_pc2" day1 4
|
||||||
|
run_check_backup_profile "$i_pc2" day3 day4
|
||||||
|
|
||||||
|
run_check_copy_fresh_backup_and_replace_profile "$i_pc1" day2 day4
|
||||||
|
run_check_update_file "$i_pc1" day1 5
|
||||||
|
run_check_backup_profile "$i_pc1" day4 day5
|
||||||
|
|
||||||
|
run_check_copy_fresh_backup_and_replace_profile "$i_pc2" day4 day5
|
||||||
|
run_check_update_file "$i_pc2" day1 6
|
||||||
|
run_check_backup_profile "$i_pc2" day5 day6
|
||||||
|
|
||||||
|
run_check_umount_test_dev "${loopdevs[@]}"
|
||||||
|
rmdir "${roots[@]}"
|
||||||
|
rm -f send.data
|
||||||
|
cleanup_loopdevs
|
Loading…
Reference in New Issue
Block a user