diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 50 |
1 files changed, 40 insertions, 10 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 286213cec861..9a02da16f2be 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -2599,12 +2599,14 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2599 | index2 = root_log_ctx.log_transid % 2; | 2599 | index2 = root_log_ctx.log_transid % 2; |
2600 | if (atomic_read(&log_root_tree->log_commit[index2])) { | 2600 | if (atomic_read(&log_root_tree->log_commit[index2])) { |
2601 | blk_finish_plug(&plug); | 2601 | blk_finish_plug(&plug); |
2602 | 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); | ||
2603 | wait_log_commit(trans, log_root_tree, | 2605 | wait_log_commit(trans, log_root_tree, |
2604 | root_log_ctx.log_transid); | 2606 | root_log_ctx.log_transid); |
2605 | btrfs_free_logged_extents(log, log_transid); | ||
2606 | mutex_unlock(&log_root_tree->log_mutex); | 2607 | mutex_unlock(&log_root_tree->log_mutex); |
2607 | ret = root_log_ctx.log_ret; | 2608 | if (!ret) |
2609 | ret = root_log_ctx.log_ret; | ||
2608 | goto out; | 2610 | goto out; |
2609 | } | 2611 | } |
2610 | ASSERT(root_log_ctx.log_transid == log_root_tree->log_transid); | 2612 | ASSERT(root_log_ctx.log_transid == log_root_tree->log_transid); |
@@ -2641,11 +2643,18 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2641 | mutex_unlock(&log_root_tree->log_mutex); | 2643 | mutex_unlock(&log_root_tree->log_mutex); |
2642 | goto out_wake_log_root; | 2644 | goto out_wake_log_root; |
2643 | } | 2645 | } |
2644 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2646 | ret = btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); |
2645 | btrfs_wait_marked_extents(log_root_tree, | 2647 | if (!ret) |
2646 | &log_root_tree->dirty_log_pages, | 2648 | ret = btrfs_wait_marked_extents(log_root_tree, |
2647 | EXTENT_NEW | EXTENT_DIRTY); | 2649 | &log_root_tree->dirty_log_pages, |
2648 | 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); | ||
2649 | 2658 | ||
2650 | btrfs_set_super_log_root(root->fs_info->super_for_commit, | 2659 | btrfs_set_super_log_root(root->fs_info->super_for_commit, |
2651 | log_root_tree->node->start); | 2660 | log_root_tree->node->start); |
@@ -3626,6 +3635,12 @@ static int wait_ordered_extents(struct btrfs_trans_handle *trans, | |||
3626 | test_bit(BTRFS_ORDERED_IOERR, &ordered->flags))); | 3635 | test_bit(BTRFS_ORDERED_IOERR, &ordered->flags))); |
3627 | 3636 | ||
3628 | if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags)) { | 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); | ||
3629 | *ordered_io_error = true; | 3644 | *ordered_io_error = true; |
3630 | break; | 3645 | break; |
3631 | } | 3646 | } |
@@ -3766,7 +3781,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3766 | fi = btrfs_item_ptr(leaf, path->slots[0], | 3781 | fi = btrfs_item_ptr(leaf, path->slots[0], |
3767 | struct btrfs_file_extent_item); | 3782 | struct btrfs_file_extent_item); |
3768 | 3783 | ||
3769 | btrfs_set_token_file_extent_generation(leaf, fi, em->generation, | 3784 | btrfs_set_token_file_extent_generation(leaf, fi, trans->transid, |
3770 | &token); | 3785 | &token); |
3771 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) | 3786 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) |
3772 | btrfs_set_token_file_extent_type(leaf, fi, | 3787 | btrfs_set_token_file_extent_type(leaf, fi, |
@@ -3963,7 +3978,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3963 | 3978 | ||
3964 | mutex_lock(&BTRFS_I(inode)->log_mutex); | 3979 | mutex_lock(&BTRFS_I(inode)->log_mutex); |
3965 | 3980 | ||
3966 | btrfs_get_logged_extents(inode, &logged_list); | 3981 | btrfs_get_logged_extents(inode, &logged_list, start, end); |
3967 | 3982 | ||
3968 | /* | 3983 | /* |
3969 | * 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 |
@@ -4089,6 +4104,21 @@ log_extents: | |||
4089 | btrfs_release_path(path); | 4104 | btrfs_release_path(path); |
4090 | btrfs_release_path(dst_path); | 4105 | btrfs_release_path(dst_path); |
4091 | 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 | } | ||
4092 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path, | 4122 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path, |
4093 | &logged_list, ctx); | 4123 | &logged_list, ctx); |
4094 | if (ret) { | 4124 | if (ret) { |