diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
| -rw-r--r-- | fs/btrfs/tree-log.c | 209 |
1 files changed, 187 insertions, 22 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 9f7fc51ca334..39d83da03e03 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
| @@ -570,7 +570,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | |||
| 570 | if (btrfs_file_extent_disk_bytenr(eb, item) == 0) | 570 | if (btrfs_file_extent_disk_bytenr(eb, item) == 0) |
| 571 | nbytes = 0; | 571 | nbytes = 0; |
| 572 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | 572 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { |
| 573 | size = btrfs_file_extent_inline_len(eb, item); | 573 | size = btrfs_file_extent_inline_len(eb, slot, item); |
| 574 | nbytes = btrfs_file_extent_ram_bytes(eb, item); | 574 | nbytes = btrfs_file_extent_ram_bytes(eb, item); |
| 575 | extent_end = ALIGN(start + size, root->sectorsize); | 575 | extent_end = ALIGN(start + size, root->sectorsize); |
| 576 | } else { | 576 | } else { |
| @@ -1238,7 +1238,8 @@ static int insert_orphan_item(struct btrfs_trans_handle *trans, | |||
| 1238 | struct btrfs_root *root, u64 offset) | 1238 | struct btrfs_root *root, u64 offset) |
| 1239 | { | 1239 | { |
| 1240 | int ret; | 1240 | int ret; |
| 1241 | ret = btrfs_find_orphan_item(root, offset); | 1241 | ret = btrfs_find_item(root, NULL, BTRFS_ORPHAN_OBJECTID, |
| 1242 | offset, BTRFS_ORPHAN_ITEM_KEY, NULL); | ||
| 1242 | if (ret > 0) | 1243 | if (ret > 0) |
| 1243 | ret = btrfs_insert_orphan_item(trans, root, offset); | 1244 | ret = btrfs_insert_orphan_item(trans, root, offset); |
| 1244 | return ret; | 1245 | return ret; |
| @@ -3194,7 +3195,7 @@ static int log_inode_item(struct btrfs_trans_handle *trans, | |||
| 3194 | static noinline int copy_items(struct btrfs_trans_handle *trans, | 3195 | static noinline int copy_items(struct btrfs_trans_handle *trans, |
| 3195 | struct inode *inode, | 3196 | struct inode *inode, |
| 3196 | struct btrfs_path *dst_path, | 3197 | struct btrfs_path *dst_path, |
| 3197 | struct extent_buffer *src, | 3198 | struct btrfs_path *src_path, u64 *last_extent, |
| 3198 | int start_slot, int nr, int inode_only) | 3199 | int start_slot, int nr, int inode_only) |
| 3199 | { | 3200 | { |
| 3200 | unsigned long src_offset; | 3201 | unsigned long src_offset; |
| @@ -3202,6 +3203,8 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
| 3202 | struct btrfs_root *log = BTRFS_I(inode)->root->log_root; | 3203 | struct btrfs_root *log = BTRFS_I(inode)->root->log_root; |
| 3203 | struct btrfs_file_extent_item *extent; | 3204 | struct btrfs_file_extent_item *extent; |
| 3204 | struct btrfs_inode_item *inode_item; | 3205 | struct btrfs_inode_item *inode_item; |
| 3206 | struct extent_buffer *src = src_path->nodes[0]; | ||
| 3207 | struct btrfs_key first_key, last_key, key; | ||
| 3205 | int ret; | 3208 | int ret; |
| 3206 | struct btrfs_key *ins_keys; | 3209 | struct btrfs_key *ins_keys; |
| 3207 | u32 *ins_sizes; | 3210 | u32 *ins_sizes; |
| @@ -3209,6 +3212,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
| 3209 | int i; | 3212 | int i; |
| 3210 | struct list_head ordered_sums; | 3213 | struct list_head ordered_sums; |
| 3211 | int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | 3214 | int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; |
| 3215 | bool has_extents = false; | ||
| 3216 | bool need_find_last_extent = (*last_extent == 0); | ||
| 3217 | bool done = false; | ||
| 3212 | 3218 | ||
| 3213 | INIT_LIST_HEAD(&ordered_sums); | 3219 | INIT_LIST_HEAD(&ordered_sums); |
| 3214 | 3220 | ||
| @@ -3217,6 +3223,8 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
| 3217 | if (!ins_data) | 3223 | if (!ins_data) |
| 3218 | return -ENOMEM; | 3224 | return -ENOMEM; |
| 3219 | 3225 | ||
| 3226 | first_key.objectid = (u64)-1; | ||
| 3227 | |||
| 3220 | ins_sizes = (u32 *)ins_data; | 3228 | ins_sizes = (u32 *)ins_data; |
| 3221 | ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32)); | 3229 | ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32)); |
| 3222 | 3230 | ||
| @@ -3237,6 +3245,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
| 3237 | 3245 | ||
| 3238 | src_offset = btrfs_item_ptr_offset(src, start_slot + i); | 3246 | src_offset = btrfs_item_ptr_offset(src, start_slot + i); |
| 3239 | 3247 | ||
| 3248 | if ((i == (nr - 1))) | ||
| 3249 | last_key = ins_keys[i]; | ||
| 3250 | |||
| 3240 | if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) { | 3251 | if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) { |
| 3241 | inode_item = btrfs_item_ptr(dst_path->nodes[0], | 3252 | inode_item = btrfs_item_ptr(dst_path->nodes[0], |
| 3242 | dst_path->slots[0], | 3253 | dst_path->slots[0], |
| @@ -3248,6 +3259,21 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
| 3248 | src_offset, ins_sizes[i]); | 3259 | src_offset, ins_sizes[i]); |
| 3249 | } | 3260 | } |
| 3250 | 3261 | ||
| 3262 | /* | ||
| 3263 | * We set need_find_last_extent here in case we know we were | ||
| 3264 | * processing other items and then walk into the first extent in | ||
| 3265 | * the inode. If we don't hit an extent then nothing changes, | ||
| 3266 | * we'll do the last search the next time around. | ||
| 3267 | */ | ||
| 3268 | if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY) { | ||
| 3269 | has_extents = true; | ||
| 3270 | if (need_find_last_extent && | ||
| 3271 | first_key.objectid == (u64)-1) | ||
| 3272 | first_key = ins_keys[i]; | ||
| 3273 | } else { | ||
| 3274 | need_find_last_extent = false; | ||
| 3275 | } | ||
| 3276 | |||
| 3251 | /* take a reference on file data extents so that truncates | 3277 | /* take a reference on file data extents so that truncates |
| 3252 | * or deletes of this inode don't have to relog the inode | 3278 | * or deletes of this inode don't have to relog the inode |
| 3253 | * again | 3279 | * again |
| @@ -3312,6 +3338,128 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
| 3312 | list_del(&sums->list); | 3338 | list_del(&sums->list); |
| 3313 | kfree(sums); | 3339 | kfree(sums); |
| 3314 | } | 3340 | } |
| 3341 | |||
| 3342 | if (!has_extents) | ||
| 3343 | return ret; | ||
| 3344 | |||
| 3345 | /* | ||
| 3346 | * Because we use btrfs_search_forward we could skip leaves that were | ||
| 3347 | * not modified and then assume *last_extent is valid when it really | ||
| 3348 | * isn't. So back up to the previous leaf and read the end of the last | ||
| 3349 | * extent before we go and fill in holes. | ||
| 3350 | */ | ||
| 3351 | if (need_find_last_extent) { | ||
| 3352 | u64 len; | ||
| 3353 | |||
| 3354 | ret = btrfs_prev_leaf(BTRFS_I(inode)->root, src_path); | ||
| 3355 | if (ret < 0) | ||
| 3356 | return ret; | ||
| 3357 | if (ret) | ||
| 3358 | goto fill_holes; | ||
| 3359 | if (src_path->slots[0]) | ||
| 3360 | src_path->slots[0]--; | ||
| 3361 | src = src_path->nodes[0]; | ||
| 3362 | btrfs_item_key_to_cpu(src, &key, src_path->slots[0]); | ||
| 3363 | if (key.objectid != btrfs_ino(inode) || | ||
| 3364 | key.type != BTRFS_EXTENT_DATA_KEY) | ||
| 3365 | goto fill_holes; | ||
| 3366 | extent = btrfs_item_ptr(src, src_path->slots[0], | ||
| 3367 | struct btrfs_file_extent_item); | ||
| 3368 | if (btrfs_file_extent_type(src, extent) == | ||
| 3369 | BTRFS_FILE_EXTENT_INLINE) { | ||
| 3370 | len = btrfs_file_extent_inline_len(src, | ||
| 3371 | src_path->slots[0], | ||
| 3372 | extent); | ||
| 3373 | *last_extent = ALIGN(key.offset + len, | ||
| 3374 | log->sectorsize); | ||
| 3375 | } else { | ||
| 3376 | len = btrfs_file_extent_num_bytes(src, extent); | ||
| 3377 | *last_extent = key.offset + len; | ||
| 3378 | } | ||
| 3379 | } | ||
| 3380 | fill_holes: | ||
| 3381 | /* So we did prev_leaf, now we need to move to the next leaf, but a few | ||
| 3382 | * things could have happened | ||
| 3383 | * | ||
| 3384 | * 1) A merge could have happened, so we could currently be on a leaf | ||
| 3385 | * that holds what we were copying in the first place. | ||
| 3386 | * 2) A split could have happened, and now not all of the items we want | ||
| 3387 | * are on the same leaf. | ||
| 3388 | * | ||
| 3389 | * So we need to adjust how we search for holes, we need to drop the | ||
| 3390 | * path and re-search for the first extent key we found, and then walk | ||
| 3391 | * forward until we hit the last one we copied. | ||
| 3392 | */ | ||
| 3393 | if (need_find_last_extent) { | ||
| 3394 | /* btrfs_prev_leaf could return 1 without releasing the path */ | ||
| 3395 | btrfs_release_path(src_path); | ||
| 3396 | ret = btrfs_search_slot(NULL, BTRFS_I(inode)->root, &first_key, | ||
| 3397 | src_path, 0, 0); | ||
| 3398 | if (ret < 0) | ||
| 3399 | return ret; | ||
| 3400 | ASSERT(ret == 0); | ||
| 3401 | src = src_path->nodes[0]; | ||
| 3402 | i = src_path->slots[0]; | ||
| 3403 | } else { | ||
| 3404 | i = start_slot; | ||
| 3405 | } | ||
| 3406 | |||
| 3407 | /* | ||
| 3408 | * Ok so here we need to go through and fill in any holes we may have | ||
| 3409 | * to make sure that holes are punched for those areas in case they had | ||
| 3410 | * extents previously. | ||
| 3411 | */ | ||
| 3412 | while (!done) { | ||
| 3413 | u64 offset, len; | ||
| 3414 | u64 extent_end; | ||
| 3415 | |||
| 3416 | if (i >= btrfs_header_nritems(src_path->nodes[0])) { | ||
| 3417 | ret = btrfs_next_leaf(BTRFS_I(inode)->root, src_path); | ||
| 3418 | if (ret < 0) | ||
| 3419 | return ret; | ||
| 3420 | ASSERT(ret == 0); | ||
| 3421 | src = src_path->nodes[0]; | ||
| 3422 | i = 0; | ||
| 3423 | } | ||
| 3424 | |||
| 3425 | btrfs_item_key_to_cpu(src, &key, i); | ||
| 3426 | if (!btrfs_comp_cpu_keys(&key, &last_key)) | ||
| 3427 | done = true; | ||
| 3428 | if (key.objectid != btrfs_ino(inode) || | ||
| 3429 | key.type != BTRFS_EXTENT_DATA_KEY) { | ||
| 3430 | i++; | ||
| 3431 | continue; | ||
| 3432 | } | ||
| 3433 | extent = btrfs_item_ptr(src, i, struct btrfs_file_extent_item); | ||
| 3434 | if (btrfs_file_extent_type(src, extent) == | ||
| 3435 | BTRFS_FILE_EXTENT_INLINE) { | ||
| 3436 | len = btrfs_file_extent_inline_len(src, i, extent); | ||
| 3437 | extent_end = ALIGN(key.offset + len, log->sectorsize); | ||
| 3438 | } else { | ||
| 3439 | len = btrfs_file_extent_num_bytes(src, extent); | ||
| 3440 | extent_end = key.offset + len; | ||
| 3441 | } | ||
| 3442 | i++; | ||
| 3443 | |||
| 3444 | if (*last_extent == key.offset) { | ||
| 3445 | *last_extent = extent_end; | ||
| 3446 | continue; | ||
| 3447 | } | ||
| 3448 | offset = *last_extent; | ||
| 3449 | len = key.offset - *last_extent; | ||
| 3450 | ret = btrfs_insert_file_extent(trans, log, btrfs_ino(inode), | ||
| 3451 | offset, 0, 0, len, 0, len, 0, | ||
| 3452 | 0, 0); | ||
| 3453 | if (ret) | ||
| 3454 | break; | ||
| 3455 | *last_extent = offset + len; | ||
| 3456 | } | ||
| 3457 | /* | ||
| 3458 | * Need to let the callers know we dropped the path so they should | ||
| 3459 | * re-search. | ||
| 3460 | */ | ||
| 3461 | if (!ret && need_find_last_extent) | ||
| 3462 | ret = 1; | ||
| 3315 | return ret; | 3463 | return ret; |
| 3316 | } | 3464 | } |
| 3317 | 3465 | ||
| @@ -3349,21 +3497,27 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
| 3349 | int ret; | 3497 | int ret; |
| 3350 | int index = log->log_transid % 2; | 3498 | int index = log->log_transid % 2; |
| 3351 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | 3499 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; |
| 3352 | 3500 | int extent_inserted = 0; | |
| 3353 | ret = __btrfs_drop_extents(trans, log, inode, path, em->start, | ||
| 3354 | em->start + em->len, NULL, 0); | ||
| 3355 | if (ret) | ||
| 3356 | return ret; | ||
| 3357 | 3501 | ||
| 3358 | INIT_LIST_HEAD(&ordered_sums); | 3502 | INIT_LIST_HEAD(&ordered_sums); |
| 3359 | btrfs_init_map_token(&token); | 3503 | btrfs_init_map_token(&token); |
| 3360 | key.objectid = btrfs_ino(inode); | ||
| 3361 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
| 3362 | key.offset = em->start; | ||
| 3363 | 3504 | ||
| 3364 | ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*fi)); | 3505 | ret = __btrfs_drop_extents(trans, log, inode, path, em->start, |
| 3506 | em->start + em->len, NULL, 0, 1, | ||
| 3507 | sizeof(*fi), &extent_inserted); | ||
| 3365 | if (ret) | 3508 | if (ret) |
| 3366 | return ret; | 3509 | return ret; |
| 3510 | |||
| 3511 | if (!extent_inserted) { | ||
| 3512 | key.objectid = btrfs_ino(inode); | ||
| 3513 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
| 3514 | key.offset = em->start; | ||
| 3515 | |||
| 3516 | ret = btrfs_insert_empty_item(trans, log, path, &key, | ||
| 3517 | sizeof(*fi)); | ||
| 3518 | if (ret) | ||
| 3519 | return ret; | ||
| 3520 | } | ||
| 3367 | leaf = path->nodes[0]; | 3521 | leaf = path->nodes[0]; |
| 3368 | fi = btrfs_item_ptr(leaf, path->slots[0], | 3522 | fi = btrfs_item_ptr(leaf, path->slots[0], |
| 3369 | struct btrfs_file_extent_item); | 3523 | struct btrfs_file_extent_item); |
| @@ -3485,7 +3639,11 @@ again: | |||
| 3485 | * start over after this. | 3639 | * start over after this. |
| 3486 | */ | 3640 | */ |
| 3487 | 3641 | ||
| 3488 | wait_event(ordered->wait, ordered->csum_bytes_left == 0); | 3642 | if (ordered->csum_bytes_left) { |
| 3643 | btrfs_start_ordered_extent(inode, ordered, 0); | ||
| 3644 | wait_event(ordered->wait, | ||
| 3645 | ordered->csum_bytes_left == 0); | ||
| 3646 | } | ||
| 3489 | 3647 | ||
| 3490 | list_for_each_entry(sum, &ordered->list, list) { | 3648 | list_for_each_entry(sum, &ordered->list, list) { |
| 3491 | ret = btrfs_csum_file_blocks(trans, log, sum); | 3649 | ret = btrfs_csum_file_blocks(trans, log, sum); |
| @@ -3630,6 +3788,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
| 3630 | struct btrfs_key max_key; | 3788 | struct btrfs_key max_key; |
| 3631 | struct btrfs_root *log = root->log_root; | 3789 | struct btrfs_root *log = root->log_root; |
| 3632 | struct extent_buffer *src = NULL; | 3790 | struct extent_buffer *src = NULL; |
| 3791 | u64 last_extent = 0; | ||
| 3633 | int err = 0; | 3792 | int err = 0; |
| 3634 | int ret; | 3793 | int ret; |
| 3635 | int nritems; | 3794 | int nritems; |
| @@ -3745,11 +3904,15 @@ again: | |||
| 3745 | goto next_slot; | 3904 | goto next_slot; |
| 3746 | } | 3905 | } |
| 3747 | 3906 | ||
| 3748 | ret = copy_items(trans, inode, dst_path, src, ins_start_slot, | 3907 | ret = copy_items(trans, inode, dst_path, path, &last_extent, |
| 3749 | ins_nr, inode_only); | 3908 | ins_start_slot, ins_nr, inode_only); |
| 3750 | if (ret) { | 3909 | if (ret < 0) { |
| 3751 | err = ret; | 3910 | err = ret; |
| 3752 | goto out_unlock; | 3911 | goto out_unlock; |
| 3912 | } if (ret) { | ||
| 3913 | ins_nr = 0; | ||
| 3914 | btrfs_release_path(path); | ||
| 3915 | continue; | ||
| 3753 | } | 3916 | } |
| 3754 | ins_nr = 1; | 3917 | ins_nr = 1; |
| 3755 | ins_start_slot = path->slots[0]; | 3918 | ins_start_slot = path->slots[0]; |
| @@ -3763,13 +3926,14 @@ next_slot: | |||
| 3763 | goto again; | 3926 | goto again; |
| 3764 | } | 3927 | } |
| 3765 | if (ins_nr) { | 3928 | if (ins_nr) { |
| 3766 | ret = copy_items(trans, inode, dst_path, src, | 3929 | ret = copy_items(trans, inode, dst_path, path, |
| 3767 | ins_start_slot, | 3930 | &last_extent, ins_start_slot, |
| 3768 | ins_nr, inode_only); | 3931 | ins_nr, inode_only); |
| 3769 | if (ret) { | 3932 | if (ret < 0) { |
| 3770 | err = ret; | 3933 | err = ret; |
| 3771 | goto out_unlock; | 3934 | goto out_unlock; |
| 3772 | } | 3935 | } |
| 3936 | ret = 0; | ||
| 3773 | ins_nr = 0; | 3937 | ins_nr = 0; |
| 3774 | } | 3938 | } |
| 3775 | btrfs_release_path(path); | 3939 | btrfs_release_path(path); |
| @@ -3784,12 +3948,13 @@ next_slot: | |||
| 3784 | } | 3948 | } |
| 3785 | } | 3949 | } |
| 3786 | if (ins_nr) { | 3950 | if (ins_nr) { |
| 3787 | ret = copy_items(trans, inode, dst_path, src, ins_start_slot, | 3951 | ret = copy_items(trans, inode, dst_path, path, &last_extent, |
| 3788 | ins_nr, inode_only); | 3952 | ins_start_slot, ins_nr, inode_only); |
| 3789 | if (ret) { | 3953 | if (ret < 0) { |
| 3790 | err = ret; | 3954 | err = ret; |
| 3791 | goto out_unlock; | 3955 | goto out_unlock; |
| 3792 | } | 3956 | } |
| 3957 | ret = 0; | ||
| 3793 | ins_nr = 0; | 3958 | ins_nr = 0; |
| 3794 | } | 3959 | } |
| 3795 | 3960 | ||
