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.c172
1 files changed, 162 insertions, 10 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 9f7fc51ca334..e7d7a837512a 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3194,7 +3194,7 @@ static int log_inode_item(struct btrfs_trans_handle *trans,
3194static noinline int copy_items(struct btrfs_trans_handle *trans, 3194static noinline int copy_items(struct btrfs_trans_handle *trans,
3195 struct inode *inode, 3195 struct inode *inode,
3196 struct btrfs_path *dst_path, 3196 struct btrfs_path *dst_path,
3197 struct extent_buffer *src, 3197 struct btrfs_path *src_path, u64 *last_extent,
3198 int start_slot, int nr, int inode_only) 3198 int start_slot, int nr, int inode_only)
3199{ 3199{
3200 unsigned long src_offset; 3200 unsigned long src_offset;
@@ -3202,6 +3202,8 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
3202 struct btrfs_root *log = BTRFS_I(inode)->root->log_root; 3202 struct btrfs_root *log = BTRFS_I(inode)->root->log_root;
3203 struct btrfs_file_extent_item *extent; 3203 struct btrfs_file_extent_item *extent;
3204 struct btrfs_inode_item *inode_item; 3204 struct btrfs_inode_item *inode_item;
3205 struct extent_buffer *src = src_path->nodes[0];
3206 struct btrfs_key first_key, last_key, key;
3205 int ret; 3207 int ret;
3206 struct btrfs_key *ins_keys; 3208 struct btrfs_key *ins_keys;
3207 u32 *ins_sizes; 3209 u32 *ins_sizes;
@@ -3209,6 +3211,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
3209 int i; 3211 int i;
3210 struct list_head ordered_sums; 3212 struct list_head ordered_sums;
3211 int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; 3213 int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
3214 bool has_extents = false;
3215 bool need_find_last_extent = (*last_extent == 0);
3216 bool done = false;
3212 3217
3213 INIT_LIST_HEAD(&ordered_sums); 3218 INIT_LIST_HEAD(&ordered_sums);
3214 3219
@@ -3217,6 +3222,8 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
3217 if (!ins_data) 3222 if (!ins_data)
3218 return -ENOMEM; 3223 return -ENOMEM;
3219 3224
3225 first_key.objectid = (u64)-1;
3226
3220 ins_sizes = (u32 *)ins_data; 3227 ins_sizes = (u32 *)ins_data;
3221 ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32)); 3228 ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32));
3222 3229
@@ -3237,6 +3244,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
3237 3244
3238 src_offset = btrfs_item_ptr_offset(src, start_slot + i); 3245 src_offset = btrfs_item_ptr_offset(src, start_slot + i);
3239 3246
3247 if ((i == (nr - 1)))
3248 last_key = ins_keys[i];
3249
3240 if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) { 3250 if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) {
3241 inode_item = btrfs_item_ptr(dst_path->nodes[0], 3251 inode_item = btrfs_item_ptr(dst_path->nodes[0],
3242 dst_path->slots[0], 3252 dst_path->slots[0],
@@ -3248,6 +3258,21 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
3248 src_offset, ins_sizes[i]); 3258 src_offset, ins_sizes[i]);
3249 } 3259 }
3250 3260
3261 /*
3262 * We set need_find_last_extent here in case we know we were
3263 * processing other items and then walk into the first extent in
3264 * the inode. If we don't hit an extent then nothing changes,
3265 * we'll do the last search the next time around.
3266 */
3267 if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY) {
3268 has_extents = true;
3269 if (need_find_last_extent &&
3270 first_key.objectid == (u64)-1)
3271 first_key = ins_keys[i];
3272 } else {
3273 need_find_last_extent = false;
3274 }
3275
3251 /* take a reference on file data extents so that truncates 3276 /* take a reference on file data extents so that truncates
3252 * or deletes of this inode don't have to relog the inode 3277 * or deletes of this inode don't have to relog the inode
3253 * again 3278 * again
@@ -3312,6 +3337,126 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
3312 list_del(&sums->list); 3337 list_del(&sums->list);
3313 kfree(sums); 3338 kfree(sums);
3314 } 3339 }
3340
3341 if (!has_extents)
3342 return ret;
3343
3344 /*
3345 * Because we use btrfs_search_forward we could skip leaves that were
3346 * not modified and then assume *last_extent is valid when it really
3347 * isn't. So back up to the previous leaf and read the end of the last
3348 * extent before we go and fill in holes.
3349 */
3350 if (need_find_last_extent) {
3351 u64 len;
3352
3353 ret = btrfs_prev_leaf(BTRFS_I(inode)->root, src_path);
3354 if (ret < 0)
3355 return ret;
3356 if (ret)
3357 goto fill_holes;
3358 if (src_path->slots[0])
3359 src_path->slots[0]--;
3360 src = src_path->nodes[0];
3361 btrfs_item_key_to_cpu(src, &key, src_path->slots[0]);
3362 if (key.objectid != btrfs_ino(inode) ||
3363 key.type != BTRFS_EXTENT_DATA_KEY)
3364 goto fill_holes;
3365 extent = btrfs_item_ptr(src, src_path->slots[0],
3366 struct btrfs_file_extent_item);
3367 if (btrfs_file_extent_type(src, extent) ==
3368 BTRFS_FILE_EXTENT_INLINE) {
3369 len = btrfs_file_extent_inline_len(src, extent);
3370 *last_extent = ALIGN(key.offset + len,
3371 log->sectorsize);
3372 } else {
3373 len = btrfs_file_extent_num_bytes(src, extent);
3374 *last_extent = key.offset + len;
3375 }
3376 }
3377fill_holes:
3378 /* So we did prev_leaf, now we need to move to the next leaf, but a few
3379 * things could have happened
3380 *
3381 * 1) A merge could have happened, so we could currently be on a leaf
3382 * that holds what we were copying in the first place.
3383 * 2) A split could have happened, and now not all of the items we want
3384 * are on the same leaf.
3385 *
3386 * So we need to adjust how we search for holes, we need to drop the
3387 * path and re-search for the first extent key we found, and then walk
3388 * forward until we hit the last one we copied.
3389 */
3390 if (need_find_last_extent) {
3391 /* btrfs_prev_leaf could return 1 without releasing the path */
3392 btrfs_release_path(src_path);
3393 ret = btrfs_search_slot(NULL, BTRFS_I(inode)->root, &first_key,
3394 src_path, 0, 0);
3395 if (ret < 0)
3396 return ret;
3397 ASSERT(ret == 0);
3398 src = src_path->nodes[0];
3399 i = src_path->slots[0];
3400 } else {
3401 i = start_slot;
3402 }
3403
3404 /*
3405 * Ok so here we need to go through and fill in any holes we may have
3406 * to make sure that holes are punched for those areas in case they had
3407 * extents previously.
3408 */
3409 while (!done) {
3410 u64 offset, len;
3411 u64 extent_end;
3412
3413 if (i >= btrfs_header_nritems(src_path->nodes[0])) {
3414 ret = btrfs_next_leaf(BTRFS_I(inode)->root, src_path);
3415 if (ret < 0)
3416 return ret;
3417 ASSERT(ret == 0);
3418 src = src_path->nodes[0];
3419 i = 0;
3420 }
3421
3422 btrfs_item_key_to_cpu(src, &key, i);
3423 if (!btrfs_comp_cpu_keys(&key, &last_key))
3424 done = true;
3425 if (key.objectid != btrfs_ino(inode) ||
3426 key.type != BTRFS_EXTENT_DATA_KEY) {
3427 i++;
3428 continue;
3429 }
3430 extent = btrfs_item_ptr(src, i, struct btrfs_file_extent_item);
3431 if (btrfs_file_extent_type(src, extent) ==
3432 BTRFS_FILE_EXTENT_INLINE) {
3433 len = btrfs_file_extent_inline_len(src, extent);
3434 extent_end = ALIGN(key.offset + len, log->sectorsize);
3435 } else {
3436 len = btrfs_file_extent_num_bytes(src, extent);
3437 extent_end = key.offset + len;
3438 }
3439 i++;
3440
3441 if (*last_extent == key.offset) {
3442 *last_extent = extent_end;
3443 continue;
3444 }
3445 offset = *last_extent;
3446 len = key.offset - *last_extent;
3447 ret = btrfs_insert_file_extent(trans, log, btrfs_ino(inode),
3448 offset, 0, 0, len, 0, len, 0,
3449 0, 0);
3450 if (ret)
3451 break;
3452 *last_extent = offset + len;
3453 }
3454 /*
3455 * Need to let the callers know we dropped the path so they should
3456 * re-search.
3457 */
3458 if (!ret && need_find_last_extent)
3459 ret = 1;
3315 return ret; 3460 return ret;
3316} 3461}
3317 3462
@@ -3630,6 +3775,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
3630 struct btrfs_key max_key; 3775 struct btrfs_key max_key;
3631 struct btrfs_root *log = root->log_root; 3776 struct btrfs_root *log = root->log_root;
3632 struct extent_buffer *src = NULL; 3777 struct extent_buffer *src = NULL;
3778 u64 last_extent = 0;
3633 int err = 0; 3779 int err = 0;
3634 int ret; 3780 int ret;
3635 int nritems; 3781 int nritems;
@@ -3745,11 +3891,15 @@ again:
3745 goto next_slot; 3891 goto next_slot;
3746 } 3892 }
3747 3893
3748 ret = copy_items(trans, inode, dst_path, src, ins_start_slot, 3894 ret = copy_items(trans, inode, dst_path, path, &last_extent,
3749 ins_nr, inode_only); 3895 ins_start_slot, ins_nr, inode_only);
3750 if (ret) { 3896 if (ret < 0) {
3751 err = ret; 3897 err = ret;
3752 goto out_unlock; 3898 goto out_unlock;
3899 } if (ret) {
3900 ins_nr = 0;
3901 btrfs_release_path(path);
3902 continue;
3753 } 3903 }
3754 ins_nr = 1; 3904 ins_nr = 1;
3755 ins_start_slot = path->slots[0]; 3905 ins_start_slot = path->slots[0];
@@ -3763,13 +3913,14 @@ next_slot:
3763 goto again; 3913 goto again;
3764 } 3914 }
3765 if (ins_nr) { 3915 if (ins_nr) {
3766 ret = copy_items(trans, inode, dst_path, src, 3916 ret = copy_items(trans, inode, dst_path, path,
3767 ins_start_slot, 3917 &last_extent, ins_start_slot,
3768 ins_nr, inode_only); 3918 ins_nr, inode_only);
3769 if (ret) { 3919 if (ret < 0) {
3770 err = ret; 3920 err = ret;
3771 goto out_unlock; 3921 goto out_unlock;
3772 } 3922 }
3923 ret = 0;
3773 ins_nr = 0; 3924 ins_nr = 0;
3774 } 3925 }
3775 btrfs_release_path(path); 3926 btrfs_release_path(path);
@@ -3784,12 +3935,13 @@ next_slot:
3784 } 3935 }
3785 } 3936 }
3786 if (ins_nr) { 3937 if (ins_nr) {
3787 ret = copy_items(trans, inode, dst_path, src, ins_start_slot, 3938 ret = copy_items(trans, inode, dst_path, path, &last_extent,
3788 ins_nr, inode_only); 3939 ins_start_slot, ins_nr, inode_only);
3789 if (ret) { 3940 if (ret < 0) {
3790 err = ret; 3941 err = ret;
3791 goto out_unlock; 3942 goto out_unlock;
3792 } 3943 }
3944 ret = 0;
3793 ins_nr = 0; 3945 ins_nr = 0;
3794 } 3946 }
3795 3947