提交 4617ea3a 编写于 作者: F Filipe Manana 提交者: Chris Mason

Btrfs: fix necessary chunk tree space calculation when allocating a chunk

When allocating a new chunk or removing one we need to update num_devs
device items and insert or remove a chunk item in the chunk tree, so
in the worst case the space needed in the chunk space_info is:

  btrfs_calc_trunc_metadata_size(chunk_root, num_devs) +
     btrfs_calc_trans_metadata_size(chunk_root, 1)

That is, in the worst case we need to cow num_devs paths and cow 1 other
path that can result in splitting every node and leaf, and each path
consisting of BTRFS_MAX_LEVEL - 1 nodes and 1 leaf. We were requiring
some additional chunk_root->nodesize * BTRFS_MAX_LEVEL * num_devs bytes,
which were unnecessary since updating the existing device items does
not result in splitting the nodes and leaf since after updating them
they remain with the same size.
Signed-off-by: NFilipe Manana <fdmanana@suse.com>
Signed-off-by: NChris Mason <clm@fb.com>
上级 7558c8bc
...@@ -3518,8 +3518,7 @@ int btrfs_start_write_no_snapshoting(struct btrfs_root *root); ...@@ -3518,8 +3518,7 @@ int btrfs_start_write_no_snapshoting(struct btrfs_root *root);
void btrfs_end_write_no_snapshoting(struct btrfs_root *root); void btrfs_end_write_no_snapshoting(struct btrfs_root *root);
void check_system_chunk(struct btrfs_trans_handle *trans, void check_system_chunk(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
const u64 type, const u64 type);
const bool is_allocation);
/* ctree.c */ /* ctree.c */
int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
int level, int *slot); int level, int *slot);
......
...@@ -4116,8 +4116,7 @@ static u64 get_profile_num_devs(struct btrfs_root *root, u64 type) ...@@ -4116,8 +4116,7 @@ static u64 get_profile_num_devs(struct btrfs_root *root, u64 type)
*/ */
void check_system_chunk(struct btrfs_trans_handle *trans, void check_system_chunk(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
u64 type, u64 type)
const bool is_allocation)
{ {
struct btrfs_space_info *info; struct btrfs_space_info *info;
u64 left; u64 left;
...@@ -4141,11 +4140,8 @@ void check_system_chunk(struct btrfs_trans_handle *trans, ...@@ -4141,11 +4140,8 @@ void check_system_chunk(struct btrfs_trans_handle *trans,
num_devs = get_profile_num_devs(root, type); num_devs = get_profile_num_devs(root, type);
/* num_devs device items to update and 1 chunk item to add or remove */ /* num_devs device items to update and 1 chunk item to add or remove */
if (is_allocation) thresh = btrfs_calc_trunc_metadata_size(root, num_devs) +
thresh = btrfs_calc_trans_metadata_size(root, num_devs + 1); btrfs_calc_trans_metadata_size(root, 1);
else
thresh = btrfs_calc_trans_metadata_size(root, num_devs) +
btrfs_calc_trunc_metadata_size(root, 1);
if (left < thresh && btrfs_test_opt(root, ENOSPC_DEBUG)) { if (left < thresh && btrfs_test_opt(root, ENOSPC_DEBUG)) {
btrfs_info(root->fs_info, "left=%llu, need=%llu, flags=%llu", btrfs_info(root->fs_info, "left=%llu, need=%llu, flags=%llu",
...@@ -4258,7 +4254,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, ...@@ -4258,7 +4254,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
* Check if we have enough space in SYSTEM chunk because we may need * Check if we have enough space in SYSTEM chunk because we may need
* to update devices. * to update devices.
*/ */
check_system_chunk(trans, extent_root, flags, true); check_system_chunk(trans, extent_root, flags);
ret = btrfs_alloc_chunk(trans, extent_root, flags); ret = btrfs_alloc_chunk(trans, extent_root, flags);
trans->allocating_chunk = false; trans->allocating_chunk = false;
...@@ -8926,7 +8922,7 @@ int btrfs_set_block_group_ro(struct btrfs_root *root, ...@@ -8926,7 +8922,7 @@ int btrfs_set_block_group_ro(struct btrfs_root *root,
if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) { if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) {
alloc_flags = update_block_group_flags(root, cache->flags); alloc_flags = update_block_group_flags(root, cache->flags);
lock_chunks(root->fs_info->chunk_root); lock_chunks(root->fs_info->chunk_root);
check_system_chunk(trans, root, alloc_flags, true); check_system_chunk(trans, root, alloc_flags);
unlock_chunks(root->fs_info->chunk_root); unlock_chunks(root->fs_info->chunk_root);
} }
mutex_unlock(&root->fs_info->ro_block_group_mutex); mutex_unlock(&root->fs_info->ro_block_group_mutex);
......
...@@ -2626,7 +2626,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, ...@@ -2626,7 +2626,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
} }
map = (struct map_lookup *)em->bdev; map = (struct map_lookup *)em->bdev;
lock_chunks(root->fs_info->chunk_root); lock_chunks(root->fs_info->chunk_root);
check_system_chunk(trans, extent_root, map->type, false); check_system_chunk(trans, extent_root, map->type);
unlock_chunks(root->fs_info->chunk_root); unlock_chunks(root->fs_info->chunk_root);
for (i = 0; i < map->num_stripes; i++) { for (i = 0; i < map->num_stripes; i++) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册