Commit 67b7859e authored by Omar Sandoval's avatar Omar Sandoval Committed by Chris Mason

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: default avatarOmar Sandoval <osandov@osandov.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.cz>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent 1b984508
...@@ -7546,7 +7546,7 @@ static void unuse_block_rsv(struct btrfs_fs_info *fs_info, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment