diff options
authorJosef Bacik <>2013-06-04 16:54:52 -0400
committerChris Mason <>2013-06-19 13:52:52 -0400
commit7e992408e3723bdb14f4af4f970b12f8f76d0b14 (patch)
parentb3be7aea12b3f974895191026cb012f6fa78203c (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 <> Signed-off-by: Chris Mason <>
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,
+ if (backref->found_forward_ref && backref->found_dir_item)
+ backref->reachable = 1;
return 0;