aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorOmar Sandoval <osandov@osandov.com>2015-02-24 05:47:04 -0500
committerChris Mason <clm@fb.com>2015-04-26 09:27:00 -0400
commit67b7859e9bfa0dcee5a8256932e393e98739be1b (patch)
tree97cc477d3597187e4aa4e450ba74e06f7eda4f35 /fs/btrfs
parent1b9845081633072c18f30d8cfd09c267adf0b109 (diff)
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>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/extent-tree.c41
1 files changed, 28 insertions, 13 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 6f420c8efdaf..0ec8e228b89f 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -7546,7 +7546,7 @@ static void unuse_block_rsv(struct btrfs_fs_info *fs_info,
7546 * returns the key for the extent through ins, and a tree buffer for 7546 * returns the key for the extent through ins, and a tree buffer for
7547 * the first block of the extent through buf. 7547 * the first block of the extent through buf.
7548 * 7548 *
7549 * returns the tree buffer or NULL. 7549 * returns the tree buffer or an ERR_PTR on error.
7550 */ 7550 */
7551struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, 7551struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
7552 struct btrfs_root *root, 7552 struct btrfs_root *root,
@@ -7557,6 +7557,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
7557 struct btrfs_key ins; 7557 struct btrfs_key ins;
7558 struct btrfs_block_rsv *block_rsv; 7558 struct btrfs_block_rsv *block_rsv;
7559 struct extent_buffer *buf; 7559 struct extent_buffer *buf;
7560 struct btrfs_delayed_extent_op *extent_op;
7560 u64 flags = 0; 7561 u64 flags = 0;
7561 int ret; 7562 int ret;
7562 u32 blocksize = root->nodesize; 7563 u32 blocksize = root->nodesize;
@@ -7577,13 +7578,14 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
7577 7578
7578 ret = btrfs_reserve_extent(root, blocksize, blocksize, 7579 ret = btrfs_reserve_extent(root, blocksize, blocksize,
7579 empty_size, hint, &ins, 0, 0); 7580 empty_size, hint, &ins, 0, 0);
7580 if (ret) { 7581 if (ret)
7581 unuse_block_rsv(root->fs_info, block_rsv, blocksize); 7582 goto out_unuse;
7582 return ERR_PTR(ret);
7583 }
7584 7583
7585 buf = btrfs_init_new_buffer(trans, root, ins.objectid, level); 7584 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 }
7587 7589
7588 if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) { 7590 if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
7589 if (parent == 0) 7591 if (parent == 0)
@@ -7593,9 +7595,11 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
7593 BUG_ON(parent > 0); 7595 BUG_ON(parent > 0);
7594 7596
7595 if (root_objectid != BTRFS_TREE_LOG_OBJECTID) { 7597 if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
7596 struct btrfs_delayed_extent_op *extent_op;
7597 extent_op = btrfs_alloc_delayed_extent_op(); 7598 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 }
7599 if (key) 7603 if (key)
7600 memcpy(&extent_op->key, key, sizeof(extent_op->key)); 7604 memcpy(&extent_op->key, key, sizeof(extent_op->key));
7601 else 7605 else
@@ -7610,13 +7614,24 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
7610 extent_op->level = level; 7614 extent_op->level = level;
7611 7615
7612 ret = btrfs_add_delayed_tree_ref(root->fs_info, trans, 7616 ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
7613 ins.objectid, 7617 ins.objectid, ins.offset,
7614 ins.offset, parent, root_objectid, 7618 parent, root_objectid, level,
7615 level, BTRFS_ADD_DELAYED_EXTENT, 7619 BTRFS_ADD_DELAYED_EXTENT,
7616 extent_op, 0); 7620 extent_op, 0);
7617 BUG_ON(ret); /* -ENOMEM */ 7621 if (ret)
7622 goto out_free_delayed;
7618 } 7623 }
7619 return buf; 7624 return buf;
7625
7626out_free_delayed:
7627 btrfs_free_delayed_extent_op(extent_op);
7628out_free_buf:
7629 free_extent_buffer(buf);
7630out_free_reserved:
7631 btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 0);
7632out_unuse:
7633 unuse_block_rsv(root->fs_info, block_rsv, blocksize);
7634 return ERR_PTR(ret);
7620} 7635}
7621 7636
7622struct walk_control { 7637struct walk_control {