diff options
author | Josef Bacik <jbacik@fusionio.com> | 2013-06-04 16:54:52 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2013-06-19 13:52:52 -0400 |
commit | 7e992408e3723bdb14f4af4f970b12f8f76d0b14 (patch) | |
tree | 0775d0611435c005e18f3b5a03ffad3598a41cd4 | |
parent | b3be7aea12b3f974895191026cb012f6fa78203c (diff) |
Btrfs-progs: fix incorrect root backref errors in fsck
A user reported that fsck was complaining about unresolved refs for some
snapshots. You can reproduce this by doing
mkfs.btrfs /dev/sdb
mount /dev/sdb /mnt
btrfs subvol snap /mnt/ /mnt/a
btrfs subvol snap /mnt/ /mnt/b
btrfs subvol del /mnt/a
umount /mnt
btrfsck /dev/sdb
and you'd get this
unresolved ref root 258 dir 256 index 2 namelen 1 name a error 600
because snapshot b has a dir item that points to a. Except we encode in our
root ref the dirid of the ref holder, and if it doesn't match we just give it
back a empty directory since we can't hardlink directories. This makes the
check in btrfsck bogus, when we delete a we remove the ref key for it so any
lookups into /mnt/b/a will just give a blank directory as it's supposed to. Fix
this by only saying the backref is reachable if there is both a DIR_ITEM and a
REF_KEY for the given root. With this patch I no longer see errors when running
this reproducer. Thanks,
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
-rw-r--r-- | cmds-check.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/cmds-check.c b/cmds-check.c index bbef89a3..4083298f 100644 --- a/cmds-check.c +++ b/cmds-check.c @@ -1507,14 +1507,16 @@ static int add_root_backref(struct cache_tree *root_cache, } if (item_type == BTRFS_DIR_ITEM_KEY) { + if (backref->found_forward_ref) + rec->found_ref++; backref->found_dir_item = 1; - backref->reachable = 1; - rec->found_ref++; } else if (item_type == BTRFS_DIR_INDEX_KEY) { backref->found_dir_index = 1; } else if (item_type == BTRFS_ROOT_REF_KEY) { if (backref->found_forward_ref) backref->errors |= REF_ERR_DUP_ROOT_REF; + else if (backref->found_dir_item) + rec->found_ref++; backref->found_forward_ref = 1; } else if (item_type == BTRFS_ROOT_BACKREF_KEY) { if (backref->found_back_ref) @@ -1524,6 +1526,8 @@ static int add_root_backref(struct cache_tree *root_cache, BUG_ON(1); } + if (backref->found_forward_ref && backref->found_dir_item) + backref->reachable = 1; return 0; } |