Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Btrfs: use received_uuid of parent during send

Neil Horman pointed out a problem where if he did something like this

receive A
snap A B
change B
send -p A B

and then on another box do

recieve A
receive B

the receive B would fail because we use the UUID of A for the clone sources for
B. This makes sense most of the time because normally you are sending from the
original sources, not a received source. However when you use a recieved subvol
its UUID is going to be something completely different, so if you then try to
receive the diff on a different volume it won't find the UUID because the new A
will be something else. The only constant is the received uuid. So instead
check to see if we have received_uuid set on the root, and if so use that as the
clone source, as btrfs receive looks for matches either in received_uuid or
uuid. Thanks,

Reported-by: Neil Horman <nhorman@redhat.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
Reviewed-by: Hugo Mills <hugo@carfax.org.uk>
Signed-off-by: Chris Mason <clm@fb.com>

authored by

Josef Bacik and committed by
Chris Mason
37b8d27d 0eeff236

+21 -4
+21 -4
fs/btrfs/send.c
··· 2356 2356 TLV_PUT_U64(sctx, BTRFS_SEND_A_CTRANSID, 2357 2357 le64_to_cpu(sctx->send_root->root_item.ctransid)); 2358 2358 if (parent_root) { 2359 - TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, 2360 - sctx->parent_root->root_item.uuid); 2359 + if (!btrfs_is_empty_uuid(parent_root->root_item.received_uuid)) 2360 + TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, 2361 + parent_root->root_item.received_uuid); 2362 + else 2363 + TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, 2364 + parent_root->root_item.uuid); 2361 2365 TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID, 2362 2366 le64_to_cpu(sctx->parent_root->root_item.ctransid)); 2363 2367 } ··· 4590 4586 if (ret < 0) 4591 4587 goto out; 4592 4588 4593 - TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, 4594 - clone_root->root->root_item.uuid); 4589 + /* 4590 + * If the parent we're using has a received_uuid set then use that as 4591 + * our clone source as that is what we will look for when doing a 4592 + * receive. 4593 + * 4594 + * This covers the case that we create a snapshot off of a received 4595 + * subvolume and then use that as the parent and try to receive on a 4596 + * different host. 4597 + */ 4598 + if (!btrfs_is_empty_uuid(clone_root->root->root_item.received_uuid)) 4599 + TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, 4600 + clone_root->root->root_item.received_uuid); 4601 + else 4602 + TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, 4603 + clone_root->root->root_item.uuid); 4595 4604 TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID, 4596 4605 le64_to_cpu(clone_root->root->root_item.ctransid)); 4597 4606 TLV_PUT_PATH(sctx, BTRFS_SEND_A_CLONE_PATH, p);