Skip to content

Commit

Permalink
btrfs-progs: receive: don't lookup clone root for received subvolume
Browse files Browse the repository at this point in the history
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: f1c24cd ("Btrfs-progs: add btrfs send/receive commands")
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
  • Loading branch information
osandov authored and kdave committed Mar 31, 2020
1 parent d451fe2 commit 0183068
Showing 1 changed file with 8 additions and 10 deletions.
18 changes: 8 additions & 10 deletions cmds/receive.c
Original file line number Diff line number Diff line change
Expand Up @@ -745,23 +745,21 @@ 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
ret = PTR_ERR(si);
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);
Expand Down

0 comments on commit 0183068

Please sign in to comment.