diff options
-rw-r--r-- | fs/btrfs/tree-log.c | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 451fad96ecd1..ef96381569a4 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -317,6 +317,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | |||
317 | unsigned long src_ptr; | 317 | unsigned long src_ptr; |
318 | unsigned long dst_ptr; | 318 | unsigned long dst_ptr; |
319 | int overwrite_root = 0; | 319 | int overwrite_root = 0; |
320 | bool inode_item = key->type == BTRFS_INODE_ITEM_KEY; | ||
320 | 321 | ||
321 | if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) | 322 | if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) |
322 | overwrite_root = 1; | 323 | overwrite_root = 1; |
@@ -326,6 +327,9 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | |||
326 | 327 | ||
327 | /* look for the key in the destination tree */ | 328 | /* look for the key in the destination tree */ |
328 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); | 329 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); |
330 | if (ret < 0) | ||
331 | return ret; | ||
332 | |||
329 | if (ret == 0) { | 333 | if (ret == 0) { |
330 | char *src_copy; | 334 | char *src_copy; |
331 | char *dst_copy; | 335 | char *dst_copy; |
@@ -367,6 +371,30 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | |||
367 | return 0; | 371 | return 0; |
368 | } | 372 | } |
369 | 373 | ||
374 | /* | ||
375 | * We need to load the old nbytes into the inode so when we | ||
376 | * replay the extents we've logged we get the right nbytes. | ||
377 | */ | ||
378 | if (inode_item) { | ||
379 | struct btrfs_inode_item *item; | ||
380 | u64 nbytes; | ||
381 | |||
382 | item = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
383 | struct btrfs_inode_item); | ||
384 | nbytes = btrfs_inode_nbytes(path->nodes[0], item); | ||
385 | item = btrfs_item_ptr(eb, slot, | ||
386 | struct btrfs_inode_item); | ||
387 | btrfs_set_inode_nbytes(eb, item, nbytes); | ||
388 | } | ||
389 | } else if (inode_item) { | ||
390 | struct btrfs_inode_item *item; | ||
391 | |||
392 | /* | ||
393 | * New inode, set nbytes to 0 so that the nbytes comes out | ||
394 | * properly when we replay the extents. | ||
395 | */ | ||
396 | item = btrfs_item_ptr(eb, slot, struct btrfs_inode_item); | ||
397 | btrfs_set_inode_nbytes(eb, item, 0); | ||
370 | } | 398 | } |
371 | insert: | 399 | insert: |
372 | btrfs_release_path(path); | 400 | btrfs_release_path(path); |
@@ -486,7 +514,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | |||
486 | int found_type; | 514 | int found_type; |
487 | u64 extent_end; | 515 | u64 extent_end; |
488 | u64 start = key->offset; | 516 | u64 start = key->offset; |
489 | u64 saved_nbytes; | 517 | u64 nbytes = 0; |
490 | struct btrfs_file_extent_item *item; | 518 | struct btrfs_file_extent_item *item; |
491 | struct inode *inode = NULL; | 519 | struct inode *inode = NULL; |
492 | unsigned long size; | 520 | unsigned long size; |
@@ -496,10 +524,19 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | |||
496 | found_type = btrfs_file_extent_type(eb, item); | 524 | found_type = btrfs_file_extent_type(eb, item); |
497 | 525 | ||
498 | if (found_type == BTRFS_FILE_EXTENT_REG || | 526 | if (found_type == BTRFS_FILE_EXTENT_REG || |
499 | found_type == BTRFS_FILE_EXTENT_PREALLOC) | 527 | found_type == BTRFS_FILE_EXTENT_PREALLOC) { |
500 | extent_end = start + btrfs_file_extent_num_bytes(eb, item); | 528 | nbytes = btrfs_file_extent_num_bytes(eb, item); |
501 | else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | 529 | extent_end = start + nbytes; |
530 | |||
531 | /* | ||
532 | * We don't add to the inodes nbytes if we are prealloc or a | ||
533 | * hole. | ||
534 | */ | ||
535 | if (btrfs_file_extent_disk_bytenr(eb, item) == 0) | ||
536 | nbytes = 0; | ||
537 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | ||
502 | size = btrfs_file_extent_inline_len(eb, item); | 538 | size = btrfs_file_extent_inline_len(eb, item); |
539 | nbytes = btrfs_file_extent_ram_bytes(eb, item); | ||
503 | extent_end = ALIGN(start + size, root->sectorsize); | 540 | extent_end = ALIGN(start + size, root->sectorsize); |
504 | } else { | 541 | } else { |
505 | ret = 0; | 542 | ret = 0; |
@@ -548,7 +585,6 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | |||
548 | } | 585 | } |
549 | btrfs_release_path(path); | 586 | btrfs_release_path(path); |
550 | 587 | ||
551 | saved_nbytes = inode_get_bytes(inode); | ||
552 | /* drop any overlapping extents */ | 588 | /* drop any overlapping extents */ |
553 | ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1); | 589 | ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1); |
554 | BUG_ON(ret); | 590 | BUG_ON(ret); |
@@ -635,7 +671,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | |||
635 | BUG_ON(ret); | 671 | BUG_ON(ret); |
636 | } | 672 | } |
637 | 673 | ||
638 | inode_set_bytes(inode, saved_nbytes); | 674 | inode_add_bytes(inode, nbytes); |
639 | ret = btrfs_update_inode(trans, root, inode); | 675 | ret = btrfs_update_inode(trans, root, inode); |
640 | out: | 676 | out: |
641 | if (inode) | 677 | if (inode) |