diff options
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 | ||