diff options
author | Yan Zheng <zheng.yan@oracle.com> | 2008-10-29 14:49:05 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-10-29 14:49:05 -0400 |
commit | f82d02d9d8222183b7945e893111a6d1bf67ae4a (patch) | |
tree | 70be1bb231f4cc2e673920774e759359f3dcf1a5 /fs/btrfs/extent-tree.c | |
parent | c8b978188c9a0fd3d535c13debd19d522b726f1f (diff) |
Btrfs: Improve space balancing code
This patch improves the space balancing code to keep more sharing
of tree blocks. The only case that breaks sharing of tree blocks is
data extents get fragmented during balancing. The main changes in
this patch are:
Add a 'drop sub-tree' function. This solves the problem in old code
that BTRFS_HEADER_FLAG_WRITTEN check breaks sharing of tree block.
Remove relocation mapping tree. Relocation mappings are stored in
struct btrfs_ref_path and updated dynamically during walking up/down
the reference path. This reduces CPU usage and simplifies code.
This patch also fixes a bug. Root items for reloc trees should be
updated in btrfs_free_reloc_root.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 364 |
1 files changed, 223 insertions, 141 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index bbf04e80a1a3..56e41369d713 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -3032,13 +3032,103 @@ out: | |||
3032 | } | 3032 | } |
3033 | 3033 | ||
3034 | /* | 3034 | /* |
3035 | * helper function for drop_subtree, this function is similar to | ||
3036 | * walk_down_tree. The main difference is that it checks reference | ||
3037 | * counts while tree blocks are locked. | ||
3038 | */ | ||
3039 | static int noinline walk_down_subtree(struct btrfs_trans_handle *trans, | ||
3040 | struct btrfs_root *root, | ||
3041 | struct btrfs_path *path, int *level) | ||
3042 | { | ||
3043 | struct extent_buffer *next; | ||
3044 | struct extent_buffer *cur; | ||
3045 | struct extent_buffer *parent; | ||
3046 | u64 bytenr; | ||
3047 | u64 ptr_gen; | ||
3048 | u32 blocksize; | ||
3049 | u32 refs; | ||
3050 | int ret; | ||
3051 | |||
3052 | cur = path->nodes[*level]; | ||
3053 | ret = btrfs_lookup_extent_ref(trans, root, cur->start, cur->len, | ||
3054 | &refs); | ||
3055 | BUG_ON(ret); | ||
3056 | if (refs > 1) | ||
3057 | goto out; | ||
3058 | |||
3059 | while (*level >= 0) { | ||
3060 | cur = path->nodes[*level]; | ||
3061 | if (*level == 0) { | ||
3062 | ret = btrfs_drop_leaf_ref(trans, root, cur); | ||
3063 | BUG_ON(ret); | ||
3064 | clean_tree_block(trans, root, cur); | ||
3065 | break; | ||
3066 | } | ||
3067 | if (path->slots[*level] >= btrfs_header_nritems(cur)) { | ||
3068 | clean_tree_block(trans, root, cur); | ||
3069 | break; | ||
3070 | } | ||
3071 | |||
3072 | bytenr = btrfs_node_blockptr(cur, path->slots[*level]); | ||
3073 | blocksize = btrfs_level_size(root, *level - 1); | ||
3074 | ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]); | ||
3075 | |||
3076 | next = read_tree_block(root, bytenr, blocksize, ptr_gen); | ||
3077 | btrfs_tree_lock(next); | ||
3078 | |||
3079 | ret = btrfs_lookup_extent_ref(trans, root, bytenr, blocksize, | ||
3080 | &refs); | ||
3081 | BUG_ON(ret); | ||
3082 | if (refs > 1) { | ||
3083 | parent = path->nodes[*level]; | ||
3084 | ret = btrfs_free_extent(trans, root, bytenr, | ||
3085 | blocksize, parent->start, | ||
3086 | btrfs_header_owner(parent), | ||
3087 | btrfs_header_generation(parent), | ||
3088 | *level - 1, 1); | ||
3089 | BUG_ON(ret); | ||
3090 | path->slots[*level]++; | ||
3091 | btrfs_tree_unlock(next); | ||
3092 | free_extent_buffer(next); | ||
3093 | continue; | ||
3094 | } | ||
3095 | |||
3096 | *level = btrfs_header_level(next); | ||
3097 | path->nodes[*level] = next; | ||
3098 | path->slots[*level] = 0; | ||
3099 | path->locks[*level] = 1; | ||
3100 | cond_resched(); | ||
3101 | } | ||
3102 | out: | ||
3103 | parent = path->nodes[*level + 1]; | ||
3104 | bytenr = path->nodes[*level]->start; | ||
3105 | blocksize = path->nodes[*level]->len; | ||
3106 | |||
3107 | ret = btrfs_free_extent(trans, root, bytenr, blocksize, | ||
3108 | parent->start, btrfs_header_owner(parent), | ||
3109 | btrfs_header_generation(parent), *level, 1); | ||
3110 | BUG_ON(ret); | ||
3111 | |||
3112 | if (path->locks[*level]) { | ||
3113 | btrfs_tree_unlock(path->nodes[*level]); | ||
3114 | path->locks[*level] = 0; | ||
3115 | } | ||
3116 | free_extent_buffer(path->nodes[*level]); | ||
3117 | path->nodes[*level] = NULL; | ||
3118 | *level += 1; | ||
3119 | cond_resched(); | ||
3120 | return 0; | ||
3121 | } | ||
3122 | |||
3123 | /* | ||
3035 | * helper for dropping snapshots. This walks back up the tree in the path | 3124 | * helper for dropping snapshots. This walks back up the tree in the path |
3036 | * to find the first node higher up where we haven't yet gone through | 3125 | * to find the first node higher up where we haven't yet gone through |
3037 | * all the slots | 3126 | * all the slots |
3038 | */ | 3127 | */ |
3039 | static int noinline walk_up_tree(struct btrfs_trans_handle *trans, | 3128 | static int noinline walk_up_tree(struct btrfs_trans_handle *trans, |
3040 | struct btrfs_root *root, | 3129 | struct btrfs_root *root, |
3041 | struct btrfs_path *path, int *level) | 3130 | struct btrfs_path *path, |
3131 | int *level, int max_level) | ||
3042 | { | 3132 | { |
3043 | u64 root_owner; | 3133 | u64 root_owner; |
3044 | u64 root_gen; | 3134 | u64 root_gen; |
@@ -3047,7 +3137,7 @@ static int noinline walk_up_tree(struct btrfs_trans_handle *trans, | |||
3047 | int slot; | 3137 | int slot; |
3048 | int ret; | 3138 | int ret; |
3049 | 3139 | ||
3050 | for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { | 3140 | for (i = *level; i < max_level && path->nodes[i]; i++) { |
3051 | slot = path->slots[i]; | 3141 | slot = path->slots[i]; |
3052 | if (slot < btrfs_header_nritems(path->nodes[i]) - 1) { | 3142 | if (slot < btrfs_header_nritems(path->nodes[i]) - 1) { |
3053 | struct extent_buffer *node; | 3143 | struct extent_buffer *node; |
@@ -3070,12 +3160,18 @@ static int noinline walk_up_tree(struct btrfs_trans_handle *trans, | |||
3070 | 3160 | ||
3071 | root_owner = btrfs_header_owner(parent); | 3161 | root_owner = btrfs_header_owner(parent); |
3072 | root_gen = btrfs_header_generation(parent); | 3162 | root_gen = btrfs_header_generation(parent); |
3163 | |||
3164 | clean_tree_block(trans, root, path->nodes[*level]); | ||
3073 | ret = btrfs_free_extent(trans, root, | 3165 | ret = btrfs_free_extent(trans, root, |
3074 | path->nodes[*level]->start, | 3166 | path->nodes[*level]->start, |
3075 | path->nodes[*level]->len, | 3167 | path->nodes[*level]->len, |
3076 | parent->start, root_owner, | 3168 | parent->start, root_owner, |
3077 | root_gen, *level, 1); | 3169 | root_gen, *level, 1); |
3078 | BUG_ON(ret); | 3170 | BUG_ON(ret); |
3171 | if (path->locks[*level]) { | ||
3172 | btrfs_tree_unlock(path->nodes[*level]); | ||
3173 | path->locks[*level] = 0; | ||
3174 | } | ||
3079 | free_extent_buffer(path->nodes[*level]); | 3175 | free_extent_buffer(path->nodes[*level]); |
3080 | path->nodes[*level] = NULL; | 3176 | path->nodes[*level] = NULL; |
3081 | *level = i + 1; | 3177 | *level = i + 1; |
@@ -3145,7 +3241,8 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
3145 | if (wret < 0) | 3241 | if (wret < 0) |
3146 | ret = wret; | 3242 | ret = wret; |
3147 | 3243 | ||
3148 | wret = walk_up_tree(trans, root, path, &level); | 3244 | wret = walk_up_tree(trans, root, path, &level, |
3245 | BTRFS_MAX_LEVEL); | ||
3149 | if (wret > 0) | 3246 | if (wret > 0) |
3150 | break; | 3247 | break; |
3151 | if (wret < 0) | 3248 | if (wret < 0) |
@@ -3168,6 +3265,50 @@ out: | |||
3168 | return ret; | 3265 | return ret; |
3169 | } | 3266 | } |
3170 | 3267 | ||
3268 | int btrfs_drop_subtree(struct btrfs_trans_handle *trans, | ||
3269 | struct btrfs_root *root, | ||
3270 | struct extent_buffer *node, | ||
3271 | struct extent_buffer *parent) | ||
3272 | { | ||
3273 | struct btrfs_path *path; | ||
3274 | int level; | ||
3275 | int parent_level; | ||
3276 | int ret = 0; | ||
3277 | int wret; | ||
3278 | |||
3279 | path = btrfs_alloc_path(); | ||
3280 | BUG_ON(!path); | ||
3281 | |||
3282 | BUG_ON(!btrfs_tree_locked(parent)); | ||
3283 | parent_level = btrfs_header_level(parent); | ||
3284 | extent_buffer_get(parent); | ||
3285 | path->nodes[parent_level] = parent; | ||
3286 | path->slots[parent_level] = btrfs_header_nritems(parent); | ||
3287 | |||
3288 | BUG_ON(!btrfs_tree_locked(node)); | ||
3289 | level = btrfs_header_level(node); | ||
3290 | extent_buffer_get(node); | ||
3291 | path->nodes[level] = node; | ||
3292 | path->slots[level] = 0; | ||
3293 | |||
3294 | while (1) { | ||
3295 | wret = walk_down_subtree(trans, root, path, &level); | ||
3296 | if (wret < 0) | ||
3297 | ret = wret; | ||
3298 | if (wret != 0) | ||
3299 | break; | ||
3300 | |||
3301 | wret = walk_up_tree(trans, root, path, &level, parent_level); | ||
3302 | if (wret < 0) | ||
3303 | ret = wret; | ||
3304 | if (wret != 0) | ||
3305 | break; | ||
3306 | } | ||
3307 | |||
3308 | btrfs_free_path(path); | ||
3309 | return ret; | ||
3310 | } | ||
3311 | |||
3171 | static unsigned long calc_ra(unsigned long start, unsigned long last, | 3312 | static unsigned long calc_ra(unsigned long start, unsigned long last, |
3172 | unsigned long nr) | 3313 | unsigned long nr) |
3173 | { | 3314 | { |
@@ -3312,6 +3453,10 @@ struct btrfs_ref_path { | |||
3312 | u32 num_refs; | 3453 | u32 num_refs; |
3313 | int lowest_level; | 3454 | int lowest_level; |
3314 | int current_level; | 3455 | int current_level; |
3456 | int shared_level; | ||
3457 | |||
3458 | struct btrfs_key node_keys[BTRFS_MAX_LEVEL]; | ||
3459 | u64 new_nodes[BTRFS_MAX_LEVEL]; | ||
3315 | }; | 3460 | }; |
3316 | 3461 | ||
3317 | struct disk_extent { | 3462 | struct disk_extent { |
@@ -3360,6 +3505,7 @@ static int noinline __next_ref_path(struct btrfs_trans_handle *trans, | |||
3360 | if (first_time) { | 3505 | if (first_time) { |
3361 | ref_path->lowest_level = -1; | 3506 | ref_path->lowest_level = -1; |
3362 | ref_path->current_level = -1; | 3507 | ref_path->current_level = -1; |
3508 | ref_path->shared_level = -1; | ||
3363 | goto walk_up; | 3509 | goto walk_up; |
3364 | } | 3510 | } |
3365 | walk_down: | 3511 | walk_down: |
@@ -3403,8 +3549,11 @@ walk_down: | |||
3403 | 3549 | ||
3404 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 3550 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
3405 | if (found_key.objectid == bytenr && | 3551 | if (found_key.objectid == bytenr && |
3406 | found_key.type == BTRFS_EXTENT_REF_KEY) | 3552 | found_key.type == BTRFS_EXTENT_REF_KEY) { |
3553 | if (level < ref_path->shared_level) | ||
3554 | ref_path->shared_level = level; | ||
3407 | goto found; | 3555 | goto found; |
3556 | } | ||
3408 | next: | 3557 | next: |
3409 | level--; | 3558 | level--; |
3410 | btrfs_release_path(extent_root, path); | 3559 | btrfs_release_path(extent_root, path); |
@@ -3992,51 +4141,6 @@ out: | |||
3992 | return ret; | 4141 | return ret; |
3993 | } | 4142 | } |
3994 | 4143 | ||
3995 | int btrfs_add_reloc_mapping(struct btrfs_root *root, u64 orig_bytenr, | ||
3996 | u64 num_bytes, u64 new_bytenr) | ||
3997 | { | ||
3998 | set_extent_bits(&root->fs_info->reloc_mapping_tree, | ||
3999 | orig_bytenr, orig_bytenr + num_bytes - 1, | ||
4000 | EXTENT_LOCKED, GFP_NOFS); | ||
4001 | set_state_private(&root->fs_info->reloc_mapping_tree, | ||
4002 | orig_bytenr, new_bytenr); | ||
4003 | return 0; | ||
4004 | } | ||
4005 | |||
4006 | int btrfs_get_reloc_mapping(struct btrfs_root *root, u64 orig_bytenr, | ||
4007 | u64 num_bytes, u64 *new_bytenr) | ||
4008 | { | ||
4009 | u64 bytenr; | ||
4010 | u64 cur_bytenr = orig_bytenr; | ||
4011 | u64 prev_bytenr = orig_bytenr; | ||
4012 | int ret; | ||
4013 | |||
4014 | while (1) { | ||
4015 | ret = get_state_private(&root->fs_info->reloc_mapping_tree, | ||
4016 | cur_bytenr, &bytenr); | ||
4017 | if (ret) | ||
4018 | break; | ||
4019 | prev_bytenr = cur_bytenr; | ||
4020 | cur_bytenr = bytenr; | ||
4021 | } | ||
4022 | |||
4023 | if (orig_bytenr == cur_bytenr) | ||
4024 | return -ENOENT; | ||
4025 | |||
4026 | if (prev_bytenr != orig_bytenr) { | ||
4027 | set_state_private(&root->fs_info->reloc_mapping_tree, | ||
4028 | orig_bytenr, cur_bytenr); | ||
4029 | } | ||
4030 | *new_bytenr = cur_bytenr; | ||
4031 | return 0; | ||
4032 | } | ||
4033 | |||
4034 | void btrfs_free_reloc_mappings(struct btrfs_root *root) | ||
4035 | { | ||
4036 | clear_extent_bits(&root->fs_info->reloc_mapping_tree, | ||
4037 | 0, (u64)-1, -1, GFP_NOFS); | ||
4038 | } | ||
4039 | |||
4040 | int btrfs_reloc_tree_cache_ref(struct btrfs_trans_handle *trans, | 4144 | int btrfs_reloc_tree_cache_ref(struct btrfs_trans_handle *trans, |
4041 | struct btrfs_root *root, | 4145 | struct btrfs_root *root, |
4042 | struct extent_buffer *buf, u64 orig_start) | 4146 | struct extent_buffer *buf, u64 orig_start) |
@@ -4222,15 +4326,30 @@ static int noinline replace_extents_in_leaf(struct btrfs_trans_handle *trans, | |||
4222 | return 0; | 4326 | return 0; |
4223 | } | 4327 | } |
4224 | 4328 | ||
4225 | int btrfs_free_reloc_root(struct btrfs_root *root) | 4329 | int btrfs_free_reloc_root(struct btrfs_trans_handle *trans, |
4330 | struct btrfs_root *root) | ||
4226 | { | 4331 | { |
4227 | struct btrfs_root *reloc_root; | 4332 | struct btrfs_root *reloc_root; |
4333 | int ret; | ||
4228 | 4334 | ||
4229 | if (root->reloc_root) { | 4335 | if (root->reloc_root) { |
4230 | reloc_root = root->reloc_root; | 4336 | reloc_root = root->reloc_root; |
4231 | root->reloc_root = NULL; | 4337 | root->reloc_root = NULL; |
4232 | list_add(&reloc_root->dead_list, | 4338 | list_add(&reloc_root->dead_list, |
4233 | &root->fs_info->dead_reloc_roots); | 4339 | &root->fs_info->dead_reloc_roots); |
4340 | |||
4341 | btrfs_set_root_bytenr(&reloc_root->root_item, | ||
4342 | reloc_root->node->start); | ||
4343 | btrfs_set_root_level(&root->root_item, | ||
4344 | btrfs_header_level(reloc_root->node)); | ||
4345 | memset(&reloc_root->root_item.drop_progress, 0, | ||
4346 | sizeof(struct btrfs_disk_key)); | ||
4347 | reloc_root->root_item.drop_level = 0; | ||
4348 | |||
4349 | ret = btrfs_update_root(trans, root->fs_info->tree_root, | ||
4350 | &reloc_root->root_key, | ||
4351 | &reloc_root->root_item); | ||
4352 | BUG_ON(ret); | ||
4234 | } | 4353 | } |
4235 | return 0; | 4354 | return 0; |
4236 | } | 4355 | } |
@@ -4356,8 +4475,6 @@ static int noinline init_reloc_tree(struct btrfs_trans_handle *trans, | |||
4356 | btrfs_set_root_refs(root_item, 0); | 4475 | btrfs_set_root_refs(root_item, 0); |
4357 | btrfs_set_root_bytenr(root_item, eb->start); | 4476 | btrfs_set_root_bytenr(root_item, eb->start); |
4358 | btrfs_set_root_level(root_item, btrfs_header_level(eb)); | 4477 | btrfs_set_root_level(root_item, btrfs_header_level(eb)); |
4359 | memset(&root_item->drop_progress, 0, sizeof(root_item->drop_progress)); | ||
4360 | root_item->drop_level = 0; | ||
4361 | 4478 | ||
4362 | btrfs_tree_unlock(eb); | 4479 | btrfs_tree_unlock(eb); |
4363 | free_extent_buffer(eb); | 4480 | free_extent_buffer(eb); |
@@ -4382,15 +4499,19 @@ static int noinline init_reloc_tree(struct btrfs_trans_handle *trans, | |||
4382 | * Core function of space balance. | 4499 | * Core function of space balance. |
4383 | * | 4500 | * |
4384 | * The idea is using reloc trees to relocate tree blocks in reference | 4501 | * The idea is using reloc trees to relocate tree blocks in reference |
4385 | * counted roots. There is one reloc tree for each subvol, all reloc | 4502 | * counted roots. There is one reloc tree for each subvol, and all |
4386 | * trees share same key objectid. Reloc trees are snapshots of the | 4503 | * reloc trees share same root key objectid. Reloc trees are snapshots |
4387 | * latest committed roots (subvol root->commit_root). To relocate a tree | 4504 | * of the latest committed roots of subvols (root->commit_root). |
4388 | * block referenced by a subvol, the code COW the block through the reloc | 4505 | * |
4389 | * tree, then update pointer in the subvol to point to the new block. | 4506 | * To relocate a tree block referenced by a subvol, there are two steps. |
4390 | * Since all reloc trees share same key objectid, we can easily do special | 4507 | * COW the block through subvol's reloc tree, then update block pointer |
4391 | * handing to share tree blocks between reloc trees. Once a tree block has | 4508 | * in the subvol to point to the new block. Since all reloc trees share |
4392 | * been COWed in one reloc tree, we can use the result when the same block | 4509 | * same root key objectid, doing special handing for tree blocks owned |
4393 | * is COWed again through other reloc trees. | 4510 | * by them is easy. Once a tree block has been COWed in one reloc tree, |
4511 | * we can use the resulting new block directly when the same block is | ||
4512 | * required to COW again through other reloc trees. By this way, relocated | ||
4513 | * tree blocks are shared between reloc trees, so they are also shared | ||
4514 | * between subvols. | ||
4394 | */ | 4515 | */ |
4395 | static int noinline relocate_one_path(struct btrfs_trans_handle *trans, | 4516 | static int noinline relocate_one_path(struct btrfs_trans_handle *trans, |
4396 | struct btrfs_root *root, | 4517 | struct btrfs_root *root, |
@@ -4405,15 +4526,14 @@ static int noinline relocate_one_path(struct btrfs_trans_handle *trans, | |||
4405 | struct btrfs_key *keys; | 4526 | struct btrfs_key *keys; |
4406 | u64 *nodes; | 4527 | u64 *nodes; |
4407 | int level; | 4528 | int level; |
4408 | int lowest_merge; | 4529 | int shared_level; |
4409 | int lowest_level = 0; | 4530 | int lowest_level = 0; |
4410 | int update_refs; | ||
4411 | int ret; | 4531 | int ret; |
4412 | 4532 | ||
4413 | if (ref_path->owner_objectid < BTRFS_FIRST_FREE_OBJECTID) | 4533 | if (ref_path->owner_objectid < BTRFS_FIRST_FREE_OBJECTID) |
4414 | lowest_level = ref_path->owner_objectid; | 4534 | lowest_level = ref_path->owner_objectid; |
4415 | 4535 | ||
4416 | if (is_cowonly_root(ref_path->root_objectid)) { | 4536 | if (!root->ref_cows) { |
4417 | path->lowest_level = lowest_level; | 4537 | path->lowest_level = lowest_level; |
4418 | ret = btrfs_search_slot(trans, root, first_key, path, 0, 1); | 4538 | ret = btrfs_search_slot(trans, root, first_key, path, 0, 1); |
4419 | BUG_ON(ret < 0); | 4539 | BUG_ON(ret < 0); |
@@ -4422,91 +4542,49 @@ static int noinline relocate_one_path(struct btrfs_trans_handle *trans, | |||
4422 | return 0; | 4542 | return 0; |
4423 | } | 4543 | } |
4424 | 4544 | ||
4425 | keys = kzalloc(sizeof(*keys) * BTRFS_MAX_LEVEL, GFP_NOFS); | ||
4426 | BUG_ON(!keys); | ||
4427 | nodes = kzalloc(sizeof(*nodes) * BTRFS_MAX_LEVEL, GFP_NOFS); | ||
4428 | BUG_ON(!nodes); | ||
4429 | |||
4430 | mutex_lock(&root->fs_info->tree_reloc_mutex); | 4545 | mutex_lock(&root->fs_info->tree_reloc_mutex); |
4431 | ret = init_reloc_tree(trans, root); | 4546 | ret = init_reloc_tree(trans, root); |
4432 | BUG_ON(ret); | 4547 | BUG_ON(ret); |
4433 | reloc_root = root->reloc_root; | 4548 | reloc_root = root->reloc_root; |
4434 | 4549 | ||
4435 | path->lowest_level = lowest_level; | 4550 | shared_level = ref_path->shared_level; |
4436 | ret = btrfs_search_slot(trans, reloc_root, first_key, path, 0, 0); | 4551 | ref_path->shared_level = BTRFS_MAX_LEVEL - 1; |
4437 | BUG_ON(ret); | ||
4438 | /* | ||
4439 | * get relocation mapping for tree blocks in the path | ||
4440 | */ | ||
4441 | lowest_merge = BTRFS_MAX_LEVEL; | ||
4442 | for (level = BTRFS_MAX_LEVEL - 1; level >= lowest_level; level--) { | ||
4443 | u64 new_bytenr; | ||
4444 | eb = path->nodes[level]; | ||
4445 | if (!eb || eb == reloc_root->node) | ||
4446 | continue; | ||
4447 | ret = btrfs_get_reloc_mapping(reloc_root, eb->start, eb->len, | ||
4448 | &new_bytenr); | ||
4449 | if (ret) | ||
4450 | continue; | ||
4451 | if (level == 0) | ||
4452 | btrfs_item_key_to_cpu(eb, &keys[level], 0); | ||
4453 | else | ||
4454 | btrfs_node_key_to_cpu(eb, &keys[level], 0); | ||
4455 | nodes[level] = new_bytenr; | ||
4456 | lowest_merge = level; | ||
4457 | } | ||
4458 | 4552 | ||
4459 | update_refs = 0; | 4553 | keys = ref_path->node_keys; |
4460 | if (ref_path->owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) { | 4554 | nodes = ref_path->new_nodes; |
4461 | eb = path->nodes[0]; | 4555 | memset(&keys[shared_level + 1], 0, |
4462 | if (btrfs_header_generation(eb) < trans->transid) | 4556 | sizeof(*keys) * (BTRFS_MAX_LEVEL - shared_level - 1)); |
4463 | update_refs = 1; | 4557 | memset(&nodes[shared_level + 1], 0, |
4464 | } | 4558 | sizeof(*nodes) * (BTRFS_MAX_LEVEL - shared_level - 1)); |
4465 | 4559 | ||
4466 | btrfs_release_path(reloc_root, path); | 4560 | if (nodes[lowest_level] == 0) { |
4467 | /* | 4561 | path->lowest_level = lowest_level; |
4468 | * merge tree blocks that already relocated in other reloc trees | 4562 | ret = btrfs_search_slot(trans, reloc_root, first_key, path, |
4469 | */ | 4563 | 0, 1); |
4470 | if (lowest_merge != BTRFS_MAX_LEVEL) { | 4564 | BUG_ON(ret); |
4565 | for (level = lowest_level; level < BTRFS_MAX_LEVEL; level++) { | ||
4566 | eb = path->nodes[level]; | ||
4567 | if (!eb || eb == reloc_root->node) | ||
4568 | break; | ||
4569 | nodes[level] = eb->start; | ||
4570 | if (level == 0) | ||
4571 | btrfs_item_key_to_cpu(eb, &keys[level], 0); | ||
4572 | else | ||
4573 | btrfs_node_key_to_cpu(eb, &keys[level], 0); | ||
4574 | } | ||
4575 | if (ref_path->owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) { | ||
4576 | eb = path->nodes[0]; | ||
4577 | ret = replace_extents_in_leaf(trans, reloc_root, eb, | ||
4578 | group, reloc_inode); | ||
4579 | BUG_ON(ret); | ||
4580 | } | ||
4581 | btrfs_release_path(reloc_root, path); | ||
4582 | } else { | ||
4471 | ret = btrfs_merge_path(trans, reloc_root, keys, nodes, | 4583 | ret = btrfs_merge_path(trans, reloc_root, keys, nodes, |
4472 | lowest_merge); | 4584 | lowest_level); |
4473 | BUG_ON(ret < 0); | ||
4474 | } | ||
4475 | /* | ||
4476 | * cow any tree blocks that still haven't been relocated | ||
4477 | */ | ||
4478 | ret = btrfs_search_slot(trans, reloc_root, first_key, path, 0, 1); | ||
4479 | BUG_ON(ret); | ||
4480 | /* | ||
4481 | * if we are relocating data block group, update extent pointers | ||
4482 | * in the newly created tree leaf. | ||
4483 | */ | ||
4484 | eb = path->nodes[0]; | ||
4485 | if (update_refs && nodes[0] != eb->start) { | ||
4486 | ret = replace_extents_in_leaf(trans, reloc_root, eb, group, | ||
4487 | reloc_inode); | ||
4488 | BUG_ON(ret); | 4585 | BUG_ON(ret); |
4489 | } | 4586 | } |
4490 | 4587 | ||
4491 | memset(keys, 0, sizeof(*keys) * BTRFS_MAX_LEVEL); | ||
4492 | memset(nodes, 0, sizeof(*nodes) * BTRFS_MAX_LEVEL); | ||
4493 | for (level = BTRFS_MAX_LEVEL - 1; level >= lowest_level; level--) { | ||
4494 | eb = path->nodes[level]; | ||
4495 | if (!eb || eb == reloc_root->node) | ||
4496 | continue; | ||
4497 | BUG_ON(btrfs_header_owner(eb) != BTRFS_TREE_RELOC_OBJECTID); | ||
4498 | nodes[level] = eb->start; | ||
4499 | if (level == 0) | ||
4500 | btrfs_item_key_to_cpu(eb, &keys[level], 0); | ||
4501 | else | ||
4502 | btrfs_node_key_to_cpu(eb, &keys[level], 0); | ||
4503 | } | ||
4504 | |||
4505 | if (ref_path->owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) { | ||
4506 | eb = path->nodes[0]; | ||
4507 | extent_buffer_get(eb); | ||
4508 | } | ||
4509 | btrfs_release_path(reloc_root, path); | ||
4510 | /* | 4588 | /* |
4511 | * replace tree blocks in the fs tree with tree blocks in | 4589 | * replace tree blocks in the fs tree with tree blocks in |
4512 | * the reloc tree. | 4590 | * the reloc tree. |
@@ -4515,15 +4593,19 @@ static int noinline relocate_one_path(struct btrfs_trans_handle *trans, | |||
4515 | BUG_ON(ret < 0); | 4593 | BUG_ON(ret < 0); |
4516 | 4594 | ||
4517 | if (ref_path->owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) { | 4595 | if (ref_path->owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) { |
4596 | ret = btrfs_search_slot(trans, reloc_root, first_key, path, | ||
4597 | 0, 0); | ||
4598 | BUG_ON(ret); | ||
4599 | extent_buffer_get(path->nodes[0]); | ||
4600 | eb = path->nodes[0]; | ||
4601 | btrfs_release_path(reloc_root, path); | ||
4518 | ret = invalidate_extent_cache(reloc_root, eb, group, root); | 4602 | ret = invalidate_extent_cache(reloc_root, eb, group, root); |
4519 | BUG_ON(ret); | 4603 | BUG_ON(ret); |
4520 | free_extent_buffer(eb); | 4604 | free_extent_buffer(eb); |
4521 | } | 4605 | } |
4522 | mutex_unlock(&root->fs_info->tree_reloc_mutex); | ||
4523 | 4606 | ||
4607 | mutex_unlock(&root->fs_info->tree_reloc_mutex); | ||
4524 | path->lowest_level = 0; | 4608 | path->lowest_level = 0; |
4525 | kfree(nodes); | ||
4526 | kfree(keys); | ||
4527 | return 0; | 4609 | return 0; |
4528 | } | 4610 | } |
4529 | 4611 | ||