Skip to content

Commit 67b7859

Browse files
osandovmasoncl
authored andcommitted
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>
1 parent 1b98450 commit 67b7859

File tree

1 file changed

+28
-13
lines changed

1 file changed

+28
-13
lines changed

fs/btrfs/extent-tree.c

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7546,7 +7546,7 @@ static void unuse_block_rsv(struct btrfs_fs_info *fs_info,
75467546
* returns the key for the extent through ins, and a tree buffer for
75477547
* the first block of the extent through buf.
75487548
*
7549-
* returns the tree buffer or NULL.
7549+
* returns the tree buffer or an ERR_PTR on error.
75507550
*/
75517551
struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
75527552
struct btrfs_root *root,
@@ -7557,6 +7557,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
75577557
struct btrfs_key ins;
75587558
struct btrfs_block_rsv *block_rsv;
75597559
struct extent_buffer *buf;
7560+
struct btrfs_delayed_extent_op *extent_op;
75607561
u64 flags = 0;
75617562
int ret;
75627563
u32 blocksize = root->nodesize;
@@ -7577,13 +7578,14 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
75777578

75787579
ret = btrfs_reserve_extent(root, blocksize, blocksize,
75797580
empty_size, hint, &ins, 0, 0);
7580-
if (ret) {
7581-
unuse_block_rsv(root->fs_info, block_rsv, blocksize);
7582-
return ERR_PTR(ret);
7583-
}
7581+
if (ret)
7582+
goto out_unuse;
75847583

75857584
buf = btrfs_init_new_buffer(trans, root, ins.objectid, level);
7586-
BUG_ON(IS_ERR(buf)); /* -ENOMEM */
7585+
if (IS_ERR(buf)) {
7586+
ret = PTR_ERR(buf);
7587+
goto out_free_reserved;
7588+
}
75877589

75887590
if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
75897591
if (parent == 0)
@@ -7593,9 +7595,11 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
75937595
BUG_ON(parent > 0);
75947596

75957597
if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
7596-
struct btrfs_delayed_extent_op *extent_op;
75977598
extent_op = btrfs_alloc_delayed_extent_op();
7598-
BUG_ON(!extent_op); /* -ENOMEM */
7599+
if (!extent_op) {
7600+
ret = -ENOMEM;
7601+
goto out_free_buf;
7602+
}
75997603
if (key)
76007604
memcpy(&extent_op->key, key, sizeof(extent_op->key));
76017605
else
@@ -7610,13 +7614,24 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
76107614
extent_op->level = level;
76117615

76127616
ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
7613-
ins.objectid,
7614-
ins.offset, parent, root_objectid,
7615-
level, BTRFS_ADD_DELAYED_EXTENT,
7616-
extent_op, 0);
7617-
BUG_ON(ret); /* -ENOMEM */
7617+
ins.objectid, ins.offset,
7618+
parent, root_objectid, level,
7619+
BTRFS_ADD_DELAYED_EXTENT,
7620+
extent_op, 0);
7621+
if (ret)
7622+
goto out_free_delayed;
76187623
}
76197624
return buf;
7625+
7626+
out_free_delayed:
7627+
btrfs_free_delayed_extent_op(extent_op);
7628+
out_free_buf:
7629+
free_extent_buffer(buf);
7630+
out_free_reserved:
7631+
btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 0);
7632+
out_unuse:
7633+
unuse_block_rsv(root->fs_info, block_rsv, blocksize);
7634+
return ERR_PTR(ret);
76207635
}
76217636

76227637
struct walk_control {

0 commit comments

Comments
 (0)