Skip to content

Commit 29d6d30

Browse files
fdmananaJosef Bacik
authored andcommitted
Btrfs: send, don't send rmdir for same target multiple times
When doing an incremental send, if we delete a directory that has N > 1 hardlinks for the same file and that file has the highest inode number inside the directory contents, an incremental send would send N times an rmdir operation against the directory. This made the btrfs receive command fail on the second rmdir instruction, as the target directory didn't exist anymore. Steps to reproduce the issue: $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ mkdir -p /mnt/btrfs/a/b/c $ echo 'ola mundo' > /mnt/btrfs/a/b/c/foo.txt $ ln /mnt/btrfs/a/b/c/foo.txt /mnt/btrfs/a/b/c/bar.txt $ btrfs subvolume snapshot -r /mnt/btrfs /mnt/btrfs/snap1 $ btrfs send /mnt/btrfs/snap1 -f /tmp/base.send $ rm -f /mnt/btrfs/a/b/c/foo.txt $ rm -f /mnt/btrfs/a/b/c/bar.txt $ rmdir /mnt/btrfs/a/b/c $ btrfs subvolume snapshot -r /mnt/btrfs /mnt/btrfs/snap2 $ btrfs send -p /mnt/btrfs/snap1 /mnt/btrfs/snap2 -f /tmp/incremental.send $ umount /mnt/btrfs $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ btrfs receive /mnt/btrfs -f /tmp/base.send $ btrfs receive /mnt/btrfs -f /tmp/incremental.send The second btrfs receive command failed with: ERROR: rmdir o259-6-0 failed. No such file or directory A test case for xfstests follows. Signed-off-by: Filipe David Borba Manana <[email protected]> Signed-off-by: Josef Bacik <[email protected]>
1 parent 2b863a1 commit 29d6d30

File tree

1 file changed

+4
-1
lines changed

1 file changed

+4
-1
lines changed

fs/btrfs/send.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3085,6 +3085,7 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
30853085
u64 ow_gen;
30863086
int did_overwrite = 0;
30873087
int is_orphan = 0;
3088+
u64 last_dir_ino_rm = 0;
30883089

30893090
verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
30903091

@@ -3349,7 +3350,8 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
33493350
ret = send_utimes(sctx, cur->dir, cur->dir_gen);
33503351
if (ret < 0)
33513352
goto out;
3352-
} else if (ret == inode_state_did_delete) {
3353+
} else if (ret == inode_state_did_delete &&
3354+
cur->dir != last_dir_ino_rm) {
33533355
ret = can_rmdir(sctx, cur->dir, sctx->cur_ino);
33543356
if (ret < 0)
33553357
goto out;
@@ -3361,6 +3363,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
33613363
ret = send_rmdir(sctx, valid_path);
33623364
if (ret < 0)
33633365
goto out;
3366+
last_dir_ino_rm = cur->dir;
33643367
}
33653368
}
33663369
}

0 commit comments

Comments
 (0)