diff options
Diffstat (limited to 'cmds-check.c')
-rw-r--r-- | cmds-check.c | 143 |
1 files changed, 122 insertions, 21 deletions
diff --git a/cmds-check.c b/cmds-check.c index fd661d9..0165fba 100644 --- a/cmds-check.c +++ b/cmds-check.c @@ -35,6 +35,7 @@ #include "utils.h" #include "commands.h" #include "free-space-cache.h" +#include "free-space-tree.h" #include "btrfsck.h" #include "qgroup-verify.h" #include "rbtree-utils.h" @@ -566,12 +567,15 @@ static struct inode_record *clone_inode_rec(struct inode_record *orig_rec) struct inode_record *rec; struct inode_backref *backref; struct inode_backref *orig; + struct inode_backref *tmp; struct orphan_data_extent *src_orphan; struct orphan_data_extent *dst_orphan; size_t size; int ret; rec = malloc(sizeof(*rec)); + if (!rec) + return ERR_PTR(-ENOMEM); memcpy(rec, orig_rec, sizeof(*rec)); rec->refs = 1; INIT_LIST_HEAD(&rec->backrefs); @@ -581,13 +585,19 @@ static struct inode_record *clone_inode_rec(struct inode_record *orig_rec) list_for_each_entry(orig, &orig_rec->backrefs, list) { size = sizeof(*orig) + orig->namelen + 1; backref = malloc(size); + if (!backref) { + ret = -ENOMEM; + goto cleanup; + } memcpy(backref, orig, size); list_add_tail(&backref->list, &rec->backrefs); } list_for_each_entry(src_orphan, &orig_rec->orphan_extents, list) { dst_orphan = malloc(sizeof(*dst_orphan)); - /* TODO: Fix all the HELL of un-catched -ENOMEM case */ - BUG_ON(!dst_orphan); + if (!dst_orphan) { + ret = -ENOMEM; + goto cleanup; + } memcpy(dst_orphan, src_orphan, sizeof(*src_orphan)); list_add_tail(&dst_orphan->list, &rec->orphan_extents); } @@ -595,6 +605,23 @@ static struct inode_record *clone_inode_rec(struct inode_record *orig_rec) BUG_ON(ret < 0); return rec; + +cleanup: + if (!list_empty(&rec->backrefs)) + list_for_each_entry_safe(orig, tmp, &rec->backrefs, list) { + list_del(&orig->list); + free(orig); + } + + if (!list_empty(&rec->orphan_extents)) + list_for_each_entry_safe(orig, tmp, &rec->orphan_extents, list) { + list_del(&orig->list); + free(orig); + } + + free(rec); + + return ERR_PTR(ret); } static void print_orphan_data_extents(struct list_head *orphan_extents, @@ -730,11 +757,15 @@ static struct inode_record *get_inode_rec(struct cache_tree *inode_cache, rec = node->data; if (mod && rec->refs > 1) { node->data = clone_inode_rec(rec); + if (IS_ERR(node->data)) + return node->data; rec->refs--; rec = node->data; } } else if (mod) { rec = calloc(1, sizeof(*rec)); + if (!rec) + return ERR_PTR(-ENOMEM); rec->ino = ino; rec->extent_start = (u64)-1; rec->refs = 1; @@ -743,6 +774,10 @@ static struct inode_record *get_inode_rec(struct cache_tree *inode_cache, rec->holes = RB_ROOT; node = malloc(sizeof(*node)); + if (!node) { + free(rec); + return ERR_PTR(-ENOMEM); + } node->cache.start = ino; node->cache.size = 1; node->data = rec; @@ -751,7 +786,8 @@ static struct inode_record *get_inode_rec(struct cache_tree *inode_cache, rec->found_link = 1; ret = insert_cache_extent(inode_cache, &node->cache); - BUG_ON(ret); + if (ret) + return ERR_PTR(-EEXIST); } return rec; } @@ -810,7 +846,8 @@ static void maybe_free_inode_rec(struct cache_tree *inode_cache, if (backref->found_dir_item && backref->found_dir_index) { if (backref->filetype != filetype) backref->errors |= REF_ERR_FILETYPE_UNMATCH; - if (!backref->errors && backref->found_inode_ref) { + if (!backref->errors && backref->found_inode_ref && + rec->nlink == rec->found_link) { list_del(&backref->list); free(backref); } @@ -916,6 +953,8 @@ static struct inode_backref *get_inode_backref(struct inode_record *rec, } backref = malloc(sizeof(*backref) + namelen + 1); + if (!backref) + return NULL; memset(backref, 0, sizeof(*backref)); backref->dir = dir; backref->namelen = namelen; @@ -934,7 +973,9 @@ static int add_inode_backref(struct cache_tree *inode_cache, struct inode_backref *backref; rec = get_inode_rec(inode_cache, ino, 1); + BUG_ON(IS_ERR(rec)); backref = get_inode_backref(rec, name, namelen, dir); + BUG_ON(!backref); if (errors) backref->errors |= errors; if (itemtype == BTRFS_DIR_INDEX_KEY) { @@ -1088,6 +1129,7 @@ again: ins = node; } else { ins = malloc(sizeof(*ins)); + BUG_ON(!ins); ins->cache.start = node->cache.start; ins->cache.size = node->cache.size; ins->data = rec; @@ -1096,6 +1138,7 @@ again: ret = insert_cache_extent(dst, &ins->cache); if (ret == -EEXIST) { conflict = get_inode_rec(dst, rec->ino, 1); + BUG_ON(IS_ERR(conflict)); merge_inode_recs(rec, conflict, dst); if (rec->checked) { conflict->checked = 1; @@ -1123,6 +1166,7 @@ again: maybe_free_inode_rec(dst, dst_node->current); } dst_node->current = get_inode_rec(dst, current_ino, 1); + BUG_ON(IS_ERR(dst_node->current)); } return 0; } @@ -1160,6 +1204,8 @@ static int add_shared_node(struct cache_tree *shared, u64 bytenr, u32 refs) struct shared_node *node; node = calloc(1, sizeof(*node)); + if (!node) + return -ENOMEM; node->cache.start = bytenr; node->cache.size = 1; cache_tree_init(&node->root_cache); @@ -1167,8 +1213,8 @@ static int add_shared_node(struct cache_tree *shared, u64 bytenr, u32 refs) node->refs = refs; ret = insert_cache_extent(shared, &node->cache); - BUG_ON(ret); - return 0; + + return ret; } static int enter_shared_node(struct btrfs_root *root, u64 bytenr, u32 refs, @@ -1176,6 +1222,7 @@ static int enter_shared_node(struct btrfs_root *root, u64 bytenr, u32 refs, { struct shared_node *node; struct shared_node *dest; + int ret; if (level == wc->active_node) return 0; @@ -1183,7 +1230,8 @@ static int enter_shared_node(struct btrfs_root *root, u64 bytenr, u32 refs, BUG_ON(wc->active_node <= level); node = find_shared_node(&wc->shared, bytenr); if (!node) { - add_shared_node(&wc->shared, bytenr, refs); + ret = add_shared_node(&wc->shared, bytenr, refs); + BUG_ON(ret); node = find_shared_node(&wc->shared, bytenr); wc->nodes[level] = node; wc->active_node = level; @@ -1663,6 +1711,7 @@ static int process_one_leaf(struct btrfs_root *root, struct extent_buffer *eb, } active_node->current = get_inode_rec(inode_cache, key.objectid, 1); + BUG_ON(IS_ERR(active_node->current)); } switch (key.type) { case BTRFS_DIR_ITEM_KEY: @@ -2063,6 +2112,7 @@ static int add_missing_dir_index(struct btrfs_root *root, backref->found_dir_index = 1; dir_rec = get_inode_rec(inode_cache, backref->dir, 0); + BUG_ON(IS_ERR(dir_rec)); if (!dir_rec) return 0; dir_rec->found_size += backref->namelen; @@ -2392,7 +2442,7 @@ static int reset_nlink(struct btrfs_trans_handle *trans, list_for_each_entry(backref, &rec->backrefs, list) { ret = btrfs_add_link(trans, root, rec->ino, backref->dir, backref->name, backref->namelen, - backref->ref_type, &backref->index, 1); + backref->filetype, &backref->index, 1); if (ret < 0) goto out; } @@ -2887,6 +2937,7 @@ static int check_inode_recs(struct btrfs_root *root, return err; rec = get_inode_rec(inode_cache, root_dirid, 0); + BUG_ON(IS_ERR(rec)); if (rec) { ret = check_root_dir(rec); if (ret) { @@ -2994,13 +3045,16 @@ static struct root_record *get_root_rec(struct cache_tree *root_cache, rec = container_of(cache, struct root_record, cache); } else { rec = calloc(1, sizeof(*rec)); + if (!rec) + return ERR_PTR(-ENOMEM); rec->objectid = objectid; INIT_LIST_HEAD(&rec->backrefs); rec->cache.start = objectid; rec->cache.size = 1; ret = insert_cache_extent(root_cache, &rec->cache); - BUG_ON(ret); + if (ret) + return ERR_PTR(-EEXIST); } return rec; } @@ -3021,6 +3075,8 @@ static struct root_backref *get_root_backref(struct root_record *rec, } backref = calloc(1, sizeof(*backref) + namelen + 1); + if (!backref) + return NULL; backref->ref_root = ref_root; backref->dir = dir; backref->index = index; @@ -3058,7 +3114,9 @@ static int add_root_backref(struct cache_tree *root_cache, struct root_backref *backref; rec = get_root_rec(root_cache, root_id); + BUG_ON(IS_ERR(rec)); backref = get_root_backref(rec, ref_root, dir, index, name, namelen); + BUG_ON(!backref); backref->errors |= errors; @@ -3163,6 +3221,7 @@ static int check_root_refs(struct btrfs_root *root, int errors = 0; rec = get_root_rec(root_cache, BTRFS_FS_TREE_OBJECTID); + BUG_ON(IS_ERR(rec)); rec->found_ref = 1; /* fixme: this can not detect circular references */ @@ -3184,6 +3243,7 @@ static int check_root_refs(struct btrfs_root *root, ref_root = get_root_rec(root_cache, backref->ref_root); + BUG_ON(IS_ERR(ref_root)); if (ref_root->found_ref > 0) continue; @@ -3430,6 +3490,7 @@ static int check_fs_root(struct btrfs_root *root, if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) { rec = get_root_rec(root_cache, root->root_key.objectid); + BUG_ON(IS_ERR(rec)); if (btrfs_root_refs(root_item) > 0) rec->found_root_item = 1; } @@ -3446,6 +3507,7 @@ static int check_fs_root(struct btrfs_root *root, inode = get_inode_rec(&root_node.inode_cache, orphan->objectid, 1); + BUG_ON(IS_ERR(inode)); inode->errors |= I_ERR_FILE_EXTENT_ORPHAN; list_move(&orphan->list, &inode->orphan_extents); } @@ -4293,6 +4355,9 @@ static struct tree_backref *alloc_tree_backref(struct extent_record *rec, u64 parent, u64 root) { struct tree_backref *ref = malloc(sizeof(*ref)); + + if (!ref) + return NULL; memset(&ref->node, 0, sizeof(ref->node)); if (parent > 0) { ref->parent = parent; @@ -4349,6 +4414,9 @@ static struct data_backref *alloc_data_backref(struct extent_record *rec, u64 max_size) { struct data_backref *ref = malloc(sizeof(*ref)); + + if (!ref) + return NULL; memset(&ref->node, 0, sizeof(ref->node)); ref->node.is_data = 1; @@ -4519,6 +4587,8 @@ static int add_extent_rec(struct cache_tree *extent_cache, return ret; } rec = malloc(sizeof(*rec)); + if (!rec) + return -ENOMEM; rec->start = start; rec->max_size = max_size; rec->nr = max(nr, max_size); @@ -4599,8 +4669,10 @@ static int add_tree_backref(struct cache_tree *extent_cache, u64 bytenr, } back = find_tree_backref(rec, parent, root); - if (!back) + if (!back) { back = alloc_tree_backref(rec, parent, root); + BUG_ON(!back); + } if (found_ref) { if (back->node.found_ref) { @@ -4659,9 +4731,11 @@ static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr, */ back = find_data_backref(rec, parent, root, owner, offset, found_ref, bytenr, max_size); - if (!back) + if (!back) { back = alloc_data_backref(rec, parent, root, owner, offset, max_size); + BUG_ON(!back); + } if (found_ref) { BUG_ON(num_refs != 1); @@ -5134,6 +5208,10 @@ static int process_extent_item(struct btrfs_root *root, ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item); refs = btrfs_extent_refs(eb, ei); + if (btrfs_extent_flags(eb, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK) + metadata = 1; + else + metadata = 0; add_extent_rec(extent_cache, NULL, 0, key.objectid, num_bytes, refs, 0, 0, 0, metadata, 1, num_bytes); @@ -5399,9 +5477,29 @@ static int check_space_cache(struct btrfs_root *root) btrfs_remove_free_space_cache(cache); } - ret = load_free_space_cache(root->fs_info, cache); - if (!ret) - continue; + if (btrfs_fs_compat_ro(root->fs_info, + BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE)) { + ret = exclude_super_stripes(root, cache); + if (ret) { + fprintf(stderr, "could not exclude super stripes: %s\n", + strerror(-ret)); + error++; + continue; + } + ret = load_free_space_tree(root->fs_info, cache); + free_excluded_extents(root, cache); + if (ret < 0) { + fprintf(stderr, "could not load free space tree: %s\n", + strerror(-ret)); + error++; + continue; + } + error += ret; + } else { + ret = load_free_space_cache(root->fs_info, cache); + if (!ret) + continue; + } ret = verify_space_cache(root, cache); if (ret) { @@ -9120,11 +9218,11 @@ static int build_roots_info_cache(struct btrfs_fs_info *info) iref = (struct btrfs_extent_inline_ref *)(ei + 1); level = found_key.offset; } else { - struct btrfs_tree_block_info *info; + struct btrfs_tree_block_info *binfo; - info = (struct btrfs_tree_block_info *)(ei + 1); - iref = (struct btrfs_extent_inline_ref *)(info + 1); - level = btrfs_tree_block_level(leaf, info); + binfo = (struct btrfs_tree_block_info *)(ei + 1); + iref = (struct btrfs_extent_inline_ref *)(binfo + 1); + level = btrfs_tree_block_level(leaf, binfo); } /* @@ -9640,8 +9738,12 @@ int cmd_check(int argc, char **argv) goto close_out; } - if (!ctx.progress_enabled) - fprintf(stderr, "checking free space cache\n"); + if (!ctx.progress_enabled) { + if (btrfs_fs_compat_ro(info, BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE)) + fprintf(stderr, "checking free space tree\n"); + else + fprintf(stderr, "checking free space cache\n"); + } ret = check_space_cache(root); if (ret) goto out; @@ -9730,7 +9832,6 @@ out: printf("file data blocks allocated: %llu\n referenced %llu\n", (unsigned long long)data_bytes_allocated, (unsigned long long)data_bytes_referenced); - printf("%s\n", PACKAGE_STRING); free_root_recs_tree(&root_cache); close_out: |