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

Commit 04487488 authored by Josef Bacik's avatar Josef Bacik
Browse files

Btrfs: fix chunk allocation error handling



If we error out allocating a dev extent we will have already created the
block group and such which will cause problems since the allocator may have
tried to allocate out of the block group that no longer exists.  This will
cause BUG_ON()'s in the bio submission path.  This also makes a failure to
allocate a dev extent a non-abort error, we will just clean up the dev
extents we did allocate and exit.  Now if we fail to delete the dev extents
we will abort since we can't have half of the dev extents hanging around,
but this will make us much less likely to abort.  Thanks,

Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
parent 87533c47
Loading
Loading
Loading
Loading
+22 −10
Original line number Original line Diff line number Diff line
@@ -3825,12 +3825,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
	if (ret)
	if (ret)
		goto error;
		goto error;


	ret = btrfs_make_block_group(trans, extent_root, 0, type,
				     BTRFS_FIRST_CHUNK_TREE_OBJECTID,
				     start, num_bytes);
	if (ret)
		goto error;

	for (i = 0; i < map->num_stripes; ++i) {
	for (i = 0; i < map->num_stripes; ++i) {
		struct btrfs_device *device;
		struct btrfs_device *device;
		u64 dev_offset;
		u64 dev_offset;
@@ -3842,15 +3836,33 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
				info->chunk_root->root_key.objectid,
				info->chunk_root->root_key.objectid,
				BTRFS_FIRST_CHUNK_TREE_OBJECTID,
				BTRFS_FIRST_CHUNK_TREE_OBJECTID,
				start, dev_offset, stripe_size);
				start, dev_offset, stripe_size);
		if (ret) {
		if (ret)
			btrfs_abort_transaction(trans, extent_root, ret);
			goto error_dev_extent;
			goto error;
	}
	}

	ret = btrfs_make_block_group(trans, extent_root, 0, type,
				     BTRFS_FIRST_CHUNK_TREE_OBJECTID,
				     start, num_bytes);
	if (ret) {
		i = map->num_stripes - 1;
		goto error_dev_extent;
	}
	}


	kfree(devices_info);
	kfree(devices_info);
	return 0;
	return 0;


error_dev_extent:
	for (; i >= 0; i--) {
		struct btrfs_device *device;
		int err;

		device = map->stripes[i].dev;
		err = btrfs_free_dev_extent(trans, device, start);
		if (err) {
			btrfs_abort_transaction(trans, extent_root, err);
			break;
		}
	}
error:
error:
	kfree(map);
	kfree(map);
	kfree(devices_info);
	kfree(devices_info);