Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+28 −13
Original line number Original line Diff line number Diff line
@@ -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 {