diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 312 |
1 files changed, 192 insertions, 120 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 1d1ba083ca6e..9a02da16f2be 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -97,7 +97,8 @@ 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, | 99 | const loff_t start, |
100 | const loff_t end); | 100 | const loff_t end, |
101 | struct btrfs_log_ctx *ctx); | ||
101 | static int link_to_fixup_dir(struct btrfs_trans_handle *trans, | 102 | static int link_to_fixup_dir(struct btrfs_trans_handle *trans, |
102 | struct btrfs_root *root, | 103 | struct btrfs_root *root, |
103 | struct btrfs_path *path, u64 objectid); | 104 | struct btrfs_path *path, u64 objectid); |
@@ -671,7 +672,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | |||
671 | * is this extent already allocated in the extent | 672 | * is this extent already allocated in the extent |
672 | * allocation tree? If so, just add a reference | 673 | * allocation tree? If so, just add a reference |
673 | */ | 674 | */ |
674 | ret = btrfs_lookup_extent(root, ins.objectid, | 675 | ret = btrfs_lookup_data_extent(root, ins.objectid, |
675 | ins.offset); | 676 | ins.offset); |
676 | if (ret == 0) { | 677 | if (ret == 0) { |
677 | ret = btrfs_inc_extent_ref(trans, root, | 678 | ret = btrfs_inc_extent_ref(trans, root, |
@@ -1498,7 +1499,7 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans, | |||
1498 | return -EIO; | 1499 | return -EIO; |
1499 | 1500 | ||
1500 | key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID; | 1501 | key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID; |
1501 | btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY); | 1502 | key.type = BTRFS_ORPHAN_ITEM_KEY; |
1502 | key.offset = objectid; | 1503 | key.offset = objectid; |
1503 | 1504 | ||
1504 | ret = btrfs_insert_empty_item(trans, root, path, &key, 0); | 1505 | ret = btrfs_insert_empty_item(trans, root, path, &key, 0); |
@@ -1637,6 +1638,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, | |||
1637 | found_key.type == log_key.type && | 1638 | found_key.type == log_key.type && |
1638 | found_key.offset == log_key.offset && | 1639 | found_key.offset == log_key.offset && |
1639 | 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; | ||
1640 | goto out; | 1642 | goto out; |
1641 | } | 1643 | } |
1642 | 1644 | ||
@@ -2157,7 +2159,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, | |||
2157 | 2159 | ||
2158 | bytenr = btrfs_node_blockptr(cur, path->slots[*level]); | 2160 | bytenr = btrfs_node_blockptr(cur, path->slots[*level]); |
2159 | ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]); | 2161 | ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]); |
2160 | blocksize = btrfs_level_size(root, *level - 1); | 2162 | blocksize = root->nodesize; |
2161 | 2163 | ||
2162 | parent = path->nodes[*level]; | 2164 | parent = path->nodes[*level]; |
2163 | root_owner = btrfs_header_owner(parent); | 2165 | root_owner = btrfs_header_owner(parent); |
@@ -2597,12 +2599,14 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2597 | index2 = root_log_ctx.log_transid % 2; | 2599 | index2 = root_log_ctx.log_transid % 2; |
2598 | if (atomic_read(&log_root_tree->log_commit[index2])) { | 2600 | if (atomic_read(&log_root_tree->log_commit[index2])) { |
2599 | blk_finish_plug(&plug); | 2601 | blk_finish_plug(&plug); |
2600 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2602 | ret = btrfs_wait_marked_extents(log, &log->dirty_log_pages, |
2603 | mark); | ||
2604 | btrfs_wait_logged_extents(trans, log, log_transid); | ||
2601 | wait_log_commit(trans, log_root_tree, | 2605 | wait_log_commit(trans, log_root_tree, |
2602 | root_log_ctx.log_transid); | 2606 | root_log_ctx.log_transid); |
2603 | btrfs_free_logged_extents(log, log_transid); | ||
2604 | mutex_unlock(&log_root_tree->log_mutex); | 2607 | mutex_unlock(&log_root_tree->log_mutex); |
2605 | ret = root_log_ctx.log_ret; | 2608 | if (!ret) |
2609 | ret = root_log_ctx.log_ret; | ||
2606 | goto out; | 2610 | goto out; |
2607 | } | 2611 | } |
2608 | ASSERT(root_log_ctx.log_transid == log_root_tree->log_transid); | 2612 | ASSERT(root_log_ctx.log_transid == log_root_tree->log_transid); |
@@ -2639,11 +2643,18 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2639 | mutex_unlock(&log_root_tree->log_mutex); | 2643 | mutex_unlock(&log_root_tree->log_mutex); |
2640 | goto out_wake_log_root; | 2644 | goto out_wake_log_root; |
2641 | } | 2645 | } |
2642 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2646 | ret = btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); |
2643 | btrfs_wait_marked_extents(log_root_tree, | 2647 | if (!ret) |
2644 | &log_root_tree->dirty_log_pages, | 2648 | ret = btrfs_wait_marked_extents(log_root_tree, |
2645 | EXTENT_NEW | EXTENT_DIRTY); | 2649 | &log_root_tree->dirty_log_pages, |
2646 | btrfs_wait_logged_extents(log, log_transid); | 2650 | EXTENT_NEW | EXTENT_DIRTY); |
2651 | if (ret) { | ||
2652 | btrfs_set_log_full_commit(root->fs_info, trans); | ||
2653 | btrfs_free_logged_extents(log, log_transid); | ||
2654 | mutex_unlock(&log_root_tree->log_mutex); | ||
2655 | goto out_wake_log_root; | ||
2656 | } | ||
2657 | btrfs_wait_logged_extents(trans, log, log_transid); | ||
2647 | 2658 | ||
2648 | btrfs_set_super_log_root(root->fs_info->super_for_commit, | 2659 | btrfs_set_super_log_root(root->fs_info->super_for_commit, |
2649 | log_root_tree->node->start); | 2660 | log_root_tree->node->start); |
@@ -2983,8 +2994,6 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | |||
2983 | min_key.type = key_type; | 2994 | min_key.type = key_type; |
2984 | min_key.offset = min_offset; | 2995 | min_key.offset = min_offset; |
2985 | 2996 | ||
2986 | path->keep_locks = 1; | ||
2987 | |||
2988 | ret = btrfs_search_forward(root, &min_key, path, trans->transid); | 2997 | ret = btrfs_search_forward(root, &min_key, path, trans->transid); |
2989 | 2998 | ||
2990 | /* | 2999 | /* |
@@ -3364,7 +3373,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3364 | * or deletes of this inode don't have to relog the inode | 3373 | * or deletes of this inode don't have to relog the inode |
3365 | * again | 3374 | * again |
3366 | */ | 3375 | */ |
3367 | if (btrfs_key_type(ins_keys + i) == BTRFS_EXTENT_DATA_KEY && | 3376 | if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY && |
3368 | !skip_csum) { | 3377 | !skip_csum) { |
3369 | int found_type; | 3378 | int found_type; |
3370 | extent = btrfs_item_ptr(src, start_slot + i, | 3379 | extent = btrfs_item_ptr(src, start_slot + i, |
@@ -3573,107 +3582,33 @@ static int extent_cmp(void *priv, struct list_head *a, struct list_head *b) | |||
3573 | return 0; | 3582 | return 0; |
3574 | } | 3583 | } |
3575 | 3584 | ||
3576 | static int log_one_extent(struct btrfs_trans_handle *trans, | 3585 | static int wait_ordered_extents(struct btrfs_trans_handle *trans, |
3577 | struct inode *inode, struct btrfs_root *root, | 3586 | struct inode *inode, |
3578 | struct extent_map *em, struct btrfs_path *path, | 3587 | struct btrfs_root *root, |
3579 | struct list_head *logged_list) | 3588 | const struct extent_map *em, |
3589 | const struct list_head *logged_list, | ||
3590 | bool *ordered_io_error) | ||
3580 | { | 3591 | { |
3581 | struct btrfs_root *log = root->log_root; | ||
3582 | struct btrfs_file_extent_item *fi; | ||
3583 | struct extent_buffer *leaf; | ||
3584 | struct btrfs_ordered_extent *ordered; | 3592 | struct btrfs_ordered_extent *ordered; |
3585 | struct list_head ordered_sums; | 3593 | struct btrfs_root *log = root->log_root; |
3586 | struct btrfs_map_token token; | ||
3587 | struct btrfs_key key; | ||
3588 | u64 mod_start = em->mod_start; | 3594 | u64 mod_start = em->mod_start; |
3589 | u64 mod_len = em->mod_len; | 3595 | u64 mod_len = em->mod_len; |
3596 | const bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | ||
3590 | u64 csum_offset; | 3597 | u64 csum_offset; |
3591 | u64 csum_len; | 3598 | u64 csum_len; |
3592 | u64 extent_offset = em->start - em->orig_start; | 3599 | LIST_HEAD(ordered_sums); |
3593 | u64 block_len; | 3600 | int ret = 0; |
3594 | int ret; | ||
3595 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | ||
3596 | int extent_inserted = 0; | ||
3597 | |||
3598 | INIT_LIST_HEAD(&ordered_sums); | ||
3599 | btrfs_init_map_token(&token); | ||
3600 | |||
3601 | ret = __btrfs_drop_extents(trans, log, inode, path, em->start, | ||
3602 | em->start + em->len, NULL, 0, 1, | ||
3603 | sizeof(*fi), &extent_inserted); | ||
3604 | if (ret) | ||
3605 | return ret; | ||
3606 | |||
3607 | if (!extent_inserted) { | ||
3608 | key.objectid = btrfs_ino(inode); | ||
3609 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
3610 | key.offset = em->start; | ||
3611 | |||
3612 | ret = btrfs_insert_empty_item(trans, log, path, &key, | ||
3613 | sizeof(*fi)); | ||
3614 | if (ret) | ||
3615 | return ret; | ||
3616 | } | ||
3617 | leaf = path->nodes[0]; | ||
3618 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
3619 | struct btrfs_file_extent_item); | ||
3620 | |||
3621 | btrfs_set_token_file_extent_generation(leaf, fi, em->generation, | ||
3622 | &token); | ||
3623 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) { | ||
3624 | skip_csum = true; | ||
3625 | btrfs_set_token_file_extent_type(leaf, fi, | ||
3626 | BTRFS_FILE_EXTENT_PREALLOC, | ||
3627 | &token); | ||
3628 | } else { | ||
3629 | btrfs_set_token_file_extent_type(leaf, fi, | ||
3630 | BTRFS_FILE_EXTENT_REG, | ||
3631 | &token); | ||
3632 | if (em->block_start == EXTENT_MAP_HOLE) | ||
3633 | skip_csum = true; | ||
3634 | } | ||
3635 | |||
3636 | block_len = max(em->block_len, em->orig_block_len); | ||
3637 | if (em->compress_type != BTRFS_COMPRESS_NONE) { | ||
3638 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, | ||
3639 | em->block_start, | ||
3640 | &token); | ||
3641 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len, | ||
3642 | &token); | ||
3643 | } else if (em->block_start < EXTENT_MAP_LAST_BYTE) { | ||
3644 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, | ||
3645 | em->block_start - | ||
3646 | extent_offset, &token); | ||
3647 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len, | ||
3648 | &token); | ||
3649 | } else { | ||
3650 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, 0, &token); | ||
3651 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, 0, | ||
3652 | &token); | ||
3653 | } | ||
3654 | |||
3655 | btrfs_set_token_file_extent_offset(leaf, fi, | ||
3656 | em->start - em->orig_start, | ||
3657 | &token); | ||
3658 | btrfs_set_token_file_extent_num_bytes(leaf, fi, em->len, &token); | ||
3659 | btrfs_set_token_file_extent_ram_bytes(leaf, fi, em->ram_bytes, &token); | ||
3660 | btrfs_set_token_file_extent_compression(leaf, fi, em->compress_type, | ||
3661 | &token); | ||
3662 | btrfs_set_token_file_extent_encryption(leaf, fi, 0, &token); | ||
3663 | btrfs_set_token_file_extent_other_encoding(leaf, fi, 0, &token); | ||
3664 | btrfs_mark_buffer_dirty(leaf); | ||
3665 | 3601 | ||
3666 | btrfs_release_path(path); | 3602 | *ordered_io_error = false; |
3667 | if (ret) { | ||
3668 | return ret; | ||
3669 | } | ||
3670 | 3603 | ||
3671 | if (skip_csum) | 3604 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) || |
3605 | em->block_start == EXTENT_MAP_HOLE) | ||
3672 | return 0; | 3606 | return 0; |
3673 | 3607 | ||
3674 | /* | 3608 | /* |
3675 | * First check and see if our csums are on our outstanding ordered | 3609 | * Wait far any ordered extent that covers our extent map. If it |
3676 | * extents. | 3610 | * finishes without an error, first check and see if our csums are on |
3611 | * our outstanding ordered extents. | ||
3677 | */ | 3612 | */ |
3678 | list_for_each_entry(ordered, logged_list, log_list) { | 3613 | list_for_each_entry(ordered, logged_list, log_list) { |
3679 | struct btrfs_ordered_sum *sum; | 3614 | struct btrfs_ordered_sum *sum; |
@@ -3685,6 +3620,30 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3685 | mod_start + mod_len <= ordered->file_offset) | 3620 | mod_start + mod_len <= ordered->file_offset) |
3686 | continue; | 3621 | continue; |
3687 | 3622 | ||
3623 | if (!test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) && | ||
3624 | !test_bit(BTRFS_ORDERED_IOERR, &ordered->flags) && | ||
3625 | !test_bit(BTRFS_ORDERED_DIRECT, &ordered->flags)) { | ||
3626 | const u64 start = ordered->file_offset; | ||
3627 | const u64 end = ordered->file_offset + ordered->len - 1; | ||
3628 | |||
3629 | WARN_ON(ordered->inode != inode); | ||
3630 | filemap_fdatawrite_range(inode->i_mapping, start, end); | ||
3631 | } | ||
3632 | |||
3633 | wait_event(ordered->wait, | ||
3634 | (test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) || | ||
3635 | test_bit(BTRFS_ORDERED_IOERR, &ordered->flags))); | ||
3636 | |||
3637 | if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags)) { | ||
3638 | /* | ||
3639 | * Clear the AS_EIO/AS_ENOSPC flags from the inode's | ||
3640 | * i_mapping flags, so that the next fsync won't get | ||
3641 | * an outdated io error too. | ||
3642 | */ | ||
3643 | btrfs_inode_check_errors(inode); | ||
3644 | *ordered_io_error = true; | ||
3645 | break; | ||
3646 | } | ||
3688 | /* | 3647 | /* |
3689 | * We are going to copy all the csums on this ordered extent, so | 3648 | * We are going to copy all the csums on this ordered extent, so |
3690 | * go ahead and adjust mod_start and mod_len in case this | 3649 | * go ahead and adjust mod_start and mod_len in case this |
@@ -3716,6 +3675,9 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3716 | } | 3675 | } |
3717 | } | 3676 | } |
3718 | 3677 | ||
3678 | if (skip_csum) | ||
3679 | continue; | ||
3680 | |||
3719 | /* | 3681 | /* |
3720 | * To keep us from looping for the above case of an ordered | 3682 | * To keep us from looping for the above case of an ordered |
3721 | * extent that falls inside of the logged extent. | 3683 | * extent that falls inside of the logged extent. |
@@ -3733,18 +3695,16 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3733 | list_for_each_entry(sum, &ordered->list, list) { | 3695 | list_for_each_entry(sum, &ordered->list, list) { |
3734 | ret = btrfs_csum_file_blocks(trans, log, sum); | 3696 | ret = btrfs_csum_file_blocks(trans, log, sum); |
3735 | if (ret) | 3697 | if (ret) |
3736 | goto unlocked; | 3698 | break; |
3737 | } | 3699 | } |
3738 | |||
3739 | } | 3700 | } |
3740 | unlocked: | ||
3741 | 3701 | ||
3742 | if (!mod_len || ret) | 3702 | if (*ordered_io_error || !mod_len || ret || skip_csum) |
3743 | return ret; | 3703 | return ret; |
3744 | 3704 | ||
3745 | if (em->compress_type) { | 3705 | if (em->compress_type) { |
3746 | csum_offset = 0; | 3706 | csum_offset = 0; |
3747 | csum_len = block_len; | 3707 | csum_len = max(em->block_len, em->orig_block_len); |
3748 | } else { | 3708 | } else { |
3749 | csum_offset = mod_start - em->start; | 3709 | csum_offset = mod_start - em->start; |
3750 | csum_len = mod_len; | 3710 | csum_len = mod_len; |
@@ -3771,11 +3731,106 @@ unlocked: | |||
3771 | return ret; | 3731 | return ret; |
3772 | } | 3732 | } |
3773 | 3733 | ||
3734 | static int log_one_extent(struct btrfs_trans_handle *trans, | ||
3735 | struct inode *inode, struct btrfs_root *root, | ||
3736 | const struct extent_map *em, | ||
3737 | struct btrfs_path *path, | ||
3738 | const struct list_head *logged_list, | ||
3739 | struct btrfs_log_ctx *ctx) | ||
3740 | { | ||
3741 | struct btrfs_root *log = root->log_root; | ||
3742 | struct btrfs_file_extent_item *fi; | ||
3743 | struct extent_buffer *leaf; | ||
3744 | struct btrfs_map_token token; | ||
3745 | struct btrfs_key key; | ||
3746 | u64 extent_offset = em->start - em->orig_start; | ||
3747 | u64 block_len; | ||
3748 | int ret; | ||
3749 | int extent_inserted = 0; | ||
3750 | bool ordered_io_err = false; | ||
3751 | |||
3752 | ret = wait_ordered_extents(trans, inode, root, em, logged_list, | ||
3753 | &ordered_io_err); | ||
3754 | if (ret) | ||
3755 | return ret; | ||
3756 | |||
3757 | if (ordered_io_err) { | ||
3758 | ctx->io_err = -EIO; | ||
3759 | return 0; | ||
3760 | } | ||
3761 | |||
3762 | btrfs_init_map_token(&token); | ||
3763 | |||
3764 | ret = __btrfs_drop_extents(trans, log, inode, path, em->start, | ||
3765 | em->start + em->len, NULL, 0, 1, | ||
3766 | sizeof(*fi), &extent_inserted); | ||
3767 | if (ret) | ||
3768 | return ret; | ||
3769 | |||
3770 | if (!extent_inserted) { | ||
3771 | key.objectid = btrfs_ino(inode); | ||
3772 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
3773 | key.offset = em->start; | ||
3774 | |||
3775 | ret = btrfs_insert_empty_item(trans, log, path, &key, | ||
3776 | sizeof(*fi)); | ||
3777 | if (ret) | ||
3778 | return ret; | ||
3779 | } | ||
3780 | leaf = path->nodes[0]; | ||
3781 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
3782 | struct btrfs_file_extent_item); | ||
3783 | |||
3784 | btrfs_set_token_file_extent_generation(leaf, fi, trans->transid, | ||
3785 | &token); | ||
3786 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) | ||
3787 | btrfs_set_token_file_extent_type(leaf, fi, | ||
3788 | BTRFS_FILE_EXTENT_PREALLOC, | ||
3789 | &token); | ||
3790 | else | ||
3791 | btrfs_set_token_file_extent_type(leaf, fi, | ||
3792 | BTRFS_FILE_EXTENT_REG, | ||
3793 | &token); | ||
3794 | |||
3795 | block_len = max(em->block_len, em->orig_block_len); | ||
3796 | if (em->compress_type != BTRFS_COMPRESS_NONE) { | ||
3797 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, | ||
3798 | em->block_start, | ||
3799 | &token); | ||
3800 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len, | ||
3801 | &token); | ||
3802 | } else if (em->block_start < EXTENT_MAP_LAST_BYTE) { | ||
3803 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, | ||
3804 | em->block_start - | ||
3805 | extent_offset, &token); | ||
3806 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len, | ||
3807 | &token); | ||
3808 | } else { | ||
3809 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, 0, &token); | ||
3810 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, 0, | ||
3811 | &token); | ||
3812 | } | ||
3813 | |||
3814 | btrfs_set_token_file_extent_offset(leaf, fi, extent_offset, &token); | ||
3815 | btrfs_set_token_file_extent_num_bytes(leaf, fi, em->len, &token); | ||
3816 | btrfs_set_token_file_extent_ram_bytes(leaf, fi, em->ram_bytes, &token); | ||
3817 | btrfs_set_token_file_extent_compression(leaf, fi, em->compress_type, | ||
3818 | &token); | ||
3819 | btrfs_set_token_file_extent_encryption(leaf, fi, 0, &token); | ||
3820 | btrfs_set_token_file_extent_other_encoding(leaf, fi, 0, &token); | ||
3821 | btrfs_mark_buffer_dirty(leaf); | ||
3822 | |||
3823 | btrfs_release_path(path); | ||
3824 | |||
3825 | return ret; | ||
3826 | } | ||
3827 | |||
3774 | static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | 3828 | static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, |
3775 | struct btrfs_root *root, | 3829 | struct btrfs_root *root, |
3776 | struct inode *inode, | 3830 | struct inode *inode, |
3777 | struct btrfs_path *path, | 3831 | struct btrfs_path *path, |
3778 | struct list_head *logged_list) | 3832 | struct list_head *logged_list, |
3833 | struct btrfs_log_ctx *ctx) | ||
3779 | { | 3834 | { |
3780 | struct extent_map *em, *n; | 3835 | struct extent_map *em, *n; |
3781 | struct list_head extents; | 3836 | struct list_head extents; |
@@ -3833,7 +3888,8 @@ process: | |||
3833 | 3888 | ||
3834 | write_unlock(&tree->lock); | 3889 | write_unlock(&tree->lock); |
3835 | 3890 | ||
3836 | ret = log_one_extent(trans, inode, root, em, path, logged_list); | 3891 | ret = log_one_extent(trans, inode, root, em, path, logged_list, |
3892 | ctx); | ||
3837 | write_lock(&tree->lock); | 3893 | write_lock(&tree->lock); |
3838 | clear_em_logging(tree, em); | 3894 | clear_em_logging(tree, em); |
3839 | free_extent_map(em); | 3895 | free_extent_map(em); |
@@ -3863,7 +3919,8 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3863 | struct btrfs_root *root, struct inode *inode, | 3919 | struct btrfs_root *root, struct inode *inode, |
3864 | int inode_only, | 3920 | int inode_only, |
3865 | const loff_t start, | 3921 | const loff_t start, |
3866 | const loff_t end) | 3922 | const loff_t end, |
3923 | struct btrfs_log_ctx *ctx) | ||
3867 | { | 3924 | { |
3868 | struct btrfs_path *path; | 3925 | struct btrfs_path *path; |
3869 | struct btrfs_path *dst_path; | 3926 | struct btrfs_path *dst_path; |
@@ -3921,7 +3978,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3921 | 3978 | ||
3922 | mutex_lock(&BTRFS_I(inode)->log_mutex); | 3979 | mutex_lock(&BTRFS_I(inode)->log_mutex); |
3923 | 3980 | ||
3924 | btrfs_get_logged_extents(inode, &logged_list); | 3981 | btrfs_get_logged_extents(inode, &logged_list, start, end); |
3925 | 3982 | ||
3926 | /* | 3983 | /* |
3927 | * a brute force approach to making sure we get the most uptodate | 3984 | * a brute force approach to making sure we get the most uptodate |
@@ -3964,7 +4021,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3964 | err = ret; | 4021 | err = ret; |
3965 | goto out_unlock; | 4022 | goto out_unlock; |
3966 | } | 4023 | } |
3967 | path->keep_locks = 1; | ||
3968 | 4024 | ||
3969 | while (1) { | 4025 | while (1) { |
3970 | ins_nr = 0; | 4026 | ins_nr = 0; |
@@ -3994,7 +4050,8 @@ again: | |||
3994 | if (ret < 0) { | 4050 | if (ret < 0) { |
3995 | err = ret; | 4051 | err = ret; |
3996 | goto out_unlock; | 4052 | goto out_unlock; |
3997 | } if (ret) { | 4053 | } |
4054 | if (ret) { | ||
3998 | ins_nr = 0; | 4055 | ins_nr = 0; |
3999 | btrfs_release_path(path); | 4056 | btrfs_release_path(path); |
4000 | continue; | 4057 | continue; |
@@ -4047,8 +4104,23 @@ log_extents: | |||
4047 | btrfs_release_path(path); | 4104 | btrfs_release_path(path); |
4048 | btrfs_release_path(dst_path); | 4105 | btrfs_release_path(dst_path); |
4049 | if (fast_search) { | 4106 | if (fast_search) { |
4107 | /* | ||
4108 | * Some ordered extents started by fsync might have completed | ||
4109 | * before we collected the ordered extents in logged_list, which | ||
4110 | * means they're gone, not in our logged_list nor in the inode's | ||
4111 | * ordered tree. We want the application/user space to know an | ||
4112 | * error happened while attempting to persist file data so that | ||
4113 | * it can take proper action. If such error happened, we leave | ||
4114 | * without writing to the log tree and the fsync must report the | ||
4115 | * file data write error and not commit the current transaction. | ||
4116 | */ | ||
4117 | err = btrfs_inode_check_errors(inode); | ||
4118 | if (err) { | ||
4119 | ctx->io_err = err; | ||
4120 | goto out_unlock; | ||
4121 | } | ||
4050 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path, | 4122 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path, |
4051 | &logged_list); | 4123 | &logged_list, ctx); |
4052 | if (ret) { | 4124 | if (ret) { |
4053 | err = ret; | 4125 | err = ret; |
4054 | goto out_unlock; | 4126 | goto out_unlock; |
@@ -4238,7 +4310,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
4238 | if (ret) | 4310 | if (ret) |
4239 | goto end_no_trans; | 4311 | goto end_no_trans; |
4240 | 4312 | ||
4241 | ret = btrfs_log_inode(trans, root, inode, inode_only, start, end); | 4313 | ret = btrfs_log_inode(trans, root, inode, inode_only, start, end, ctx); |
4242 | if (ret) | 4314 | if (ret) |
4243 | goto end_trans; | 4315 | goto end_trans; |
4244 | 4316 | ||
@@ -4267,7 +4339,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
4267 | if (BTRFS_I(inode)->generation > | 4339 | if (BTRFS_I(inode)->generation > |
4268 | root->fs_info->last_trans_committed) { | 4340 | root->fs_info->last_trans_committed) { |
4269 | ret = btrfs_log_inode(trans, root, inode, inode_only, | 4341 | ret = btrfs_log_inode(trans, root, inode, inode_only, |
4270 | 0, LLONG_MAX); | 4342 | 0, LLONG_MAX, ctx); |
4271 | if (ret) | 4343 | if (ret) |
4272 | goto end_trans; | 4344 | goto end_trans; |
4273 | } | 4345 | } |
@@ -4359,7 +4431,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) | |||
4359 | again: | 4431 | again: |
4360 | key.objectid = BTRFS_TREE_LOG_OBJECTID; | 4432 | key.objectid = BTRFS_TREE_LOG_OBJECTID; |
4361 | key.offset = (u64)-1; | 4433 | key.offset = (u64)-1; |
4362 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | 4434 | key.type = BTRFS_ROOT_ITEM_KEY; |
4363 | 4435 | ||
4364 | while (1) { | 4436 | while (1) { |
4365 | ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0); | 4437 | ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0); |