aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-log.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r--fs/btrfs/tree-log.c209
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,
3194static noinline int copy_items(struct btrfs_trans_handle *trans, 3195static 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 }
3380fill_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