#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"
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);
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);
}
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,
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;
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;
rec->found_link = 1;
ret = insert_cache_extent(inode_cache, &node->cache);
- BUG_ON(ret);
+ if (ret)
+ return ERR_PTR(-EEXIST);
}
return rec;
}
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);
}
}
backref = malloc(sizeof(*backref) + namelen + 1);
+ if (!backref)
+ return NULL;
memset(backref, 0, sizeof(*backref));
backref->dir = dir;
backref->namelen = namelen;
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) {
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;
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;
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;
}
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);
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,
{
struct shared_node *node;
struct shared_node *dest;
+ int ret;
if (level == wc->active_node)
return 0;
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;
}
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:
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;
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;
}
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) {
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;
}
}
backref = calloc(1, sizeof(*backref) + namelen + 1);
+ if (!backref)
+ return NULL;
backref->ref_root = ref_root;
backref->dir = dir;
backref->index = index;
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;
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 */
ref_root = get_root_rec(root_cache,
backref->ref_root);
+ BUG_ON(IS_ERR(ref_root));
if (ref_root->found_ref > 0)
continue;
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;
}
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);
}
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;
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;
return ret;
}
rec = malloc(sizeof(*rec));
+ if (!rec)
+ return -ENOMEM;
rec->start = start;
rec->max_size = max_size;
rec->nr = max(nr, max_size);
}
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) {
*/
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);
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);
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) {
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);
}
/*
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;