Btrfs: Introduce contexts for metadata reservation
PATCH v2 5/12 Btrfs: Introduce contexts for metadata reservation
Introducing metadata reseravtion contexts has two major advantages. First, it makes metadata reseravtion more traceable. Second, it can reclaim freed space and re-add them to the itself after transaction committed.
Besides add btrfs_block_rsv structure and related helper functions, This patch contains following changes:
Move code that decides if freed tree block should be pinned into btrfs_free_tree_block().
Make space accounting more accuracy, mainly for handling read only block groups.
fs/btrfs/ctree.c +63 -41
@@ -279,7 +279,8 @@ int btrfs_block_can_be_shared(struct btr static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,struct btrfs_root *root,struct extent_buffer *buf, -struct extent_buffer *cow) +struct extent_buffer *cow, +int *last_ref) {u64 refs;u64 owner;
@@ -365,6 +366,7 @@ static noinline int update_ref_for_cow(sBUG_ON (ret); }clean_tree_block (trans, root, buf); + *last_ref =1 ; }return 0 ; }
@@ -391,6 +393,7 @@ static noinline int __btrfs_cow_block(ststruct btrfs_disk_key disk_key;struct extent_buffer *cow;int level; +int last_ref =0 ;int unlock_orig =0 ;u64 parent_start;
@@ -441,7 +444,7 @@ static noinline int __btrfs_cow_block(st (unsigned long )btrfs_header_fsid (cow), BTRFS_FSID_SIZE); -update_ref_for_cow (trans, root, buf, cow); +update_ref_for_cow (trans, root, buf, cow, &last_ref);if (buf == root->node) {WARN_ON (parent && parent != buf);
@@ -456,8 +459,8 @@ static noinline int __btrfs_cow_block(stextent_buffer_get (cow);spin_unlock (&root->node_lock); -btrfs_free_tree_block (trans, root, buf->start, buf->len, - parent_start, root->root_key.objectid, level); +btrfs_free_tree_block (trans, root, buf, parent_start, + last_ref);free_extent_buffer (buf);add_root_to_dirty_list (root); }else {
@@ -472,8 +475,8 @@ static noinline int __btrfs_cow_block(stbtrfs_set_node_ptr_generation (parent, parent_slot, trans->transid);btrfs_mark_buffer_dirty (parent); -btrfs_free_tree_block (trans, root, buf->start, buf->len, - parent_start, root->root_key.objectid, level); +btrfs_free_tree_block (trans, root, buf, parent_start, + last_ref); }if (unlock_orig)btrfs_tree_unlock (buf);
@@ -948,6 +951,22 @@ int btrfs_bin_search(struct extent_buffereturn bin_search (eb, key, level, slot); } +static void root_add_used (struct btrfs_root *root,u32 size) +{ +spin_lock (&root->accounting_lock); +btrfs_set_root_used (&root->root_item, +btrfs_root_used (&root->root_item) + size); +spin_unlock (&root->accounting_lock); +} + +static void root_sub_used (struct btrfs_root *root,u32 size) +{ +spin_lock (&root->accounting_lock); +btrfs_set_root_used (&root->root_item, +btrfs_root_used (&root->root_item) - size); +spin_unlock (&root->accounting_lock); +} +/* given a node and slot number, this reads the blocks it points to. The * extent buffer is returned with a reference taken (but unlocked). * NULL is returned on error.
@@ -1018,7 +1037,11 @@ static noinline int balance_level(structbtrfs_tree_lock (child);btrfs_set_lock_blocking (child); ret =btrfs_cow_block (trans, root, child, mid,0 , &child); -BUG_ON (ret); +if (ret) { +btrfs_tree_unlock (child); +free_extent_buffer (child); + goto enospc; + }spin_lock (&root->node_lock); root->node = child;
@@ -1033,11 +1056,12 @@ static noinline int balance_level(structbtrfs_tree_unlock (mid);/* once for the path */ free_extent_buffer (mid); - ret =btrfs_free_tree_block (trans, root, mid->start, mid->len, -0 , root->root_key.objectid, level); + +root_sub_used (root, mid->len); +btrfs_free_tree_block (trans, root, mid,0 ,1 );/* once for the root ptr */ free_extent_buffer (mid); -return ret; +return 0 ; }if (btrfs_header_nritems (mid) >BTRFS_NODEPTRS_PER_BLOCK (root) /4 )
@@ -1087,23 +1111,16 @@ static noinline int balance_level(structif (wret <0 && wret != -ENOSPC ) ret = wret;if (btrfs_header_nritems (right) ==0 ) { -u64 bytenr = right->start; -u32 blocksize = right->len; -clean_tree_block (trans, root, right);btrfs_tree_unlock (right); -free_extent_buffer (right); - right =NULL ; wret =del_ptr (trans, root, path, level +1 , pslot +1 );if (wret) ret = wret; - wret =btrfs_free_tree_block (trans, root, - bytenr, blocksize,0 , - root->root_key.objectid, - level); -if (wret) - ret = wret; +root_sub_used (root, right->len); +btrfs_free_tree_block (trans, root, right,0 ,1 ); +free_extent_buffer (right); + right =NULL ; }else {struct btrfs_disk_key right_key;btrfs_node_key (right, &right_key,0 );
@@ -1135,21 +1152,15 @@ static noinline int balance_level(structBUG_ON (wret ==1 ); }if (btrfs_header_nritems (mid) ==0 ) { -/* we've managed to empty the middle node, drop it */ -u64 bytenr = mid->start; -u32 blocksize = mid->len; -clean_tree_block (trans, root, mid);btrfs_tree_unlock (mid); -free_extent_buffer (mid); - mid =NULL ; wret =del_ptr (trans, root, path, level +1 , pslot);if (wret) ret = wret; - wret =btrfs_free_tree_block (trans, root, bytenr, blocksize, -0 , root->root_key.objectid, level); -if (wret) - ret = wret; +root_sub_used (root, mid->len); +btrfs_free_tree_block (trans, root, mid,0 ,1 ); +free_extent_buffer (mid); + mid =NULL ; }else {/* update the parent key to reflect our changes */ struct btrfs_disk_key mid_key;
@@ -1739,7 +1750,6 @@ again: p->nodes[level +1 ], p->slots[level + 1], &b);if (err) { -free_extent_buffer (b); ret = err; goto done; }
@@ -2075,6 +2085,8 @@ static noinline int insert_new_root(struif (IS_ERR (c))return PTR_ERR (c); +root_add_used (root, root->nodesize); +memset_extent_buffer (c,0 ,0 ,sizeof (struct btrfs_header ));btrfs_set_header_nritems (c,1 );btrfs_set_header_level (c, level);
@@ -2133,6 +2145,7 @@ static int insert_ptr(struct btrfs_transint nritems;BUG_ON (!path->nodes[level]); +btrfs_assert_tree_locked (path->nodes[level]); lower = path->nodes[level]; nritems =btrfs_header_nritems (lower);BUG_ON (slot > nritems);
@@ -2201,6 +2214,8 @@ static noinline int split_node(struct btif (IS_ERR (split))return PTR_ERR (split); +root_add_used (root, root->nodesize); +memset_extent_buffer (split,0 ,0 ,sizeof (struct btrfs_header ));btrfs_set_header_level (split,btrfs_header_level (c));btrfs_set_header_bytenr (split, split->start);
@@ -2414,6 +2429,9 @@ static noinline int __push_leaf_right(stif (left_nritems)btrfs_mark_buffer_dirty (left); +else +clean_tree_block (trans, root, left); +btrfs_mark_buffer_dirty (right);btrfs_item_key (right, &disk_key,0 );
@@ -2659,6 +2677,8 @@ static noinline int __push_leaf_left(strbtrfs_mark_buffer_dirty (left);if (right_nritems)btrfs_mark_buffer_dirty (right); +else +clean_tree_block (trans, root, right);btrfs_item_key (right, &disk_key,0 ); wret =fixup_low_keys (trans, root, path, &disk_key,1 );
@@ -2668,8 +2688,6 @@ static noinline int __push_leaf_left(str/* then fixup the leaf pointer in the path */ if (path->slots[0 ] < push_items) { path->slots[0 ] += old_left_nritems; -if (btrfs_header_nritems (path->nodes[0 ]) ==0 ) -clean_tree_block (trans, root, path->nodes[0 ]);btrfs_tree_unlock (path->nodes[0 ]);free_extent_buffer (path->nodes[0 ]); path->nodes[0 ] = left;
@@ -2931,10 +2949,10 @@ again: right =btrfs_alloc_free_block (trans, root, root->leafsize,0 , root->root_key.objectid, &disk_key,0 , l->start,0 ); -if (IS_ERR (right)) { -BUG_ON (1 ); +if (IS_ERR (right))return PTR_ERR (right); - } + +root_add_used (root, root->leafsize);memset_extent_buffer (right,0 ,0 ,sizeof (struct btrfs_header ));btrfs_set_header_bytenr (right, right->start);
@@ -3053,7 +3071,8 @@ static noinline int setup_leaf_for_splitbtrfs_set_path_blocking (path); ret =split_leaf (trans, root, &key, path, ins_len,1 ); -BUG_ON (ret); +if (ret) + goto err; path->keep_locks =0 ;btrfs_unlock_up_safe (path,1 );
@@ -3795,9 +3814,10 @@ static noinline int btrfs_del_leaf(struc*/ btrfs_unlock_up_safe (path,0 ); - ret =btrfs_free_tree_block (trans, root, leaf->start, leaf->len, -0 , root->root_key.objectid,0 ); -return ret; +root_sub_used (root, leaf->len); + +btrfs_free_tree_block (trans, root, leaf,0 ,1 ); +return 0 ; }/* * delete the item at the leaf level in path. If that empties
@@ -3864,6 +3884,8 @@ int btrfs_del_items(struct btrfs_trans_hif (leaf == root->node) {btrfs_set_header_level (leaf,0 ); }else { +btrfs_set_path_blocking (path); +clean_tree_block (trans, root, leaf); ret =btrfs_del_leaf (trans, root, path, leaf);BUG_ON (ret); }
fs/btrfs/ctree.h +62 -7
111 lines not on this page · raw message
fs/btrfs/disk-io.c +9 -0
@@ -904,6 +904,7 @@ static int __setup_root(u32 nodesize, u3 root->name =NULL ; root->in_sysfs =0 ; root->inode_tree =RB_ROOT ; + root->block_rsv =NULL ;INIT_LIST_HEAD (&root->dirty_list);INIT_LIST_HEAD (&root->orphan_list);
@@ -911,6 +912,7 @@ static int __setup_root(u32 nodesize, u3spin_lock_init (&root->node_lock);spin_lock_init (&root->list_lock);spin_lock_init (&root->inode_lock); +spin_lock_init (&root->accounting_lock);mutex_init (&root->objectid_mutex);mutex_init (&root->log_mutex);init_waitqueue_head (&root->log_writer_wait);
@@ -1629,6 +1631,13 @@ struct btrfs_root *open_ctree(struct supINIT_LIST_HEAD (&fs_info->dirty_cowonly_roots);INIT_LIST_HEAD (&fs_info->space_info);btrfs_mapping_init (&fs_info->mapping_tree); +btrfs_init_block_rsv (&fs_info->global_block_rsv); +btrfs_init_block_rsv (&fs_info->delalloc_block_rsv); +btrfs_init_block_rsv (&fs_info->trans_block_rsv); +btrfs_init_block_rsv (&fs_info->chunk_block_rsv); +btrfs_init_block_rsv (&fs_info->empty_block_rsv); +INIT_LIST_HEAD (&fs_info->durable_block_rsv_list); +mutex_init (&fs_info->durable_block_rsv_mutex);atomic_set (&fs_info->nr_async_submits,0 );atomic_set (&fs_info->async_delalloc_pages,0 );atomic_set (&fs_info->async_submit_draining,0 );
fs/btrfs/extent-tree.c +703 -330
1,389 lines not on this page · raw message
fs/btrfs/relocation.c +13 -3
@@ -3513,6 +3513,7 @@ int btrfs_relocate_block_group(struct btstruct btrfs_fs_info *fs_info = extent_root->fs_info;struct reloc_control *rc;int ret; +int rw =0 ;int err =0 ; rc =kzalloc (sizeof (*rc),GFP_NOFS );
@@ -3523,15 +3524,22 @@ int btrfs_relocate_block_group(struct btextent_io_tree_init (&rc->processed_blocks,NULL ,GFP_NOFS );INIT_LIST_HEAD (&rc->reloc_roots); + rc->extent_root = extent_root; rc->block_group =btrfs_lookup_block_group (fs_info, group_start);BUG_ON (!rc->block_group); +if (!rc->block_group->ro) { + ret =btrfs_set_block_group_ro (extent_root, rc->block_group); +if (ret) { + err = ret; + goto out; + } + rw =1 ; + } +btrfs_init_workers (&rc->workers,"relocate" , fs_info->thread_pool_size,NULL ); - rc->extent_root = extent_root; -btrfs_prepare_block_group_relocation (extent_root, rc->block_group); - rc->data_inode =create_reloc_inode (fs_info, rc->block_group);if (IS_ERR (rc->data_inode)) { err =PTR_ERR (rc->data_inode);
@@ -3596,6 +3604,8 @@ int btrfs_relocate_block_group(struct btWARN_ON (rc->block_group->reserved >0 );WARN_ON (btrfs_block_group_used (&rc->block_group->item) >0 ); out: +if (err && rw) +btrfs_set_block_group_rw (extent_root, rc->block_group);iput (rc->data_inode);btrfs_stop_workers (&rc->workers);btrfs_put_block_group (rc->block_group);
fs/btrfs/transaction.c +1 -2
@@ -184,9 +184,8 @@ static struct btrfs_trans_handle *start_ h->blocks_reserved = num_blocks; h->blocks_used =0 ; h->block_group =0 ; - h->alloc_exclude_nr =0 ; - h->alloc_exclude_start =0 ; h->delayed_ref_updates =0 ; + h->block_rsv =NULL ;if (!current->journal_info && type !=TRANS_USERSPACE ) current->journal_info = h;
fs/btrfs/transaction.h +4 -4
@@ -45,13 +45,13 @@ struct btrfs_transaction {struct btrfs_trans_handle {u64 transid; +u64 block_group; +u64 bytes_reserved;unsigned long blocks_reserved;unsigned long blocks_used; -struct btrfs_transaction *transaction; -u64 block_group; -u64 alloc_exclude_start; -u64 alloc_exclude_nr;unsigned long delayed_ref_updates; +struct btrfs_transaction *transaction; +struct btrfs_block_rsv *block_rsv; };struct btrfs_pending_snapshot {
Signed-off-by Yan Zheng <[email protected]>
---