aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2015-03-12 11:16:20 -0400
committerChris Mason <clm@fb.com>2015-03-26 20:55:51 -0400
commit8996a48c0a8ed01c55f52e6794625c95a9977ee6 (patch)
tree97ed4620748c00b8a7bca561c40a51a869454184 /fs
parent2f1f465ae6da244099af55c066e5355abd8ff620 (diff)
Btrfs: incremental send, clear name from cache after orphanization
If a directory's reference ends up being orphanized, because the inode currently being processed has a new path that matches that directory's path, make sure we evict the name of the directory from the name cache. This is because there might be descendent inodes (either directories or regular files) that will be orphanized later too, and therefore the orphan name of the ancestor must be used, otherwise we send issue rename operations with a wrong path in the send stream. Reproducer: $ mkfs.btrfs -f /dev/sdb $ mount /dev/sdb /mnt $ mkdir -p /mnt/data/n1/n2/p1/p2 $ mkdir /mnt/data/n4 $ mkdir -p /mnt/data/p1/p2 $ btrfs subvolume snapshot -r /mnt /mnt/snap1 $ mv /mnt/data/p1/p2 /mnt/data $ mv /mnt/data/n1/n2/p1/p2 /mnt/data/p1 $ mv /mnt/data/p2 /mnt/data/n1/n2/p1 $ mv /mnt/data/n1/n2 /mnt/data/p1 $ mv /mnt/data/p1 /mnt/data/n4 $ mv /mnt/data/n4/p1/n2/p1 /mnt/data $ btrfs subvolume snapshot -r /mnt /mnt/snap2 $ btrfs send /mnt/snap1 -f /tmp/1.send $ btrfs send -p /mnt/snap1 /mnt/snap2 -f /tmp/2.send $ mkfs.btrfs -f /dev/sdc $ mount /dev/sdc /mnt2 $ btrfs receive /mnt2 -f /tmp/1.send $ btrfs receive /mnt2 -f /tmp/2.send ERROR: rename data/p1/p2 -> data/n4/p1/p2 failed. no such file or directory Directories data/p1 (inode 263) and data/p1/p2 (inode 264) in the parent snapshot are both orphanized during the incremental send, and as soon as data/p1 is orphanized, we must make sure that when orphanizing data/p1/p2 we use a source path of o263-6-o/p2 for the rename operation instead of the old path data/p1/p2 (the one before the orphanization of inode 263). A test case for xfstests follows soon. Reported-by: Robbie Ko <robbieko@synology.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/send.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 571de5a08fe7..00cb924884f5 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -3610,10 +3610,27 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
3610 if (ret < 0) 3610 if (ret < 0)
3611 goto out; 3611 goto out;
3612 if (ret) { 3612 if (ret) {
3613 struct name_cache_entry *nce;
3614
3613 ret = orphanize_inode(sctx, ow_inode, ow_gen, 3615 ret = orphanize_inode(sctx, ow_inode, ow_gen,
3614 cur->full_path); 3616 cur->full_path);
3615 if (ret < 0) 3617 if (ret < 0)
3616 goto out; 3618 goto out;
3619 /*
3620 * Make sure we clear our orphanized inode's
3621 * name from the name cache. This is because the
3622 * inode ow_inode might be an ancestor of some
3623 * other inode that will be orphanized as well
3624 * later and has an inode number greater than
3625 * sctx->send_progress. We need to prevent
3626 * future name lookups from using the old name
3627 * and get instead the orphan name.
3628 */
3629 nce = name_cache_search(sctx, ow_inode, ow_gen);
3630 if (nce) {
3631 name_cache_delete(sctx, nce);
3632 kfree(nce);
3633 }
3617 } else { 3634 } else {
3618 ret = send_unlink(sctx, cur->full_path); 3635 ret = send_unlink(sctx, cur->full_path);
3619 if (ret < 0) 3636 if (ret < 0)