diff options
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 15 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 21 |
3 files changed, 37 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index a9466e346358..49d956b2cf30 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -3866,6 +3866,7 @@ int btrfs_prealloc_file_range_trans(struct inode *inode, | |||
3866 | struct btrfs_trans_handle *trans, int mode, | 3866 | struct btrfs_trans_handle *trans, int mode, |
3867 | u64 start, u64 num_bytes, u64 min_size, | 3867 | u64 start, u64 num_bytes, u64 min_size, |
3868 | loff_t actual_len, u64 *alloc_hint); | 3868 | loff_t actual_len, u64 *alloc_hint); |
3869 | int btrfs_inode_check_errors(struct inode *inode); | ||
3869 | extern const struct dentry_operations btrfs_dentry_operations; | 3870 | extern const struct dentry_operations btrfs_dentry_operations; |
3870 | 3871 | ||
3871 | /* ioctl.c */ | 3872 | /* ioctl.c */ |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index cb5978a4a277..a5374c2bb943 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -9464,6 +9464,21 @@ out_inode: | |||
9464 | 9464 | ||
9465 | } | 9465 | } |
9466 | 9466 | ||
9467 | /* Inspired by filemap_check_errors() */ | ||
9468 | int btrfs_inode_check_errors(struct inode *inode) | ||
9469 | { | ||
9470 | int ret = 0; | ||
9471 | |||
9472 | if (test_bit(AS_ENOSPC, &inode->i_mapping->flags) && | ||
9473 | test_and_clear_bit(AS_ENOSPC, &inode->i_mapping->flags)) | ||
9474 | ret = -ENOSPC; | ||
9475 | if (test_bit(AS_EIO, &inode->i_mapping->flags) && | ||
9476 | test_and_clear_bit(AS_EIO, &inode->i_mapping->flags)) | ||
9477 | ret = -EIO; | ||
9478 | |||
9479 | return ret; | ||
9480 | } | ||
9481 | |||
9467 | static const struct inode_operations btrfs_dir_inode_operations = { | 9482 | static const struct inode_operations btrfs_dir_inode_operations = { |
9468 | .getattr = btrfs_getattr, | 9483 | .getattr = btrfs_getattr, |
9469 | .lookup = btrfs_lookup, | 9484 | .lookup = btrfs_lookup, |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 3883d0febd82..9a02da16f2be 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -3635,6 +3635,12 @@ static int wait_ordered_extents(struct btrfs_trans_handle *trans, | |||
3635 | test_bit(BTRFS_ORDERED_IOERR, &ordered->flags))); | 3635 | test_bit(BTRFS_ORDERED_IOERR, &ordered->flags))); |
3636 | 3636 | ||
3637 | 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); | ||
3638 | *ordered_io_error = true; | 3644 | *ordered_io_error = true; |
3639 | break; | 3645 | break; |
3640 | } | 3646 | } |
@@ -4098,6 +4104,21 @@ log_extents: | |||
4098 | btrfs_release_path(path); | 4104 | btrfs_release_path(path); |
4099 | btrfs_release_path(dst_path); | 4105 | btrfs_release_path(dst_path); |
4100 | 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 | } | ||
4101 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path, | 4122 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path, |
4102 | &logged_list, ctx); | 4123 | &logged_list, ctx); |
4103 | if (ret) { | 4124 | if (ret) { |