diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 334 |
1 files changed, 210 insertions, 124 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 9e1f2cd5e67a..1475979e5718 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -94,8 +94,11 @@ | |||
94 | #define LOG_WALK_REPLAY_ALL 3 | 94 | #define LOG_WALK_REPLAY_ALL 3 |
95 | 95 | ||
96 | static int btrfs_log_inode(struct btrfs_trans_handle *trans, | 96 | static int btrfs_log_inode(struct btrfs_trans_handle *trans, |
97 | struct btrfs_root *root, struct inode *inode, | 97 | struct btrfs_root *root, struct inode *inode, |
98 | int inode_only); | 98 | int inode_only, |
99 | const loff_t start, | ||
100 | const loff_t end, | ||
101 | struct btrfs_log_ctx *ctx); | ||
99 | static int link_to_fixup_dir(struct btrfs_trans_handle *trans, | 102 | static int link_to_fixup_dir(struct btrfs_trans_handle *trans, |
100 | struct btrfs_root *root, | 103 | struct btrfs_root *root, |
101 | struct btrfs_path *path, u64 objectid); | 104 | struct btrfs_path *path, u64 objectid); |
@@ -1496,7 +1499,7 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans, | |||
1496 | return -EIO; | 1499 | return -EIO; |
1497 | 1500 | ||
1498 | key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID; | 1501 | key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID; |
1499 | btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY); | 1502 | key.type = BTRFS_ORPHAN_ITEM_KEY; |
1500 | key.offset = objectid; | 1503 | key.offset = objectid; |
1501 | 1504 | ||
1502 | ret = btrfs_insert_empty_item(trans, root, path, &key, 0); | 1505 | ret = btrfs_insert_empty_item(trans, root, path, &key, 0); |
@@ -1635,6 +1638,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, | |||
1635 | found_key.type == log_key.type && | 1638 | found_key.type == log_key.type && |
1636 | found_key.offset == log_key.offset && | 1639 | found_key.offset == log_key.offset && |
1637 | btrfs_dir_type(path->nodes[0], dst_di) == log_type) { | 1640 | btrfs_dir_type(path->nodes[0], dst_di) == log_type) { |
1641 | update_size = false; | ||
1638 | goto out; | 1642 | goto out; |
1639 | } | 1643 | } |
1640 | 1644 | ||
@@ -2155,7 +2159,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, | |||
2155 | 2159 | ||
2156 | bytenr = btrfs_node_blockptr(cur, path->slots[*level]); | 2160 | bytenr = btrfs_node_blockptr(cur, path->slots[*level]); |
2157 | ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]); | 2161 | ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]); |
2158 | blocksize = btrfs_level_size(root, *level - 1); | 2162 | blocksize = root->nodesize; |
2159 | 2163 | ||
2160 | parent = path->nodes[*level]; | 2164 | parent = path->nodes[*level]; |
2161 | root_owner = btrfs_header_owner(parent); | 2165 | root_owner = btrfs_header_owner(parent); |
@@ -2981,8 +2985,6 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | |||
2981 | min_key.type = key_type; | 2985 | min_key.type = key_type; |
2982 | min_key.offset = min_offset; | 2986 | min_key.offset = min_offset; |
2983 | 2987 | ||
2984 | path->keep_locks = 1; | ||
2985 | |||
2986 | ret = btrfs_search_forward(root, &min_key, path, trans->transid); | 2988 | ret = btrfs_search_forward(root, &min_key, path, trans->transid); |
2987 | 2989 | ||
2988 | /* | 2990 | /* |
@@ -3298,7 +3300,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3298 | struct list_head ordered_sums; | 3300 | struct list_head ordered_sums; |
3299 | int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | 3301 | int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; |
3300 | bool has_extents = false; | 3302 | bool has_extents = false; |
3301 | bool need_find_last_extent = (*last_extent == 0); | 3303 | bool need_find_last_extent = true; |
3302 | bool done = false; | 3304 | bool done = false; |
3303 | 3305 | ||
3304 | INIT_LIST_HEAD(&ordered_sums); | 3306 | INIT_LIST_HEAD(&ordered_sums); |
@@ -3352,8 +3354,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3352 | */ | 3354 | */ |
3353 | if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY) { | 3355 | if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY) { |
3354 | has_extents = true; | 3356 | has_extents = true; |
3355 | if (need_find_last_extent && | 3357 | if (first_key.objectid == (u64)-1) |
3356 | first_key.objectid == (u64)-1) | ||
3357 | first_key = ins_keys[i]; | 3358 | first_key = ins_keys[i]; |
3358 | } else { | 3359 | } else { |
3359 | need_find_last_extent = false; | 3360 | need_find_last_extent = false; |
@@ -3363,7 +3364,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3363 | * or deletes of this inode don't have to relog the inode | 3364 | * or deletes of this inode don't have to relog the inode |
3364 | * again | 3365 | * again |
3365 | */ | 3366 | */ |
3366 | if (btrfs_key_type(ins_keys + i) == BTRFS_EXTENT_DATA_KEY && | 3367 | if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY && |
3367 | !skip_csum) { | 3368 | !skip_csum) { |
3368 | int found_type; | 3369 | int found_type; |
3369 | extent = btrfs_item_ptr(src, start_slot + i, | 3370 | extent = btrfs_item_ptr(src, start_slot + i, |
@@ -3427,6 +3428,16 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3427 | if (!has_extents) | 3428 | if (!has_extents) |
3428 | return ret; | 3429 | return ret; |
3429 | 3430 | ||
3431 | if (need_find_last_extent && *last_extent == first_key.offset) { | ||
3432 | /* | ||
3433 | * We don't have any leafs between our current one and the one | ||
3434 | * we processed before that can have file extent items for our | ||
3435 | * inode (and have a generation number smaller than our current | ||
3436 | * transaction id). | ||
3437 | */ | ||
3438 | need_find_last_extent = false; | ||
3439 | } | ||
3440 | |||
3430 | /* | 3441 | /* |
3431 | * Because we use btrfs_search_forward we could skip leaves that were | 3442 | * Because we use btrfs_search_forward we could skip leaves that were |
3432 | * not modified and then assume *last_extent is valid when it really | 3443 | * not modified and then assume *last_extent is valid when it really |
@@ -3537,7 +3548,7 @@ fill_holes: | |||
3537 | 0, 0); | 3548 | 0, 0); |
3538 | if (ret) | 3549 | if (ret) |
3539 | break; | 3550 | break; |
3540 | *last_extent = offset + len; | 3551 | *last_extent = extent_end; |
3541 | } | 3552 | } |
3542 | /* | 3553 | /* |
3543 | * Need to let the callers know we dropped the path so they should | 3554 | * Need to let the callers know we dropped the path so they should |
@@ -3562,107 +3573,33 @@ static int extent_cmp(void *priv, struct list_head *a, struct list_head *b) | |||
3562 | return 0; | 3573 | return 0; |
3563 | } | 3574 | } |
3564 | 3575 | ||
3565 | static int log_one_extent(struct btrfs_trans_handle *trans, | 3576 | static int wait_ordered_extents(struct btrfs_trans_handle *trans, |
3566 | struct inode *inode, struct btrfs_root *root, | 3577 | struct inode *inode, |
3567 | struct extent_map *em, struct btrfs_path *path, | 3578 | struct btrfs_root *root, |
3568 | struct list_head *logged_list) | 3579 | const struct extent_map *em, |
3580 | const struct list_head *logged_list, | ||
3581 | bool *ordered_io_error) | ||
3569 | { | 3582 | { |
3570 | struct btrfs_root *log = root->log_root; | ||
3571 | struct btrfs_file_extent_item *fi; | ||
3572 | struct extent_buffer *leaf; | ||
3573 | struct btrfs_ordered_extent *ordered; | 3583 | struct btrfs_ordered_extent *ordered; |
3574 | struct list_head ordered_sums; | 3584 | struct btrfs_root *log = root->log_root; |
3575 | struct btrfs_map_token token; | ||
3576 | struct btrfs_key key; | ||
3577 | u64 mod_start = em->mod_start; | 3585 | u64 mod_start = em->mod_start; |
3578 | u64 mod_len = em->mod_len; | 3586 | u64 mod_len = em->mod_len; |
3587 | const bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | ||
3579 | u64 csum_offset; | 3588 | u64 csum_offset; |
3580 | u64 csum_len; | 3589 | u64 csum_len; |
3581 | u64 extent_offset = em->start - em->orig_start; | 3590 | LIST_HEAD(ordered_sums); |
3582 | u64 block_len; | 3591 | int ret = 0; |
3583 | int ret; | ||
3584 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | ||
3585 | int extent_inserted = 0; | ||
3586 | |||
3587 | INIT_LIST_HEAD(&ordered_sums); | ||
3588 | btrfs_init_map_token(&token); | ||
3589 | |||
3590 | ret = __btrfs_drop_extents(trans, log, inode, path, em->start, | ||
3591 | em->start + em->len, NULL, 0, 1, | ||
3592 | sizeof(*fi), &extent_inserted); | ||
3593 | if (ret) | ||
3594 | return ret; | ||
3595 | |||
3596 | if (!extent_inserted) { | ||
3597 | key.objectid = btrfs_ino(inode); | ||
3598 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
3599 | key.offset = em->start; | ||
3600 | |||
3601 | ret = btrfs_insert_empty_item(trans, log, path, &key, | ||
3602 | sizeof(*fi)); | ||
3603 | if (ret) | ||
3604 | return ret; | ||
3605 | } | ||
3606 | leaf = path->nodes[0]; | ||
3607 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
3608 | struct btrfs_file_extent_item); | ||
3609 | |||
3610 | btrfs_set_token_file_extent_generation(leaf, fi, em->generation, | ||
3611 | &token); | ||
3612 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) { | ||
3613 | skip_csum = true; | ||
3614 | btrfs_set_token_file_extent_type(leaf, fi, | ||
3615 | BTRFS_FILE_EXTENT_PREALLOC, | ||
3616 | &token); | ||
3617 | } else { | ||
3618 | btrfs_set_token_file_extent_type(leaf, fi, | ||
3619 | BTRFS_FILE_EXTENT_REG, | ||
3620 | &token); | ||
3621 | if (em->block_start == EXTENT_MAP_HOLE) | ||
3622 | skip_csum = true; | ||
3623 | } | ||
3624 | |||
3625 | block_len = max(em->block_len, em->orig_block_len); | ||
3626 | if (em->compress_type != BTRFS_COMPRESS_NONE) { | ||
3627 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, | ||
3628 | em->block_start, | ||
3629 | &token); | ||
3630 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len, | ||
3631 | &token); | ||
3632 | } else if (em->block_start < EXTENT_MAP_LAST_BYTE) { | ||
3633 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, | ||
3634 | em->block_start - | ||
3635 | extent_offset, &token); | ||
3636 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len, | ||
3637 | &token); | ||
3638 | } else { | ||
3639 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, 0, &token); | ||
3640 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, 0, | ||
3641 | &token); | ||
3642 | } | ||
3643 | 3592 | ||
3644 | btrfs_set_token_file_extent_offset(leaf, fi, | 3593 | *ordered_io_error = false; |
3645 | em->start - em->orig_start, | ||
3646 | &token); | ||
3647 | btrfs_set_token_file_extent_num_bytes(leaf, fi, em->len, &token); | ||
3648 | btrfs_set_token_file_extent_ram_bytes(leaf, fi, em->ram_bytes, &token); | ||
3649 | btrfs_set_token_file_extent_compression(leaf, fi, em->compress_type, | ||
3650 | &token); | ||
3651 | btrfs_set_token_file_extent_encryption(leaf, fi, 0, &token); | ||
3652 | btrfs_set_token_file_extent_other_encoding(leaf, fi, 0, &token); | ||
3653 | btrfs_mark_buffer_dirty(leaf); | ||
3654 | 3594 | ||
3655 | btrfs_release_path(path); | 3595 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) || |
3656 | if (ret) { | 3596 | em->block_start == EXTENT_MAP_HOLE) |
3657 | return ret; | ||
3658 | } | ||
3659 | |||
3660 | if (skip_csum) | ||
3661 | return 0; | 3597 | return 0; |
3662 | 3598 | ||
3663 | /* | 3599 | /* |
3664 | * First check and see if our csums are on our outstanding ordered | 3600 | * Wait far any ordered extent that covers our extent map. If it |
3665 | * extents. | 3601 | * finishes without an error, first check and see if our csums are on |
3602 | * our outstanding ordered extents. | ||
3666 | */ | 3603 | */ |
3667 | list_for_each_entry(ordered, logged_list, log_list) { | 3604 | list_for_each_entry(ordered, logged_list, log_list) { |
3668 | struct btrfs_ordered_sum *sum; | 3605 | struct btrfs_ordered_sum *sum; |
@@ -3674,6 +3611,24 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3674 | mod_start + mod_len <= ordered->file_offset) | 3611 | mod_start + mod_len <= ordered->file_offset) |
3675 | continue; | 3612 | continue; |
3676 | 3613 | ||
3614 | if (!test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) && | ||
3615 | !test_bit(BTRFS_ORDERED_IOERR, &ordered->flags) && | ||
3616 | !test_bit(BTRFS_ORDERED_DIRECT, &ordered->flags)) { | ||
3617 | const u64 start = ordered->file_offset; | ||
3618 | const u64 end = ordered->file_offset + ordered->len - 1; | ||
3619 | |||
3620 | WARN_ON(ordered->inode != inode); | ||
3621 | filemap_fdatawrite_range(inode->i_mapping, start, end); | ||
3622 | } | ||
3623 | |||
3624 | wait_event(ordered->wait, | ||
3625 | (test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) || | ||
3626 | test_bit(BTRFS_ORDERED_IOERR, &ordered->flags))); | ||
3627 | |||
3628 | if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags)) { | ||
3629 | *ordered_io_error = true; | ||
3630 | break; | ||
3631 | } | ||
3677 | /* | 3632 | /* |
3678 | * We are going to copy all the csums on this ordered extent, so | 3633 | * We are going to copy all the csums on this ordered extent, so |
3679 | * go ahead and adjust mod_start and mod_len in case this | 3634 | * go ahead and adjust mod_start and mod_len in case this |
@@ -3705,6 +3660,9 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3705 | } | 3660 | } |
3706 | } | 3661 | } |
3707 | 3662 | ||
3663 | if (skip_csum) | ||
3664 | continue; | ||
3665 | |||
3708 | /* | 3666 | /* |
3709 | * To keep us from looping for the above case of an ordered | 3667 | * To keep us from looping for the above case of an ordered |
3710 | * extent that falls inside of the logged extent. | 3668 | * extent that falls inside of the logged extent. |
@@ -3722,18 +3680,16 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3722 | list_for_each_entry(sum, &ordered->list, list) { | 3680 | list_for_each_entry(sum, &ordered->list, list) { |
3723 | ret = btrfs_csum_file_blocks(trans, log, sum); | 3681 | ret = btrfs_csum_file_blocks(trans, log, sum); |
3724 | if (ret) | 3682 | if (ret) |
3725 | goto unlocked; | 3683 | break; |
3726 | } | 3684 | } |
3727 | |||
3728 | } | 3685 | } |
3729 | unlocked: | ||
3730 | 3686 | ||
3731 | if (!mod_len || ret) | 3687 | if (*ordered_io_error || !mod_len || ret || skip_csum) |
3732 | return ret; | 3688 | return ret; |
3733 | 3689 | ||
3734 | if (em->compress_type) { | 3690 | if (em->compress_type) { |
3735 | csum_offset = 0; | 3691 | csum_offset = 0; |
3736 | csum_len = block_len; | 3692 | csum_len = max(em->block_len, em->orig_block_len); |
3737 | } else { | 3693 | } else { |
3738 | csum_offset = mod_start - em->start; | 3694 | csum_offset = mod_start - em->start; |
3739 | csum_len = mod_len; | 3695 | csum_len = mod_len; |
@@ -3760,11 +3716,106 @@ unlocked: | |||
3760 | return ret; | 3716 | return ret; |
3761 | } | 3717 | } |
3762 | 3718 | ||
3719 | static int log_one_extent(struct btrfs_trans_handle *trans, | ||
3720 | struct inode *inode, struct btrfs_root *root, | ||
3721 | const struct extent_map *em, | ||
3722 | struct btrfs_path *path, | ||
3723 | const struct list_head *logged_list, | ||
3724 | struct btrfs_log_ctx *ctx) | ||
3725 | { | ||
3726 | struct btrfs_root *log = root->log_root; | ||
3727 | struct btrfs_file_extent_item *fi; | ||
3728 | struct extent_buffer *leaf; | ||
3729 | struct btrfs_map_token token; | ||
3730 | struct btrfs_key key; | ||
3731 | u64 extent_offset = em->start - em->orig_start; | ||
3732 | u64 block_len; | ||
3733 | int ret; | ||
3734 | int extent_inserted = 0; | ||
3735 | bool ordered_io_err = false; | ||
3736 | |||
3737 | ret = wait_ordered_extents(trans, inode, root, em, logged_list, | ||
3738 | &ordered_io_err); | ||
3739 | if (ret) | ||
3740 | return ret; | ||
3741 | |||
3742 | if (ordered_io_err) { | ||
3743 | ctx->io_err = -EIO; | ||
3744 | return 0; | ||
3745 | } | ||
3746 | |||
3747 | btrfs_init_map_token(&token); | ||
3748 | |||
3749 | ret = __btrfs_drop_extents(trans, log, inode, path, em->start, | ||
3750 | em->start + em->len, NULL, 0, 1, | ||
3751 | sizeof(*fi), &extent_inserted); | ||
3752 | if (ret) | ||
3753 | return ret; | ||
3754 | |||
3755 | if (!extent_inserted) { | ||
3756 | key.objectid = btrfs_ino(inode); | ||
3757 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
3758 | key.offset = em->start; | ||
3759 | |||
3760 | ret = btrfs_insert_empty_item(trans, log, path, &key, | ||
3761 | sizeof(*fi)); | ||
3762 | if (ret) | ||
3763 | return ret; | ||
3764 | } | ||
3765 | leaf = path->nodes[0]; | ||
3766 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
3767 | struct btrfs_file_extent_item); | ||
3768 | |||
3769 | btrfs_set_token_file_extent_generation(leaf, fi, em->generation, | ||
3770 | &token); | ||
3771 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) | ||
3772 | btrfs_set_token_file_extent_type(leaf, fi, | ||
3773 | BTRFS_FILE_EXTENT_PREALLOC, | ||
3774 | &token); | ||
3775 | else | ||
3776 | btrfs_set_token_file_extent_type(leaf, fi, | ||
3777 | BTRFS_FILE_EXTENT_REG, | ||
3778 | &token); | ||
3779 | |||
3780 | block_len = max(em->block_len, em->orig_block_len); | ||
3781 | if (em->compress_type != BTRFS_COMPRESS_NONE) { | ||
3782 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, | ||
3783 | em->block_start, | ||
3784 | &token); | ||
3785 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len, | ||
3786 | &token); | ||
3787 | } else if (em->block_start < EXTENT_MAP_LAST_BYTE) { | ||
3788 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, | ||
3789 | em->block_start - | ||
3790 | extent_offset, &token); | ||
3791 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len, | ||
3792 | &token); | ||
3793 | } else { | ||
3794 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, 0, &token); | ||
3795 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, 0, | ||
3796 | &token); | ||
3797 | } | ||
3798 | |||
3799 | btrfs_set_token_file_extent_offset(leaf, fi, extent_offset, &token); | ||
3800 | btrfs_set_token_file_extent_num_bytes(leaf, fi, em->len, &token); | ||
3801 | btrfs_set_token_file_extent_ram_bytes(leaf, fi, em->ram_bytes, &token); | ||
3802 | btrfs_set_token_file_extent_compression(leaf, fi, em->compress_type, | ||
3803 | &token); | ||
3804 | btrfs_set_token_file_extent_encryption(leaf, fi, 0, &token); | ||
3805 | btrfs_set_token_file_extent_other_encoding(leaf, fi, 0, &token); | ||
3806 | btrfs_mark_buffer_dirty(leaf); | ||
3807 | |||
3808 | btrfs_release_path(path); | ||
3809 | |||
3810 | return ret; | ||
3811 | } | ||
3812 | |||
3763 | static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | 3813 | static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, |
3764 | struct btrfs_root *root, | 3814 | struct btrfs_root *root, |
3765 | struct inode *inode, | 3815 | struct inode *inode, |
3766 | struct btrfs_path *path, | 3816 | struct btrfs_path *path, |
3767 | struct list_head *logged_list) | 3817 | struct list_head *logged_list, |
3818 | struct btrfs_log_ctx *ctx) | ||
3768 | { | 3819 | { |
3769 | struct extent_map *em, *n; | 3820 | struct extent_map *em, *n; |
3770 | struct list_head extents; | 3821 | struct list_head extents; |
@@ -3822,7 +3873,8 @@ process: | |||
3822 | 3873 | ||
3823 | write_unlock(&tree->lock); | 3874 | write_unlock(&tree->lock); |
3824 | 3875 | ||
3825 | ret = log_one_extent(trans, inode, root, em, path, logged_list); | 3876 | ret = log_one_extent(trans, inode, root, em, path, logged_list, |
3877 | ctx); | ||
3826 | write_lock(&tree->lock); | 3878 | write_lock(&tree->lock); |
3827 | clear_em_logging(tree, em); | 3879 | clear_em_logging(tree, em); |
3828 | free_extent_map(em); | 3880 | free_extent_map(em); |
@@ -3849,8 +3901,11 @@ process: | |||
3849 | * This handles both files and directories. | 3901 | * This handles both files and directories. |
3850 | */ | 3902 | */ |
3851 | static int btrfs_log_inode(struct btrfs_trans_handle *trans, | 3903 | static int btrfs_log_inode(struct btrfs_trans_handle *trans, |
3852 | struct btrfs_root *root, struct inode *inode, | 3904 | struct btrfs_root *root, struct inode *inode, |
3853 | int inode_only) | 3905 | int inode_only, |
3906 | const loff_t start, | ||
3907 | const loff_t end, | ||
3908 | struct btrfs_log_ctx *ctx) | ||
3854 | { | 3909 | { |
3855 | struct btrfs_path *path; | 3910 | struct btrfs_path *path; |
3856 | struct btrfs_path *dst_path; | 3911 | struct btrfs_path *dst_path; |
@@ -3867,6 +3922,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3867 | int ins_nr; | 3922 | int ins_nr; |
3868 | bool fast_search = false; | 3923 | bool fast_search = false; |
3869 | u64 ino = btrfs_ino(inode); | 3924 | u64 ino = btrfs_ino(inode); |
3925 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | ||
3870 | 3926 | ||
3871 | path = btrfs_alloc_path(); | 3927 | path = btrfs_alloc_path(); |
3872 | if (!path) | 3928 | if (!path) |
@@ -3950,7 +4006,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3950 | err = ret; | 4006 | err = ret; |
3951 | goto out_unlock; | 4007 | goto out_unlock; |
3952 | } | 4008 | } |
3953 | path->keep_locks = 1; | ||
3954 | 4009 | ||
3955 | while (1) { | 4010 | while (1) { |
3956 | ins_nr = 0; | 4011 | ins_nr = 0; |
@@ -3980,7 +4035,8 @@ again: | |||
3980 | if (ret < 0) { | 4035 | if (ret < 0) { |
3981 | err = ret; | 4036 | err = ret; |
3982 | goto out_unlock; | 4037 | goto out_unlock; |
3983 | } if (ret) { | 4038 | } |
4039 | if (ret) { | ||
3984 | ins_nr = 0; | 4040 | ins_nr = 0; |
3985 | btrfs_release_path(path); | 4041 | btrfs_release_path(path); |
3986 | continue; | 4042 | continue; |
@@ -4034,19 +4090,41 @@ log_extents: | |||
4034 | btrfs_release_path(dst_path); | 4090 | btrfs_release_path(dst_path); |
4035 | if (fast_search) { | 4091 | if (fast_search) { |
4036 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path, | 4092 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path, |
4037 | &logged_list); | 4093 | &logged_list, ctx); |
4038 | if (ret) { | 4094 | if (ret) { |
4039 | err = ret; | 4095 | err = ret; |
4040 | goto out_unlock; | 4096 | goto out_unlock; |
4041 | } | 4097 | } |
4042 | } else if (inode_only == LOG_INODE_ALL) { | 4098 | } else if (inode_only == LOG_INODE_ALL) { |
4043 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; | ||
4044 | struct extent_map *em, *n; | 4099 | struct extent_map *em, *n; |
4045 | 4100 | ||
4046 | write_lock(&tree->lock); | 4101 | write_lock(&em_tree->lock); |
4047 | list_for_each_entry_safe(em, n, &tree->modified_extents, list) | 4102 | /* |
4048 | list_del_init(&em->list); | 4103 | * We can't just remove every em if we're called for a ranged |
4049 | write_unlock(&tree->lock); | 4104 | * fsync - that is, one that doesn't cover the whole possible |
4105 | * file range (0 to LLONG_MAX). This is because we can have | ||
4106 | * em's that fall outside the range we're logging and therefore | ||
4107 | * their ordered operations haven't completed yet | ||
4108 | * (btrfs_finish_ordered_io() not invoked yet). This means we | ||
4109 | * didn't get their respective file extent item in the fs/subvol | ||
4110 | * tree yet, and need to let the next fast fsync (one which | ||
4111 | * consults the list of modified extent maps) find the em so | ||
4112 | * that it logs a matching file extent item and waits for the | ||
4113 | * respective ordered operation to complete (if it's still | ||
4114 | * running). | ||
4115 | * | ||
4116 | * Removing every em outside the range we're logging would make | ||
4117 | * the next fast fsync not log their matching file extent items, | ||
4118 | * therefore making us lose data after a log replay. | ||
4119 | */ | ||
4120 | list_for_each_entry_safe(em, n, &em_tree->modified_extents, | ||
4121 | list) { | ||
4122 | const u64 mod_end = em->mod_start + em->mod_len - 1; | ||
4123 | |||
4124 | if (em->mod_start >= start && mod_end <= end) | ||
4125 | list_del_init(&em->list); | ||
4126 | } | ||
4127 | write_unlock(&em_tree->lock); | ||
4050 | } | 4128 | } |
4051 | 4129 | ||
4052 | if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) { | 4130 | if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) { |
@@ -4056,6 +4134,7 @@ log_extents: | |||
4056 | goto out_unlock; | 4134 | goto out_unlock; |
4057 | } | 4135 | } |
4058 | } | 4136 | } |
4137 | |||
4059 | BTRFS_I(inode)->logged_trans = trans->transid; | 4138 | BTRFS_I(inode)->logged_trans = trans->transid; |
4060 | BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans; | 4139 | BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans; |
4061 | out_unlock: | 4140 | out_unlock: |
@@ -4152,7 +4231,10 @@ out: | |||
4152 | */ | 4231 | */ |
4153 | static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | 4232 | static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, |
4154 | struct btrfs_root *root, struct inode *inode, | 4233 | struct btrfs_root *root, struct inode *inode, |
4155 | struct dentry *parent, int exists_only, | 4234 | struct dentry *parent, |
4235 | const loff_t start, | ||
4236 | const loff_t end, | ||
4237 | int exists_only, | ||
4156 | struct btrfs_log_ctx *ctx) | 4238 | struct btrfs_log_ctx *ctx) |
4157 | { | 4239 | { |
4158 | int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL; | 4240 | int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL; |
@@ -4198,7 +4280,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
4198 | if (ret) | 4280 | if (ret) |
4199 | goto end_no_trans; | 4281 | goto end_no_trans; |
4200 | 4282 | ||
4201 | ret = btrfs_log_inode(trans, root, inode, inode_only); | 4283 | ret = btrfs_log_inode(trans, root, inode, inode_only, start, end, ctx); |
4202 | if (ret) | 4284 | if (ret) |
4203 | goto end_trans; | 4285 | goto end_trans; |
4204 | 4286 | ||
@@ -4226,7 +4308,8 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
4226 | 4308 | ||
4227 | if (BTRFS_I(inode)->generation > | 4309 | if (BTRFS_I(inode)->generation > |
4228 | root->fs_info->last_trans_committed) { | 4310 | root->fs_info->last_trans_committed) { |
4229 | ret = btrfs_log_inode(trans, root, inode, inode_only); | 4311 | ret = btrfs_log_inode(trans, root, inode, inode_only, |
4312 | 0, LLONG_MAX, ctx); | ||
4230 | if (ret) | 4313 | if (ret) |
4231 | goto end_trans; | 4314 | goto end_trans; |
4232 | } | 4315 | } |
@@ -4260,13 +4343,15 @@ end_no_trans: | |||
4260 | */ | 4343 | */ |
4261 | int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, | 4344 | int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, |
4262 | struct btrfs_root *root, struct dentry *dentry, | 4345 | struct btrfs_root *root, struct dentry *dentry, |
4346 | const loff_t start, | ||
4347 | const loff_t end, | ||
4263 | struct btrfs_log_ctx *ctx) | 4348 | struct btrfs_log_ctx *ctx) |
4264 | { | 4349 | { |
4265 | struct dentry *parent = dget_parent(dentry); | 4350 | struct dentry *parent = dget_parent(dentry); |
4266 | int ret; | 4351 | int ret; |
4267 | 4352 | ||
4268 | ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, | 4353 | ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, |
4269 | 0, ctx); | 4354 | start, end, 0, ctx); |
4270 | dput(parent); | 4355 | dput(parent); |
4271 | 4356 | ||
4272 | return ret; | 4357 | return ret; |
@@ -4316,7 +4401,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) | |||
4316 | again: | 4401 | again: |
4317 | key.objectid = BTRFS_TREE_LOG_OBJECTID; | 4402 | key.objectid = BTRFS_TREE_LOG_OBJECTID; |
4318 | key.offset = (u64)-1; | 4403 | key.offset = (u64)-1; |
4319 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | 4404 | key.type = BTRFS_ROOT_ITEM_KEY; |
4320 | 4405 | ||
4321 | while (1) { | 4406 | while (1) { |
4322 | ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0); | 4407 | ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0); |
@@ -4503,6 +4588,7 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans, | |||
4503 | root->fs_info->last_trans_committed)) | 4588 | root->fs_info->last_trans_committed)) |
4504 | return 0; | 4589 | return 0; |
4505 | 4590 | ||
4506 | return btrfs_log_inode_parent(trans, root, inode, parent, 1, NULL); | 4591 | return btrfs_log_inode_parent(trans, root, inode, parent, 0, |
4592 | LLONG_MAX, 1, NULL); | ||
4507 | } | 4593 | } |
4508 | 4594 | ||