diff options
author | Josef Bacik <jbacik@fb.com> | 2015-06-04 17:17:25 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2015-06-12 16:20:38 -0400 |
commit | 37b8d27de5d0079e1ecef2711061048e13054ebe (patch) | |
tree | ca36f955398f3e3dc9f369bee28bbcc125d8b628 | |
parent | 0eeff2362b829b5e80f8b69f86b60b8094bc742d (diff) |
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>
-rw-r--r-- | fs/btrfs/send.c | 25 |
1 files changed, 21 insertions, 4 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 50ebc622a324..aa72bfd28f7d 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c | |||
@@ -2356,8 +2356,12 @@ static int send_subvol_begin(struct send_ctx *sctx) | |||
2356 | TLV_PUT_U64(sctx, BTRFS_SEND_A_CTRANSID, | 2356 | TLV_PUT_U64(sctx, BTRFS_SEND_A_CTRANSID, |
2357 | le64_to_cpu(sctx->send_root->root_item.ctransid)); | 2357 | le64_to_cpu(sctx->send_root->root_item.ctransid)); |
2358 | if (parent_root) { | 2358 | if (parent_root) { |
2359 | TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, | 2359 | if (!btrfs_is_empty_uuid(parent_root->root_item.received_uuid)) |
2360 | sctx->parent_root->root_item.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 | TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID, | 2365 | TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID, |
2362 | le64_to_cpu(sctx->parent_root->root_item.ctransid)); | 2366 | le64_to_cpu(sctx->parent_root->root_item.ctransid)); |
2363 | } | 2367 | } |
@@ -4586,8 +4590,21 @@ verbose_printk("btrfs: send_clone offset=%llu, len=%d, clone_root=%llu, " | |||
4586 | if (ret < 0) | 4590 | if (ret < 0) |
4587 | goto out; | 4591 | goto out; |
4588 | 4592 | ||
4589 | TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, | 4593 | /* |
4590 | clone_root->root->root_item.uuid); | 4594 | * If the parent we're using has a received_uuid set then use that as |
4595 | * our clone source as that is what we will look for when doing a | ||
4596 | * receive. | ||
4597 | * | ||
4598 | * This covers the case that we create a snapshot off of a received | ||
4599 | * subvolume and then use that as the parent and try to receive on a | ||
4600 | * different host. | ||
4601 | */ | ||
4602 | if (!btrfs_is_empty_uuid(clone_root->root->root_item.received_uuid)) | ||
4603 | TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, | ||
4604 | clone_root->root->root_item.received_uuid); | ||
4605 | else | ||
4606 | TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, | ||
4607 | clone_root->root->root_item.uuid); | ||
4591 | TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID, | 4608 | TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID, |
4592 | le64_to_cpu(clone_root->root->root_item.ctransid)); | 4609 | le64_to_cpu(clone_root->root->root_item.ctransid)); |
4593 | TLV_PUT_PATH(sctx, BTRFS_SEND_A_CLONE_PATH, p); | 4610 | TLV_PUT_PATH(sctx, BTRFS_SEND_A_CLONE_PATH, p); |