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