Fix inode link count checks in btrfsck
authorYan Zheng <zheng.yan@oracle.com>
Thu, 9 Sep 2010 13:41:48 +0000 (21:41 +0800)
committerChris Mason <chris.mason@oracle.com>
Fri, 24 Sep 2010 00:26:50 +0000 (20:26 -0400)
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
btrfsck.c

index af5746f758d491a37d160c55bff3028063833312..cd2cedd7a9a864841143c6d313e1111ef44876dc 100644 (file)
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -423,7 +423,6 @@ static struct inode_backref *get_inode_backref(struct inode_record *rec,
        memcpy(backref->name, name, namelen);
        backref->name[namelen] = '\0';
        list_add_tail(&backref->list, &rec->backrefs);
-       rec->found_link++;
        return backref;
 }
 
@@ -451,6 +450,7 @@ static int add_inode_backref(struct cache_tree *inode_cache,
                backref->filetype = filetype;
                backref->found_dir_index = 1;
        } else if (itemtype == BTRFS_DIR_ITEM_KEY) {
+               rec->found_link++;
                if (backref->found_dir_item)
                        backref->errors |= REF_ERR_DUP_DIR_ITEM;
                if (backref->found_dir_index && backref->filetype != filetype)
@@ -478,6 +478,7 @@ static int merge_inode_recs(struct inode_record *src, struct inode_record *dst,
                            struct cache_tree *dst_cache)
 {
        struct inode_backref *backref;
+       u32 dir_count = 0;
 
        dst->merging = 1;
        list_for_each_entry(backref, &src->backrefs, list) {
@@ -488,6 +489,7 @@ static int merge_inode_recs(struct inode_record *src, struct inode_record *dst,
                                        BTRFS_DIR_INDEX_KEY, backref->errors);
                }
                if (backref->found_dir_item) {
+                       dir_count++;
                        add_inode_backref(dst_cache, dst->ino,
                                        backref->dir, 0, backref->name,
                                        backref->namelen, backref->filetype,
@@ -512,6 +514,8 @@ static int merge_inode_recs(struct inode_record *src, struct inode_record *dst,
        if (dst->first_extent_gap > src->first_extent_gap)
                dst->first_extent_gap = src->first_extent_gap;
 
+       BUG_ON(src->found_link < dir_count);
+       dst->found_link += src->found_link - dir_count;
        dst->found_size += src->found_size;
        if (src->extent_start != (u64)-1) {
                if (dst->extent_start == (u64)-1) {
@@ -1164,7 +1168,7 @@ static int check_root_dir(struct inode_record *rec)
 
        if (!rec->found_inode_item || rec->errors)
                goto out;
-       if (rec->nlink != 1 || rec->found_link != 1)
+       if (rec->nlink != 1 || rec->found_link != 0)
                goto out;
        if (list_empty(&rec->backrefs))
                goto out;