|
@@ -245,7 +245,7 @@ static int exclude_super_stripes(struct btrfs_root *root,
|
|
|
cache->bytes_super += stripe_len;
|
|
|
ret = add_excluded_extent(root, cache->key.objectid,
|
|
|
stripe_len);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
}
|
|
|
|
|
|
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
|
|
@@ -253,13 +253,13 @@ static int exclude_super_stripes(struct btrfs_root *root,
|
|
|
ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
|
|
|
cache->key.objectid, bytenr,
|
|
|
0, &logical, &nr, &stripe_len);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
|
|
|
while (nr--) {
|
|
|
cache->bytes_super += stripe_len;
|
|
|
ret = add_excluded_extent(root, logical[nr],
|
|
|
stripe_len);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
}
|
|
|
|
|
|
kfree(logical);
|
|
@@ -321,7 +321,7 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
|
|
|
total_added += size;
|
|
|
ret = btrfs_add_free_space(block_group, start,
|
|
|
size);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM or logic error */
|
|
|
start = extent_end + 1;
|
|
|
} else {
|
|
|
break;
|
|
@@ -332,7 +332,7 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
|
|
|
size = end - start;
|
|
|
total_added += size;
|
|
|
ret = btrfs_add_free_space(block_group, start, size);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM or logic error */
|
|
|
}
|
|
|
|
|
|
return total_added;
|
|
@@ -474,7 +474,8 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
|
|
|
int ret = 0;
|
|
|
|
|
|
caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS);
|
|
|
- BUG_ON(!caching_ctl);
|
|
|
+ if (!caching_ctl)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
INIT_LIST_HEAD(&caching_ctl->list);
|
|
|
mutex_init(&caching_ctl->mutex);
|
|
@@ -982,7 +983,7 @@ static int convert_extent_item_v0(struct btrfs_trans_handle *trans,
|
|
|
ret = btrfs_next_leaf(root, path);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
- BUG_ON(ret > 0);
|
|
|
+ BUG_ON(ret > 0); /* Corruption */
|
|
|
leaf = path->nodes[0];
|
|
|
}
|
|
|
btrfs_item_key_to_cpu(leaf, &found_key,
|
|
@@ -1008,7 +1009,7 @@ static int convert_extent_item_v0(struct btrfs_trans_handle *trans,
|
|
|
new_size + extra_size, 1);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* Corruption */
|
|
|
|
|
|
btrfs_extend_item(trans, root, path, new_size);
|
|
|
|
|
@@ -1478,7 +1479,11 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
|
|
|
err = ret;
|
|
|
goto out;
|
|
|
}
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret && !insert) {
|
|
|
+ err = -ENOENT;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ BUG_ON(ret); /* Corruption */
|
|
|
|
|
|
leaf = path->nodes[0];
|
|
|
item_size = btrfs_item_size_nr(leaf, path->slots[0]);
|
|
@@ -1831,6 +1836,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
|
|
|
/* Tell the block device(s) that the sectors can be discarded */
|
|
|
ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD,
|
|
|
bytenr, &num_bytes, &bbio, 0);
|
|
|
+ /* Error condition is -ENOMEM */
|
|
|
if (!ret) {
|
|
|
struct btrfs_bio_stripe *stripe = bbio->stripes;
|
|
|
int i;
|
|
@@ -1846,7 +1852,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
|
|
|
if (!ret)
|
|
|
discarded_bytes += stripe->length;
|
|
|
else if (ret != -EOPNOTSUPP)
|
|
|
- break;
|
|
|
+ break; /* Logic errors or -ENOMEM, or -EIO but I don't know how that could happen JDM */
|
|
|
|
|
|
/*
|
|
|
* Just in case we get back EOPNOTSUPP for some reason,
|
|
@@ -1865,6 +1871,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/* Can return -ENOMEM */
|
|
|
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root,
|
|
|
u64 bytenr, u64 num_bytes, u64 parent,
|
|
@@ -1940,7 +1947,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
|
|
ret = insert_extent_backref(trans, root->fs_info->extent_root,
|
|
|
path, bytenr, parent, root_objectid,
|
|
|
owner, offset, refs_to_add);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret)
|
|
|
+ btrfs_abort_transaction(trans, root, ret);
|
|
|
out:
|
|
|
btrfs_free_path(path);
|
|
|
return err;
|
|
@@ -2027,6 +2035,9 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
|
|
|
int ret;
|
|
|
int err = 0;
|
|
|
|
|
|
+ if (trans->aborted)
|
|
|
+ return 0;
|
|
|
+
|
|
|
path = btrfs_alloc_path();
|
|
|
if (!path)
|
|
|
return -ENOMEM;
|
|
@@ -2124,7 +2135,11 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_delayed_extent_op *extent_op,
|
|
|
int insert_reserved)
|
|
|
{
|
|
|
- int ret;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (trans->aborted)
|
|
|
+ return 0;
|
|
|
+
|
|
|
if (btrfs_delayed_ref_is_head(node)) {
|
|
|
struct btrfs_delayed_ref_head *head;
|
|
|
/*
|
|
@@ -2142,11 +2157,10 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
|
|
|
ret = btrfs_del_csums(trans, root,
|
|
|
node->bytenr,
|
|
|
node->num_bytes);
|
|
|
- BUG_ON(ret);
|
|
|
}
|
|
|
}
|
|
|
mutex_unlock(&head->mutex);
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
if (node->type == BTRFS_TREE_BLOCK_REF_KEY ||
|
|
@@ -2193,6 +2207,10 @@ again:
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Returns 0 on success or if called with an already aborted transaction.
|
|
|
+ * Returns -ENOMEM or -EIO on failure and will abort the transaction.
|
|
|
+ */
|
|
|
static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root,
|
|
|
struct list_head *cluster)
|
|
@@ -2281,9 +2299,13 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
ret = run_delayed_extent_op(trans, root,
|
|
|
ref, extent_op);
|
|
|
- BUG_ON(ret);
|
|
|
kfree(extent_op);
|
|
|
|
|
|
+ if (ret) {
|
|
|
+ printk(KERN_DEBUG "btrfs: run_delayed_extent_op returned %d\n", ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
goto next;
|
|
|
}
|
|
|
|
|
@@ -2304,11 +2326,16 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
ret = run_one_delayed_ref(trans, root, ref, extent_op,
|
|
|
must_insert_reserved);
|
|
|
- BUG_ON(ret);
|
|
|
|
|
|
btrfs_put_delayed_ref(ref);
|
|
|
kfree(extent_op);
|
|
|
count++;
|
|
|
+
|
|
|
+ if (ret) {
|
|
|
+ printk(KERN_DEBUG "btrfs: run_one_delayed_ref returned %d\n", ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
next:
|
|
|
do_chunk_alloc(trans, root->fs_info->extent_root,
|
|
|
2 * 1024 * 1024,
|
|
@@ -2343,6 +2370,9 @@ static void wait_for_more_refs(struct btrfs_delayed_ref_root *delayed_refs,
|
|
|
* 0, which means to process everything in the tree at the start
|
|
|
* of the run (but not newly added entries), or it can be some target
|
|
|
* number you'd like to process.
|
|
|
+ *
|
|
|
+ * Returns 0 on success or if called with an aborted transaction
|
|
|
+ * Returns <0 on error and aborts the transaction
|
|
|
*/
|
|
|
int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root, unsigned long count)
|
|
@@ -2358,6 +2388,10 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
|
|
|
unsigned long num_refs = 0;
|
|
|
int consider_waiting;
|
|
|
|
|
|
+ /* We'll clean this up in btrfs_cleanup_transaction */
|
|
|
+ if (trans->aborted)
|
|
|
+ return 0;
|
|
|
+
|
|
|
if (root == root->fs_info->extent_root)
|
|
|
root = root->fs_info->tree_root;
|
|
|
|
|
@@ -2415,7 +2449,11 @@ again:
|
|
|
}
|
|
|
|
|
|
ret = run_clustered_refs(trans, root, &cluster);
|
|
|
- BUG_ON(ret < 0);
|
|
|
+ if (ret < 0) {
|
|
|
+ spin_unlock(&delayed_refs->lock);
|
|
|
+ btrfs_abort_transaction(trans, root, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
|
|
|
count -= min_t(unsigned long, ret, count);
|
|
|
|
|
@@ -2580,7 +2618,7 @@ static noinline int check_committed_ref(struct btrfs_trans_handle *trans,
|
|
|
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
|
- BUG_ON(ret == 0);
|
|
|
+ BUG_ON(ret == 0); /* Corruption */
|
|
|
|
|
|
ret = -ENOENT;
|
|
|
if (path->slots[0] == 0)
|
|
@@ -2734,7 +2772,6 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
|
|
|
}
|
|
|
return 0;
|
|
|
fail:
|
|
|
- BUG();
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -2763,7 +2800,7 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
|
|
|
ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1);
|
|
|
if (ret < 0)
|
|
|
goto fail;
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* Corruption */
|
|
|
|
|
|
leaf = path->nodes[0];
|
|
|
bi = btrfs_item_ptr_offset(leaf, path->slots[0]);
|
|
@@ -2771,8 +2808,10 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
|
|
|
btrfs_mark_buffer_dirty(leaf);
|
|
|
btrfs_release_path(path);
|
|
|
fail:
|
|
|
- if (ret)
|
|
|
+ if (ret) {
|
|
|
+ btrfs_abort_transaction(trans, root, ret);
|
|
|
return ret;
|
|
|
+ }
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
@@ -2945,7 +2984,8 @@ again:
|
|
|
if (last == 0) {
|
|
|
err = btrfs_run_delayed_refs(trans, root,
|
|
|
(unsigned long)-1);
|
|
|
- BUG_ON(err);
|
|
|
+ if (err) /* File system offline */
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
cache = btrfs_lookup_first_block_group(root->fs_info, last);
|
|
@@ -2972,7 +3012,9 @@ again:
|
|
|
last = cache->key.objectid + cache->key.offset;
|
|
|
|
|
|
err = write_one_cache_group(trans, root, path, cache);
|
|
|
- BUG_ON(err);
|
|
|
+ if (err) /* File system offline */
|
|
|
+ goto out;
|
|
|
+
|
|
|
btrfs_put_block_group(cache);
|
|
|
}
|
|
|
|
|
@@ -2985,7 +3027,8 @@ again:
|
|
|
if (last == 0) {
|
|
|
err = btrfs_run_delayed_refs(trans, root,
|
|
|
(unsigned long)-1);
|
|
|
- BUG_ON(err);
|
|
|
+ if (err) /* File system offline */
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
cache = btrfs_lookup_first_block_group(root->fs_info, last);
|
|
@@ -3010,20 +3053,21 @@ again:
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- btrfs_write_out_cache(root, trans, cache, path);
|
|
|
+ err = btrfs_write_out_cache(root, trans, cache, path);
|
|
|
|
|
|
/*
|
|
|
* If we didn't have an error then the cache state is still
|
|
|
* NEED_WRITE, so we can set it to WRITTEN.
|
|
|
*/
|
|
|
- if (cache->disk_cache_state == BTRFS_DC_NEED_WRITE)
|
|
|
+ if (!err && cache->disk_cache_state == BTRFS_DC_NEED_WRITE)
|
|
|
cache->disk_cache_state = BTRFS_DC_WRITTEN;
|
|
|
last = cache->key.objectid + cache->key.offset;
|
|
|
btrfs_put_block_group(cache);
|
|
|
}
|
|
|
+out:
|
|
|
|
|
|
btrfs_free_path(path);
|
|
|
- return 0;
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr)
|
|
@@ -3407,9 +3451,9 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
|
|
|
if (!space_info) {
|
|
|
ret = update_space_info(extent_root->fs_info, flags,
|
|
|
0, 0, &space_info);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
}
|
|
|
- BUG_ON(!space_info);
|
|
|
+ BUG_ON(!space_info); /* Logic error */
|
|
|
|
|
|
again:
|
|
|
spin_lock(&space_info->lock);
|
|
@@ -3674,8 +3718,10 @@ again:
|
|
|
ret = wait_event_interruptible(space_info->wait,
|
|
|
!space_info->flush);
|
|
|
/* Must have been interrupted, return */
|
|
|
- if (ret)
|
|
|
+ if (ret) {
|
|
|
+ printk(KERN_DEBUG "btrfs: %s returning -EINTR\n", __func__);
|
|
|
return -EINTR;
|
|
|
+ }
|
|
|
|
|
|
spin_lock(&space_info->lock);
|
|
|
}
|
|
@@ -3832,8 +3878,9 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static struct btrfs_block_rsv *get_block_rsv(struct btrfs_trans_handle *trans,
|
|
|
- struct btrfs_root *root)
|
|
|
+static struct btrfs_block_rsv *get_block_rsv(
|
|
|
+ const struct btrfs_trans_handle *trans,
|
|
|
+ const struct btrfs_root *root)
|
|
|
{
|
|
|
struct btrfs_block_rsv *block_rsv = NULL;
|
|
|
|
|
@@ -4200,6 +4247,7 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
|
|
|
trans->bytes_reserved = 0;
|
|
|
}
|
|
|
|
|
|
+/* Can only return 0 or -ENOSPC */
|
|
|
int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
|
|
|
struct inode *inode)
|
|
|
{
|
|
@@ -4536,7 +4584,7 @@ static int update_block_group(struct btrfs_trans_handle *trans,
|
|
|
while (total) {
|
|
|
cache = btrfs_lookup_block_group(info, bytenr);
|
|
|
if (!cache)
|
|
|
- return -1;
|
|
|
+ return -ENOENT;
|
|
|
if (cache->flags & (BTRFS_BLOCK_GROUP_DUP |
|
|
|
BTRFS_BLOCK_GROUP_RAID1 |
|
|
|
BTRFS_BLOCK_GROUP_RAID10))
|
|
@@ -4639,7 +4687,7 @@ int btrfs_pin_extent(struct btrfs_root *root,
|
|
|
struct btrfs_block_group_cache *cache;
|
|
|
|
|
|
cache = btrfs_lookup_block_group(root->fs_info, bytenr);
|
|
|
- BUG_ON(!cache);
|
|
|
+ BUG_ON(!cache); /* Logic error */
|
|
|
|
|
|
pin_down_extent(root, cache, bytenr, num_bytes, reserved);
|
|
|
|
|
@@ -4657,7 +4705,7 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_block_group_cache *cache;
|
|
|
|
|
|
cache = btrfs_lookup_block_group(root->fs_info, bytenr);
|
|
|
- BUG_ON(!cache);
|
|
|
+ BUG_ON(!cache); /* Logic error */
|
|
|
|
|
|
/*
|
|
|
* pull in the free space cache (if any) so that our pin
|
|
@@ -4702,6 +4750,7 @@ static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache,
|
|
|
{
|
|
|
struct btrfs_space_info *space_info = cache->space_info;
|
|
|
int ret = 0;
|
|
|
+
|
|
|
spin_lock(&space_info->lock);
|
|
|
spin_lock(&cache->lock);
|
|
|
if (reserve != RESERVE_FREE) {
|
|
@@ -4774,7 +4823,7 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
|
|
|
if (cache)
|
|
|
btrfs_put_block_group(cache);
|
|
|
cache = btrfs_lookup_block_group(fs_info, start);
|
|
|
- BUG_ON(!cache);
|
|
|
+ BUG_ON(!cache); /* Logic error */
|
|
|
}
|
|
|
|
|
|
len = cache->key.objectid + cache->key.offset - start;
|
|
@@ -4811,6 +4860,9 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
|
|
|
u64 end;
|
|
|
int ret;
|
|
|
|
|
|
+ if (trans->aborted)
|
|
|
+ return 0;
|
|
|
+
|
|
|
if (fs_info->pinned_extents == &fs_info->freed_extents[0])
|
|
|
unpin = &fs_info->freed_extents[1];
|
|
|
else
|
|
@@ -4896,7 +4948,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
|
|
ret = remove_extent_backref(trans, extent_root, path,
|
|
|
NULL, refs_to_drop,
|
|
|
is_data);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret)
|
|
|
+ goto abort;
|
|
|
btrfs_release_path(path);
|
|
|
path->leave_spinning = 1;
|
|
|
|
|
@@ -4914,10 +4967,11 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
|
|
btrfs_print_leaf(extent_root,
|
|
|
path->nodes[0]);
|
|
|
}
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret < 0)
|
|
|
+ goto abort;
|
|
|
extent_slot = path->slots[0];
|
|
|
}
|
|
|
- } else {
|
|
|
+ } else if (ret == -ENOENT) {
|
|
|
btrfs_print_leaf(extent_root, path->nodes[0]);
|
|
|
WARN_ON(1);
|
|
|
printk(KERN_ERR "btrfs unable to find ref byte nr %llu "
|
|
@@ -4927,6 +4981,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
|
|
(unsigned long long)root_objectid,
|
|
|
(unsigned long long)owner_objectid,
|
|
|
(unsigned long long)owner_offset);
|
|
|
+ } else {
|
|
|
+ goto abort;
|
|
|
}
|
|
|
|
|
|
leaf = path->nodes[0];
|
|
@@ -4936,7 +4992,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
|
|
BUG_ON(found_extent || extent_slot != path->slots[0]);
|
|
|
ret = convert_extent_item_v0(trans, extent_root, path,
|
|
|
owner_objectid, 0);
|
|
|
- BUG_ON(ret < 0);
|
|
|
+ if (ret < 0)
|
|
|
+ goto abort;
|
|
|
|
|
|
btrfs_release_path(path);
|
|
|
path->leave_spinning = 1;
|
|
@@ -4953,7 +5010,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
|
|
(unsigned long long)bytenr);
|
|
|
btrfs_print_leaf(extent_root, path->nodes[0]);
|
|
|
}
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret < 0)
|
|
|
+ goto abort;
|
|
|
extent_slot = path->slots[0];
|
|
|
leaf = path->nodes[0];
|
|
|
item_size = btrfs_item_size_nr(leaf, extent_slot);
|
|
@@ -4990,7 +5048,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
|
|
ret = remove_extent_backref(trans, extent_root, path,
|
|
|
iref, refs_to_drop,
|
|
|
is_data);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret)
|
|
|
+ goto abort;
|
|
|
}
|
|
|
} else {
|
|
|
if (found_extent) {
|
|
@@ -5007,12 +5066,14 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
|
|
|
num_to_del);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret)
|
|
|
+ goto abort;
|
|
|
btrfs_release_path(path);
|
|
|
|
|
|
if (is_data) {
|
|
|
ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret)
|
|
|
+ goto abort;
|
|
|
} else {
|
|
|
invalidate_mapping_pages(info->btree_inode->i_mapping,
|
|
|
bytenr >> PAGE_CACHE_SHIFT,
|
|
@@ -5020,10 +5081,16 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
|
|
}
|
|
|
|
|
|
ret = update_block_group(trans, root, bytenr, num_bytes, 0);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret)
|
|
|
+ goto abort;
|
|
|
}
|
|
|
+out:
|
|
|
btrfs_free_path(path);
|
|
|
return ret;
|
|
|
+
|
|
|
+abort:
|
|
|
+ btrfs_abort_transaction(trans, extent_root, ret);
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -5119,7 +5186,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
|
|
parent, root->root_key.objectid,
|
|
|
btrfs_header_level(buf),
|
|
|
BTRFS_DROP_DELAYED_REF, NULL, for_cow);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
}
|
|
|
|
|
|
if (!last_ref)
|
|
@@ -5153,6 +5220,7 @@ out:
|
|
|
btrfs_put_block_group(cache);
|
|
|
}
|
|
|
|
|
|
+/* Can return -ENOMEM */
|
|
|
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|
|
u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid,
|
|
|
u64 owner, u64 offset, int for_cow)
|
|
@@ -5174,14 +5242,12 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|
|
num_bytes,
|
|
|
parent, root_objectid, (int)owner,
|
|
|
BTRFS_DROP_DELAYED_REF, NULL, for_cow);
|
|
|
- BUG_ON(ret);
|
|
|
} else {
|
|
|
ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
|
|
|
num_bytes,
|
|
|
parent, root_objectid, owner,
|
|
|
offset, BTRFS_DROP_DELAYED_REF,
|
|
|
NULL, for_cow);
|
|
|
- BUG_ON(ret);
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
@@ -5418,6 +5484,7 @@ have_block_group:
|
|
|
found_uncached_bg = true;
|
|
|
ret = cache_block_group(block_group, trans,
|
|
|
orig_root, 1);
|
|
|
+ BUG_ON(ret < 0); /* -ENOMEM */
|
|
|
if (block_group->cached == BTRFS_CACHE_FINISHED)
|
|
|
goto alloc;
|
|
|
|
|
@@ -5439,7 +5506,7 @@ have_block_group:
|
|
|
if (loop > LOOP_FIND_IDEAL) {
|
|
|
ret = cache_block_group(block_group, trans,
|
|
|
orig_root, 0);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -5712,6 +5779,11 @@ loop:
|
|
|
ret = do_chunk_alloc(trans, root, num_bytes +
|
|
|
2 * 1024 * 1024, data,
|
|
|
CHUNK_ALLOC_LIMITED);
|
|
|
+ if (ret < 0) {
|
|
|
+ btrfs_abort_transaction(trans,
|
|
|
+ root, ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
allowed_chunk_alloc = 0;
|
|
|
if (ret == 1)
|
|
|
done_chunk_alloc = 1;
|
|
@@ -5740,6 +5812,7 @@ loop:
|
|
|
} else if (ins->objectid) {
|
|
|
ret = 0;
|
|
|
}
|
|
|
+out:
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -5806,10 +5879,15 @@ again:
|
|
|
* the only place that sets empty_size is btrfs_realloc_node, which
|
|
|
* is not called recursively on allocations
|
|
|
*/
|
|
|
- if (empty_size || root->ref_cows)
|
|
|
+ if (empty_size || root->ref_cows) {
|
|
|
ret = do_chunk_alloc(trans, root->fs_info->extent_root,
|
|
|
num_bytes + 2 * 1024 * 1024, data,
|
|
|
CHUNK_ALLOC_NO_FORCE);
|
|
|
+ if (ret < 0 && ret != -ENOSPC) {
|
|
|
+ btrfs_abort_transaction(trans, root, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
WARN_ON(num_bytes < root->sectorsize);
|
|
|
ret = find_free_extent(trans, root, num_bytes, empty_size,
|
|
@@ -5821,8 +5899,12 @@ again:
|
|
|
num_bytes = num_bytes >> 1;
|
|
|
num_bytes = num_bytes & ~(root->sectorsize - 1);
|
|
|
num_bytes = max(num_bytes, min_alloc_size);
|
|
|
- do_chunk_alloc(trans, root->fs_info->extent_root,
|
|
|
+ ret = do_chunk_alloc(trans, root->fs_info->extent_root,
|
|
|
num_bytes, data, CHUNK_ALLOC_FORCE);
|
|
|
+ if (ret < 0 && ret != -ENOSPC) {
|
|
|
+ btrfs_abort_transaction(trans, root, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
if (num_bytes == min_alloc_size)
|
|
|
final_tried = true;
|
|
|
goto again;
|
|
@@ -5913,7 +5995,10 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
|
|
|
path->leave_spinning = 1;
|
|
|
ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
|
|
|
ins, size);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret) {
|
|
|
+ btrfs_free_path(path);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
|
|
|
leaf = path->nodes[0];
|
|
|
extent_item = btrfs_item_ptr(leaf, path->slots[0],
|
|
@@ -5943,7 +6028,7 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
|
|
|
btrfs_free_path(path);
|
|
|
|
|
|
ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
|
|
|
- if (ret) {
|
|
|
+ if (ret) { /* -ENOENT, logic error */
|
|
|
printk(KERN_ERR "btrfs update block group failed for %llu "
|
|
|
"%llu\n", (unsigned long long)ins->objectid,
|
|
|
(unsigned long long)ins->offset);
|
|
@@ -5974,7 +6059,10 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
|
|
|
path->leave_spinning = 1;
|
|
|
ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
|
|
|
ins, size);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret) {
|
|
|
+ btrfs_free_path(path);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
|
|
|
leaf = path->nodes[0];
|
|
|
extent_item = btrfs_item_ptr(leaf, path->slots[0],
|
|
@@ -6004,7 +6092,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
|
|
|
btrfs_free_path(path);
|
|
|
|
|
|
ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
|
|
|
- if (ret) {
|
|
|
+ if (ret) { /* -ENOENT, logic error */
|
|
|
printk(KERN_ERR "btrfs update block group failed for %llu "
|
|
|
"%llu\n", (unsigned long long)ins->objectid,
|
|
|
(unsigned long long)ins->offset);
|
|
@@ -6052,28 +6140,28 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
|
|
|
if (!caching_ctl) {
|
|
|
BUG_ON(!block_group_cache_done(block_group));
|
|
|
ret = btrfs_remove_free_space(block_group, start, num_bytes);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
} else {
|
|
|
mutex_lock(&caching_ctl->mutex);
|
|
|
|
|
|
if (start >= caching_ctl->progress) {
|
|
|
ret = add_excluded_extent(root, start, num_bytes);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
} else if (start + num_bytes <= caching_ctl->progress) {
|
|
|
ret = btrfs_remove_free_space(block_group,
|
|
|
start, num_bytes);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
} else {
|
|
|
num_bytes = caching_ctl->progress - start;
|
|
|
ret = btrfs_remove_free_space(block_group,
|
|
|
start, num_bytes);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
|
|
|
start = caching_ctl->progress;
|
|
|
num_bytes = ins->objectid + ins->offset -
|
|
|
caching_ctl->progress;
|
|
|
ret = add_excluded_extent(root, start, num_bytes);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
}
|
|
|
|
|
|
mutex_unlock(&caching_ctl->mutex);
|
|
@@ -6082,7 +6170,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
ret = btrfs_update_reserved_bytes(block_group, ins->offset,
|
|
|
RESERVE_ALLOC_NO_ACCOUNT);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* logic error */
|
|
|
btrfs_put_block_group(block_group);
|
|
|
ret = alloc_reserved_file_extent(trans, root, 0, root_objectid,
|
|
|
0, owner, offset, ins, 1);
|
|
@@ -6218,7 +6306,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
buf = btrfs_init_new_buffer(trans, root, ins.objectid,
|
|
|
blocksize, level);
|
|
|
- BUG_ON(IS_ERR(buf));
|
|
|
+ BUG_ON(IS_ERR(buf)); /* -ENOMEM */
|
|
|
|
|
|
if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
|
|
|
if (parent == 0)
|
|
@@ -6230,7 +6318,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
|
|
if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
|
|
|
struct btrfs_delayed_extent_op *extent_op;
|
|
|
extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
|
|
|
- BUG_ON(!extent_op);
|
|
|
+ BUG_ON(!extent_op); /* -ENOMEM */
|
|
|
if (key)
|
|
|
memcpy(&extent_op->key, key, sizeof(extent_op->key));
|
|
|
else
|
|
@@ -6245,7 +6333,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
|
|
ins.offset, parent, root_objectid,
|
|
|
level, BTRFS_ADD_DELAYED_EXTENT,
|
|
|
extent_op, for_cow);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
}
|
|
|
return buf;
|
|
|
}
|
|
@@ -6315,7 +6403,9 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
|
|
|
/* We don't lock the tree block, it's OK to be racy here */
|
|
|
ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
|
|
|
&refs, &flags);
|
|
|
- BUG_ON(ret);
|
|
|
+ /* We don't care about errors in readahead. */
|
|
|
+ if (ret < 0)
|
|
|
+ continue;
|
|
|
BUG_ON(refs == 0);
|
|
|
|
|
|
if (wc->stage == DROP_REFERENCE) {
|
|
@@ -6382,7 +6472,9 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
|
|
|
eb->start, eb->len,
|
|
|
&wc->refs[level],
|
|
|
&wc->flags[level]);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret == -ENOMEM);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
BUG_ON(wc->refs[level] == 0);
|
|
|
}
|
|
|
|
|
@@ -6401,12 +6493,12 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
|
|
|
if (!(wc->flags[level] & flag)) {
|
|
|
BUG_ON(!path->locks[level]);
|
|
|
ret = btrfs_inc_ref(trans, root, eb, 1, wc->for_reloc);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
ret = btrfs_dec_ref(trans, root, eb, 0, wc->for_reloc);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
ret = btrfs_set_disk_extent_flags(trans, root, eb->start,
|
|
|
eb->len, flag, 0);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
wc->flags[level] |= flag;
|
|
|
}
|
|
|
|
|
@@ -6478,7 +6570,11 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
|
|
|
ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
|
|
|
&wc->refs[level - 1],
|
|
|
&wc->flags[level - 1]);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret < 0) {
|
|
|
+ btrfs_tree_unlock(next);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
BUG_ON(wc->refs[level - 1] == 0);
|
|
|
*lookup_info = 0;
|
|
|
|
|
@@ -6547,7 +6643,7 @@ skip:
|
|
|
|
|
|
ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
|
|
|
root->root_key.objectid, level - 1, 0, 0);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
}
|
|
|
btrfs_tree_unlock(next);
|
|
|
free_extent_buffer(next);
|
|
@@ -6605,7 +6701,10 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
|
|
|
eb->start, eb->len,
|
|
|
&wc->refs[level],
|
|
|
&wc->flags[level]);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret < 0) {
|
|
|
+ btrfs_tree_unlock_rw(eb, path->locks[level]);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
BUG_ON(wc->refs[level] == 0);
|
|
|
if (wc->refs[level] == 1) {
|
|
|
btrfs_tree_unlock_rw(eb, path->locks[level]);
|
|
@@ -6625,7 +6724,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
|
|
|
else
|
|
|
ret = btrfs_dec_ref(trans, root, eb, 0,
|
|
|
wc->for_reloc);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
}
|
|
|
/* make block locked assertion in clean_tree_block happy */
|
|
|
if (!path->locks[level] &&
|
|
@@ -6762,7 +6861,10 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
|
|
}
|
|
|
|
|
|
trans = btrfs_start_transaction(tree_root, 0);
|
|
|
- BUG_ON(IS_ERR(trans));
|
|
|
+ if (IS_ERR(trans)) {
|
|
|
+ err = PTR_ERR(trans);
|
|
|
+ goto out_free;
|
|
|
+ }
|
|
|
|
|
|
if (block_rsv)
|
|
|
trans->block_rsv = block_rsv;
|
|
@@ -6787,7 +6889,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
|
|
path->lowest_level = 0;
|
|
|
if (ret < 0) {
|
|
|
err = ret;
|
|
|
- goto out_free;
|
|
|
+ goto out_end_trans;
|
|
|
}
|
|
|
WARN_ON(ret > 0);
|
|
|
|
|
@@ -6807,7 +6909,10 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
|
|
path->nodes[level]->len,
|
|
|
&wc->refs[level],
|
|
|
&wc->flags[level]);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret < 0) {
|
|
|
+ err = ret;
|
|
|
+ goto out_end_trans;
|
|
|
+ }
|
|
|
BUG_ON(wc->refs[level] == 0);
|
|
|
|
|
|
if (level == root_item->drop_level)
|
|
@@ -6858,26 +6963,40 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
|
|
ret = btrfs_update_root(trans, tree_root,
|
|
|
&root->root_key,
|
|
|
root_item);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret) {
|
|
|
+ btrfs_abort_transaction(trans, tree_root, ret);
|
|
|
+ err = ret;
|
|
|
+ goto out_end_trans;
|
|
|
+ }
|
|
|
|
|
|
btrfs_end_transaction_throttle(trans, tree_root);
|
|
|
trans = btrfs_start_transaction(tree_root, 0);
|
|
|
- BUG_ON(IS_ERR(trans));
|
|
|
+ if (IS_ERR(trans)) {
|
|
|
+ err = PTR_ERR(trans);
|
|
|
+ goto out_free;
|
|
|
+ }
|
|
|
if (block_rsv)
|
|
|
trans->block_rsv = block_rsv;
|
|
|
}
|
|
|
}
|
|
|
btrfs_release_path(path);
|
|
|
- BUG_ON(err);
|
|
|
+ if (err)
|
|
|
+ goto out_end_trans;
|
|
|
|
|
|
ret = btrfs_del_root(trans, tree_root, &root->root_key);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret) {
|
|
|
+ btrfs_abort_transaction(trans, tree_root, ret);
|
|
|
+ goto out_end_trans;
|
|
|
+ }
|
|
|
|
|
|
if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
|
|
|
ret = btrfs_find_last_root(tree_root, root->root_key.objectid,
|
|
|
NULL, NULL);
|
|
|
- BUG_ON(ret < 0);
|
|
|
- if (ret > 0) {
|
|
|
+ if (ret < 0) {
|
|
|
+ btrfs_abort_transaction(trans, tree_root, ret);
|
|
|
+ err = ret;
|
|
|
+ goto out_end_trans;
|
|
|
+ } else if (ret > 0) {
|
|
|
/* if we fail to delete the orphan item this time
|
|
|
* around, it'll get picked up the next time.
|
|
|
*
|
|
@@ -6895,8 +7014,9 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
|
|
free_extent_buffer(root->commit_root);
|
|
|
kfree(root);
|
|
|
}
|
|
|
-out_free:
|
|
|
+out_end_trans:
|
|
|
btrfs_end_transaction_throttle(trans, tree_root);
|
|
|
+out_free:
|
|
|
kfree(wc);
|
|
|
btrfs_free_path(path);
|
|
|
out:
|
|
@@ -7099,12 +7219,16 @@ int btrfs_set_block_group_ro(struct btrfs_root *root,
|
|
|
BUG_ON(cache->ro);
|
|
|
|
|
|
trans = btrfs_join_transaction(root);
|
|
|
- BUG_ON(IS_ERR(trans));
|
|
|
+ if (IS_ERR(trans))
|
|
|
+ return PTR_ERR(trans);
|
|
|
|
|
|
alloc_flags = update_block_group_flags(root, cache->flags);
|
|
|
- if (alloc_flags != cache->flags)
|
|
|
- do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
|
|
|
- CHUNK_ALLOC_FORCE);
|
|
|
+ if (alloc_flags != cache->flags) {
|
|
|
+ ret = do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
|
|
|
+ CHUNK_ALLOC_FORCE);
|
|
|
+ if (ret < 0)
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
ret = set_block_group_ro(cache, 0);
|
|
|
if (!ret)
|
|
@@ -7567,7 +7691,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
|
|
ret = update_space_info(info, cache->flags, found_key.offset,
|
|
|
btrfs_block_group_used(&cache->item),
|
|
|
&space_info);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
cache->space_info = space_info;
|
|
|
spin_lock(&cache->space_info->lock);
|
|
|
cache->space_info->bytes_readonly += cache->bytes_super;
|
|
@@ -7576,7 +7700,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
|
|
__link_block_group(space_info, cache);
|
|
|
|
|
|
ret = btrfs_add_block_group_cache(root->fs_info, cache);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* Logic error */
|
|
|
|
|
|
set_avail_alloc_bits(root->fs_info, cache->flags);
|
|
|
if (btrfs_chunk_readonly(root, cache->key.objectid))
|
|
@@ -7658,7 +7782,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
ret = update_space_info(root->fs_info, cache->flags, size, bytes_used,
|
|
|
&cache->space_info);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* -ENOMEM */
|
|
|
update_global_block_rsv(root->fs_info);
|
|
|
|
|
|
spin_lock(&cache->space_info->lock);
|
|
@@ -7668,11 +7792,14 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
|
|
|
__link_block_group(cache->space_info, cache);
|
|
|
|
|
|
ret = btrfs_add_block_group_cache(root->fs_info, cache);
|
|
|
- BUG_ON(ret);
|
|
|
+ BUG_ON(ret); /* Logic error */
|
|
|
|
|
|
ret = btrfs_insert_item(trans, extent_root, &cache->key, &cache->item,
|
|
|
sizeof(cache->item));
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret) {
|
|
|
+ btrfs_abort_transaction(trans, extent_root, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
|
|
|
set_avail_alloc_bits(extent_root->fs_info, type);
|
|
|
|
|
@@ -7753,7 +7880,10 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
|
|
|
inode = lookup_free_space_inode(tree_root, block_group, path);
|
|
|
if (!IS_ERR(inode)) {
|
|
|
ret = btrfs_orphan_add(trans, inode);
|
|
|
- BUG_ON(ret);
|
|
|
+ if (ret) {
|
|
|
+ btrfs_add_delayed_iput(inode);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
clear_nlink(inode);
|
|
|
/* One for the block groups ref */
|
|
|
spin_lock(&block_group->lock);
|