From 018306809b4bcca175dbf7dfcc8ad863a9d3e6d5 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Wed, 11 Mar 2020 01:17:10 -0700 Subject: [PATCH] btrfs-progs: receive: don't lookup clone root for received subvolume When we process a clone request, we look up the source subvolume by UUID, even if the source is the subvolume that we're currently receiving. Usually, this is fine. However, if for some reason we previously received the same subvolume, then this will use paths relative to the previously received subvolume instead of the current one. This is incorrect, since the send stream may use temporary names for the clone source. This can be reproduced as follows: btrfs subvolume create subvol dd if=/dev/urandom of=subvol/foo bs=1M count=1 cp --reflink subvol/foo subvol/bar mkdir subvol/dir mv subvol/foo subvol/dir/ btrfs property set subvol ro true btrfs send -f send.data subvol mkdir first second btrfs receive -f send.data first btrfs receive -f send.data second The second receive results in this error: ERROR: cannot open first/subvol/o259-7-0/foo: No such file or directory Fix it by always cloning from the current subvolume if its UUID matches. This has the nice side effect of avoiding unnecessary UUID tree lookups in that case. Fixes: f1c24cd80dfd ("Btrfs-progs: add btrfs send/receive commands") Reviewed-by: Filipe Manana Signed-off-by: Omar Sandoval Signed-off-by: David Sterba --- cmds/receive.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/cmds/receive.c b/cmds/receive.c index a4bf8787..74b73f48 100644 --- a/cmds/receive.c +++ b/cmds/receive.c @@ -745,15 +745,14 @@ static int process_clone(const char *path, u64 offset, u64 len, if (ret < 0) goto out; - si = subvol_uuid_search(&rctx->sus, 0, clone_uuid, clone_ctransid, - NULL, - subvol_search_by_received_uuid); - if (IS_ERR_OR_NULL(si)) { - if (memcmp(clone_uuid, rctx->cur_subvol.received_uuid, - BTRFS_UUID_SIZE) == 0) { - /* TODO check generation of extent */ - subvol_path = rctx->cur_subvol_path; - } else { + if (memcmp(clone_uuid, rctx->cur_subvol.received_uuid, + BTRFS_UUID_SIZE) == 0) { + subvol_path = rctx->cur_subvol_path; + } else { + si = subvol_uuid_search(&rctx->sus, 0, clone_uuid, clone_ctransid, + NULL, + subvol_search_by_received_uuid); + if (IS_ERR_OR_NULL(si)) { if (!si) ret = -ENOENT; else @@ -761,7 +760,6 @@ static int process_clone(const char *path, u64 offset, u64 len, error("clone: did not find source subvol"); goto out; } - } else { /* strip the subvolume that we are receiving to from the start of subvol_path */ if (rctx->full_root_path) { size_t root_len = strlen(rctx->full_root_path);