diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2010-05-16 10:46:25 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-05-25 10:34:50 -0400 |
commit | f0486c68e4bd9a06a5904d3eeb3a0d73a83befb8 (patch) | |
tree | 509428ef400ef45e875a3c448b63b86cbea36aea /fs/btrfs/ctree.c | |
parent | 2ead6ae770d9f9dec9f4286bf0fd9001b4388c4b (diff) |
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 accurate, mainly for handling read only
block groups.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 104 |
1 files changed, 63 insertions, 41 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 6795a713b205..6bee8e5204fb 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -280,7 +280,8 @@ int btrfs_block_can_be_shared(struct btrfs_root *root, | |||
280 | static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, | 280 | static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, |
281 | struct btrfs_root *root, | 281 | struct btrfs_root *root, |
282 | struct extent_buffer *buf, | 282 | struct extent_buffer *buf, |
283 | struct extent_buffer *cow) | 283 | struct extent_buffer *cow, |
284 | int *last_ref) | ||
284 | { | 285 | { |
285 | u64 refs; | 286 | u64 refs; |
286 | u64 owner; | 287 | u64 owner; |
@@ -366,6 +367,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, | |||
366 | BUG_ON(ret); | 367 | BUG_ON(ret); |
367 | } | 368 | } |
368 | clean_tree_block(trans, root, buf); | 369 | clean_tree_block(trans, root, buf); |
370 | *last_ref = 1; | ||
369 | } | 371 | } |
370 | return 0; | 372 | return 0; |
371 | } | 373 | } |
@@ -392,6 +394,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
392 | struct btrfs_disk_key disk_key; | 394 | struct btrfs_disk_key disk_key; |
393 | struct extent_buffer *cow; | 395 | struct extent_buffer *cow; |
394 | int level; | 396 | int level; |
397 | int last_ref = 0; | ||
395 | int unlock_orig = 0; | 398 | int unlock_orig = 0; |
396 | u64 parent_start; | 399 | u64 parent_start; |
397 | 400 | ||
@@ -442,7 +445,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
442 | (unsigned long)btrfs_header_fsid(cow), | 445 | (unsigned long)btrfs_header_fsid(cow), |
443 | BTRFS_FSID_SIZE); | 446 | BTRFS_FSID_SIZE); |
444 | 447 | ||
445 | update_ref_for_cow(trans, root, buf, cow); | 448 | update_ref_for_cow(trans, root, buf, cow, &last_ref); |
446 | 449 | ||
447 | if (buf == root->node) { | 450 | if (buf == root->node) { |
448 | WARN_ON(parent && parent != buf); | 451 | WARN_ON(parent && parent != buf); |
@@ -457,8 +460,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
457 | extent_buffer_get(cow); | 460 | extent_buffer_get(cow); |
458 | spin_unlock(&root->node_lock); | 461 | spin_unlock(&root->node_lock); |
459 | 462 | ||
460 | btrfs_free_tree_block(trans, root, buf->start, buf->len, | 463 | btrfs_free_tree_block(trans, root, buf, parent_start, |
461 | parent_start, root->root_key.objectid, level); | 464 | last_ref); |
462 | free_extent_buffer(buf); | 465 | free_extent_buffer(buf); |
463 | add_root_to_dirty_list(root); | 466 | add_root_to_dirty_list(root); |
464 | } else { | 467 | } else { |
@@ -473,8 +476,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
473 | btrfs_set_node_ptr_generation(parent, parent_slot, | 476 | btrfs_set_node_ptr_generation(parent, parent_slot, |
474 | trans->transid); | 477 | trans->transid); |
475 | btrfs_mark_buffer_dirty(parent); | 478 | btrfs_mark_buffer_dirty(parent); |
476 | btrfs_free_tree_block(trans, root, buf->start, buf->len, | 479 | btrfs_free_tree_block(trans, root, buf, parent_start, |
477 | parent_start, root->root_key.objectid, level); | 480 | last_ref); |
478 | } | 481 | } |
479 | if (unlock_orig) | 482 | if (unlock_orig) |
480 | btrfs_tree_unlock(buf); | 483 | btrfs_tree_unlock(buf); |
@@ -949,6 +952,22 @@ int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, | |||
949 | return bin_search(eb, key, level, slot); | 952 | return bin_search(eb, key, level, slot); |
950 | } | 953 | } |
951 | 954 | ||
955 | static void root_add_used(struct btrfs_root *root, u32 size) | ||
956 | { | ||
957 | spin_lock(&root->accounting_lock); | ||
958 | btrfs_set_root_used(&root->root_item, | ||
959 | btrfs_root_used(&root->root_item) + size); | ||
960 | spin_unlock(&root->accounting_lock); | ||
961 | } | ||
962 | |||
963 | static void root_sub_used(struct btrfs_root *root, u32 size) | ||
964 | { | ||
965 | spin_lock(&root->accounting_lock); | ||
966 | btrfs_set_root_used(&root->root_item, | ||
967 | btrfs_root_used(&root->root_item) - size); | ||
968 | spin_unlock(&root->accounting_lock); | ||
969 | } | ||
970 | |||
952 | /* given a node and slot number, this reads the blocks it points to. The | 971 | /* given a node and slot number, this reads the blocks it points to. The |
953 | * extent buffer is returned with a reference taken (but unlocked). | 972 | * extent buffer is returned with a reference taken (but unlocked). |
954 | * NULL is returned on error. | 973 | * NULL is returned on error. |
@@ -1019,7 +1038,11 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
1019 | btrfs_tree_lock(child); | 1038 | btrfs_tree_lock(child); |
1020 | btrfs_set_lock_blocking(child); | 1039 | btrfs_set_lock_blocking(child); |
1021 | ret = btrfs_cow_block(trans, root, child, mid, 0, &child); | 1040 | ret = btrfs_cow_block(trans, root, child, mid, 0, &child); |
1022 | BUG_ON(ret); | 1041 | if (ret) { |
1042 | btrfs_tree_unlock(child); | ||
1043 | free_extent_buffer(child); | ||
1044 | goto enospc; | ||
1045 | } | ||
1023 | 1046 | ||
1024 | spin_lock(&root->node_lock); | 1047 | spin_lock(&root->node_lock); |
1025 | root->node = child; | 1048 | root->node = child; |
@@ -1034,11 +1057,12 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
1034 | btrfs_tree_unlock(mid); | 1057 | btrfs_tree_unlock(mid); |
1035 | /* once for the path */ | 1058 | /* once for the path */ |
1036 | free_extent_buffer(mid); | 1059 | free_extent_buffer(mid); |
1037 | ret = btrfs_free_tree_block(trans, root, mid->start, mid->len, | 1060 | |
1038 | 0, root->root_key.objectid, level); | 1061 | root_sub_used(root, mid->len); |
1062 | btrfs_free_tree_block(trans, root, mid, 0, 1); | ||
1039 | /* once for the root ptr */ | 1063 | /* once for the root ptr */ |
1040 | free_extent_buffer(mid); | 1064 | free_extent_buffer(mid); |
1041 | return ret; | 1065 | return 0; |
1042 | } | 1066 | } |
1043 | if (btrfs_header_nritems(mid) > | 1067 | if (btrfs_header_nritems(mid) > |
1044 | BTRFS_NODEPTRS_PER_BLOCK(root) / 4) | 1068 | BTRFS_NODEPTRS_PER_BLOCK(root) / 4) |
@@ -1088,23 +1112,16 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
1088 | if (wret < 0 && wret != -ENOSPC) | 1112 | if (wret < 0 && wret != -ENOSPC) |
1089 | ret = wret; | 1113 | ret = wret; |
1090 | if (btrfs_header_nritems(right) == 0) { | 1114 | if (btrfs_header_nritems(right) == 0) { |
1091 | u64 bytenr = right->start; | ||
1092 | u32 blocksize = right->len; | ||
1093 | |||
1094 | clean_tree_block(trans, root, right); | 1115 | clean_tree_block(trans, root, right); |
1095 | btrfs_tree_unlock(right); | 1116 | btrfs_tree_unlock(right); |
1096 | free_extent_buffer(right); | ||
1097 | right = NULL; | ||
1098 | wret = del_ptr(trans, root, path, level + 1, pslot + | 1117 | wret = del_ptr(trans, root, path, level + 1, pslot + |
1099 | 1); | 1118 | 1); |
1100 | if (wret) | 1119 | if (wret) |
1101 | ret = wret; | 1120 | ret = wret; |
1102 | wret = btrfs_free_tree_block(trans, root, | 1121 | root_sub_used(root, right->len); |
1103 | bytenr, blocksize, 0, | 1122 | btrfs_free_tree_block(trans, root, right, 0, 1); |
1104 | root->root_key.objectid, | 1123 | free_extent_buffer(right); |
1105 | level); | 1124 | right = NULL; |
1106 | if (wret) | ||
1107 | ret = wret; | ||
1108 | } else { | 1125 | } else { |
1109 | struct btrfs_disk_key right_key; | 1126 | struct btrfs_disk_key right_key; |
1110 | btrfs_node_key(right, &right_key, 0); | 1127 | btrfs_node_key(right, &right_key, 0); |
@@ -1136,21 +1153,15 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
1136 | BUG_ON(wret == 1); | 1153 | BUG_ON(wret == 1); |
1137 | } | 1154 | } |
1138 | if (btrfs_header_nritems(mid) == 0) { | 1155 | if (btrfs_header_nritems(mid) == 0) { |
1139 | /* we've managed to empty the middle node, drop it */ | ||
1140 | u64 bytenr = mid->start; | ||
1141 | u32 blocksize = mid->len; | ||
1142 | |||
1143 | clean_tree_block(trans, root, mid); | 1156 | clean_tree_block(trans, root, mid); |
1144 | btrfs_tree_unlock(mid); | 1157 | btrfs_tree_unlock(mid); |
1145 | free_extent_buffer(mid); | ||
1146 | mid = NULL; | ||
1147 | wret = del_ptr(trans, root, path, level + 1, pslot); | 1158 | wret = del_ptr(trans, root, path, level + 1, pslot); |
1148 | if (wret) | 1159 | if (wret) |
1149 | ret = wret; | 1160 | ret = wret; |
1150 | wret = btrfs_free_tree_block(trans, root, bytenr, blocksize, | 1161 | root_sub_used(root, mid->len); |
1151 | 0, root->root_key.objectid, level); | 1162 | btrfs_free_tree_block(trans, root, mid, 0, 1); |
1152 | if (wret) | 1163 | free_extent_buffer(mid); |
1153 | ret = wret; | 1164 | mid = NULL; |
1154 | } else { | 1165 | } else { |
1155 | /* update the parent key to reflect our changes */ | 1166 | /* update the parent key to reflect our changes */ |
1156 | struct btrfs_disk_key mid_key; | 1167 | struct btrfs_disk_key mid_key; |
@@ -1740,7 +1751,6 @@ again: | |||
1740 | p->nodes[level + 1], | 1751 | p->nodes[level + 1], |
1741 | p->slots[level + 1], &b); | 1752 | p->slots[level + 1], &b); |
1742 | if (err) { | 1753 | if (err) { |
1743 | free_extent_buffer(b); | ||
1744 | ret = err; | 1754 | ret = err; |
1745 | goto done; | 1755 | goto done; |
1746 | } | 1756 | } |
@@ -2076,6 +2086,8 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans, | |||
2076 | if (IS_ERR(c)) | 2086 | if (IS_ERR(c)) |
2077 | return PTR_ERR(c); | 2087 | return PTR_ERR(c); |
2078 | 2088 | ||
2089 | root_add_used(root, root->nodesize); | ||
2090 | |||
2079 | memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header)); | 2091 | memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header)); |
2080 | btrfs_set_header_nritems(c, 1); | 2092 | btrfs_set_header_nritems(c, 1); |
2081 | btrfs_set_header_level(c, level); | 2093 | btrfs_set_header_level(c, level); |
@@ -2134,6 +2146,7 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root | |||
2134 | int nritems; | 2146 | int nritems; |
2135 | 2147 | ||
2136 | BUG_ON(!path->nodes[level]); | 2148 | BUG_ON(!path->nodes[level]); |
2149 | btrfs_assert_tree_locked(path->nodes[level]); | ||
2137 | lower = path->nodes[level]; | 2150 | lower = path->nodes[level]; |
2138 | nritems = btrfs_header_nritems(lower); | 2151 | nritems = btrfs_header_nritems(lower); |
2139 | BUG_ON(slot > nritems); | 2152 | BUG_ON(slot > nritems); |
@@ -2202,6 +2215,8 @@ static noinline int split_node(struct btrfs_trans_handle *trans, | |||
2202 | if (IS_ERR(split)) | 2215 | if (IS_ERR(split)) |
2203 | return PTR_ERR(split); | 2216 | return PTR_ERR(split); |
2204 | 2217 | ||
2218 | root_add_used(root, root->nodesize); | ||
2219 | |||
2205 | memset_extent_buffer(split, 0, 0, sizeof(struct btrfs_header)); | 2220 | memset_extent_buffer(split, 0, 0, sizeof(struct btrfs_header)); |
2206 | btrfs_set_header_level(split, btrfs_header_level(c)); | 2221 | btrfs_set_header_level(split, btrfs_header_level(c)); |
2207 | btrfs_set_header_bytenr(split, split->start); | 2222 | btrfs_set_header_bytenr(split, split->start); |
@@ -2415,6 +2430,9 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans, | |||
2415 | 2430 | ||
2416 | if (left_nritems) | 2431 | if (left_nritems) |
2417 | btrfs_mark_buffer_dirty(left); | 2432 | btrfs_mark_buffer_dirty(left); |
2433 | else | ||
2434 | clean_tree_block(trans, root, left); | ||
2435 | |||
2418 | btrfs_mark_buffer_dirty(right); | 2436 | btrfs_mark_buffer_dirty(right); |
2419 | 2437 | ||
2420 | btrfs_item_key(right, &disk_key, 0); | 2438 | btrfs_item_key(right, &disk_key, 0); |
@@ -2660,6 +2678,8 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans, | |||
2660 | btrfs_mark_buffer_dirty(left); | 2678 | btrfs_mark_buffer_dirty(left); |
2661 | if (right_nritems) | 2679 | if (right_nritems) |
2662 | btrfs_mark_buffer_dirty(right); | 2680 | btrfs_mark_buffer_dirty(right); |
2681 | else | ||
2682 | clean_tree_block(trans, root, right); | ||
2663 | 2683 | ||
2664 | btrfs_item_key(right, &disk_key, 0); | 2684 | btrfs_item_key(right, &disk_key, 0); |
2665 | wret = fixup_low_keys(trans, root, path, &disk_key, 1); | 2685 | wret = fixup_low_keys(trans, root, path, &disk_key, 1); |
@@ -2669,8 +2689,6 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans, | |||
2669 | /* then fixup the leaf pointer in the path */ | 2689 | /* then fixup the leaf pointer in the path */ |
2670 | if (path->slots[0] < push_items) { | 2690 | if (path->slots[0] < push_items) { |
2671 | path->slots[0] += old_left_nritems; | 2691 | path->slots[0] += old_left_nritems; |
2672 | if (btrfs_header_nritems(path->nodes[0]) == 0) | ||
2673 | clean_tree_block(trans, root, path->nodes[0]); | ||
2674 | btrfs_tree_unlock(path->nodes[0]); | 2692 | btrfs_tree_unlock(path->nodes[0]); |
2675 | free_extent_buffer(path->nodes[0]); | 2693 | free_extent_buffer(path->nodes[0]); |
2676 | path->nodes[0] = left; | 2694 | path->nodes[0] = left; |
@@ -2932,10 +2950,10 @@ again: | |||
2932 | right = btrfs_alloc_free_block(trans, root, root->leafsize, 0, | 2950 | right = btrfs_alloc_free_block(trans, root, root->leafsize, 0, |
2933 | root->root_key.objectid, | 2951 | root->root_key.objectid, |
2934 | &disk_key, 0, l->start, 0); | 2952 | &disk_key, 0, l->start, 0); |
2935 | if (IS_ERR(right)) { | 2953 | if (IS_ERR(right)) |
2936 | BUG_ON(1); | ||
2937 | return PTR_ERR(right); | 2954 | return PTR_ERR(right); |
2938 | } | 2955 | |
2956 | root_add_used(root, root->leafsize); | ||
2939 | 2957 | ||
2940 | memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header)); | 2958 | memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header)); |
2941 | btrfs_set_header_bytenr(right, right->start); | 2959 | btrfs_set_header_bytenr(right, right->start); |
@@ -3054,7 +3072,8 @@ static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans, | |||
3054 | 3072 | ||
3055 | btrfs_set_path_blocking(path); | 3073 | btrfs_set_path_blocking(path); |
3056 | ret = split_leaf(trans, root, &key, path, ins_len, 1); | 3074 | ret = split_leaf(trans, root, &key, path, ins_len, 1); |
3057 | BUG_ON(ret); | 3075 | if (ret) |
3076 | goto err; | ||
3058 | 3077 | ||
3059 | path->keep_locks = 0; | 3078 | path->keep_locks = 0; |
3060 | btrfs_unlock_up_safe(path, 1); | 3079 | btrfs_unlock_up_safe(path, 1); |
@@ -3796,9 +3815,10 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans, | |||
3796 | */ | 3815 | */ |
3797 | btrfs_unlock_up_safe(path, 0); | 3816 | btrfs_unlock_up_safe(path, 0); |
3798 | 3817 | ||
3799 | ret = btrfs_free_tree_block(trans, root, leaf->start, leaf->len, | 3818 | root_sub_used(root, leaf->len); |
3800 | 0, root->root_key.objectid, 0); | 3819 | |
3801 | return ret; | 3820 | btrfs_free_tree_block(trans, root, leaf, 0, 1); |
3821 | return 0; | ||
3802 | } | 3822 | } |
3803 | /* | 3823 | /* |
3804 | * delete the item at the leaf level in path. If that empties | 3824 | * delete the item at the leaf level in path. If that empties |
@@ -3865,6 +3885,8 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
3865 | if (leaf == root->node) { | 3885 | if (leaf == root->node) { |
3866 | btrfs_set_header_level(leaf, 0); | 3886 | btrfs_set_header_level(leaf, 0); |
3867 | } else { | 3887 | } else { |
3888 | btrfs_set_path_blocking(path); | ||
3889 | clean_tree_block(trans, root, leaf); | ||
3868 | ret = btrfs_del_leaf(trans, root, path, leaf); | 3890 | ret = btrfs_del_leaf(trans, root, path, leaf); |
3869 | BUG_ON(ret); | 3891 | BUG_ON(ret); |
3870 | } | 3892 | } |