btrfs: handle ENOMEM in btrfs_alloc_tree_block
This is one of the first places to give out when memory is tight. Handle it properly rather than with a BUG_ON. Also fix the comment about the return value, which is an ERR_PTR, not NULL, on error. Signed-off-by: Omar Sandoval <osandov@osandov.com> Reviewed-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
parent
1b98450816
commit
67b7859e9b
|
@ -7546,7 +7546,7 @@ static void unuse_block_rsv(struct btrfs_fs_info *fs_info,
|
||||||
* returns the key for the extent through ins, and a tree buffer for
|
* returns the key for the extent through ins, and a tree buffer for
|
||||||
* the first block of the extent through buf.
|
* the first block of the extent through buf.
|
||||||
*
|
*
|
||||||
* returns the tree buffer or NULL.
|
* returns the tree buffer or an ERR_PTR on error.
|
||||||
*/
|
*/
|
||||||
struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
|
struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
|
@ -7557,6 +7557,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_key ins;
|
struct btrfs_key ins;
|
||||||
struct btrfs_block_rsv *block_rsv;
|
struct btrfs_block_rsv *block_rsv;
|
||||||
struct extent_buffer *buf;
|
struct extent_buffer *buf;
|
||||||
|
struct btrfs_delayed_extent_op *extent_op;
|
||||||
u64 flags = 0;
|
u64 flags = 0;
|
||||||
int ret;
|
int ret;
|
||||||
u32 blocksize = root->nodesize;
|
u32 blocksize = root->nodesize;
|
||||||
|
@ -7577,13 +7578,14 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
ret = btrfs_reserve_extent(root, blocksize, blocksize,
|
ret = btrfs_reserve_extent(root, blocksize, blocksize,
|
||||||
empty_size, hint, &ins, 0, 0);
|
empty_size, hint, &ins, 0, 0);
|
||||||
if (ret) {
|
if (ret)
|
||||||
unuse_block_rsv(root->fs_info, block_rsv, blocksize);
|
goto out_unuse;
|
||||||
return ERR_PTR(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = btrfs_init_new_buffer(trans, root, ins.objectid, level);
|
buf = btrfs_init_new_buffer(trans, root, ins.objectid, level);
|
||||||
BUG_ON(IS_ERR(buf)); /* -ENOMEM */
|
if (IS_ERR(buf)) {
|
||||||
|
ret = PTR_ERR(buf);
|
||||||
|
goto out_free_reserved;
|
||||||
|
}
|
||||||
|
|
||||||
if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
|
if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
|
||||||
if (parent == 0)
|
if (parent == 0)
|
||||||
|
@ -7593,9 +7595,11 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
|
||||||
BUG_ON(parent > 0);
|
BUG_ON(parent > 0);
|
||||||
|
|
||||||
if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
|
if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
|
||||||
struct btrfs_delayed_extent_op *extent_op;
|
|
||||||
extent_op = btrfs_alloc_delayed_extent_op();
|
extent_op = btrfs_alloc_delayed_extent_op();
|
||||||
BUG_ON(!extent_op); /* -ENOMEM */
|
if (!extent_op) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_free_buf;
|
||||||
|
}
|
||||||
if (key)
|
if (key)
|
||||||
memcpy(&extent_op->key, key, sizeof(extent_op->key));
|
memcpy(&extent_op->key, key, sizeof(extent_op->key));
|
||||||
else
|
else
|
||||||
|
@ -7610,13 +7614,24 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
|
||||||
extent_op->level = level;
|
extent_op->level = level;
|
||||||
|
|
||||||
ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
|
ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
|
||||||
ins.objectid,
|
ins.objectid, ins.offset,
|
||||||
ins.offset, parent, root_objectid,
|
parent, root_objectid, level,
|
||||||
level, BTRFS_ADD_DELAYED_EXTENT,
|
BTRFS_ADD_DELAYED_EXTENT,
|
||||||
extent_op, 0);
|
extent_op, 0);
|
||||||
BUG_ON(ret); /* -ENOMEM */
|
if (ret)
|
||||||
|
goto out_free_delayed;
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
|
|
||||||
|
out_free_delayed:
|
||||||
|
btrfs_free_delayed_extent_op(extent_op);
|
||||||
|
out_free_buf:
|
||||||
|
free_extent_buffer(buf);
|
||||||
|
out_free_reserved:
|
||||||
|
btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 0);
|
||||||
|
out_unuse:
|
||||||
|
unuse_block_rsv(root->fs_info, block_rsv, blocksize);
|
||||||
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct walk_control {
|
struct walk_control {
|
||||||
|
|
Loading…
Reference in a new issue