Commit d07b5855 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Greg Kroah-Hartman

xfs: fix and streamline error handling in xfs_end_io

commit 787eb485 upstream.

There are two different cases of buffered I/O errors:

 - first we can have an already shutdown fs.  In that case we should skip
   any on-disk operations and just clean up the appen transaction if
   present and destroy the ioend
 - a real I/O error.  In that case we should cleanup any lingering COW
   blocks.  This gets skipped in the current code and is fixed by this
   patch.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3b83a02a
...@@ -279,54 +279,49 @@ xfs_end_io( ...@@ -279,54 +279,49 @@ xfs_end_io(
struct xfs_ioend *ioend = struct xfs_ioend *ioend =
container_of(work, struct xfs_ioend, io_work); container_of(work, struct xfs_ioend, io_work);
struct xfs_inode *ip = XFS_I(ioend->io_inode); struct xfs_inode *ip = XFS_I(ioend->io_inode);
xfs_off_t offset = ioend->io_offset;
size_t size = ioend->io_size;
int error = ioend->io_bio->bi_error; int error = ioend->io_bio->bi_error;
/* /*
* Set an error if the mount has shut down and proceed with end I/O * Just clean up the in-memory strutures if the fs has been shut down.
* processing so it can perform whatever cleanups are necessary.
*/ */
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
error = -EIO; error = -EIO;
goto done;
}
/* /*
* For a CoW extent, we need to move the mapping from the CoW fork * Clean up any COW blocks on an I/O error.
* to the data fork. If instead an error happened, just dump the
* new blocks.
*/ */
if (ioend->io_type == XFS_IO_COW) { if (unlikely(error)) {
if (error) switch (ioend->io_type) {
goto done; case XFS_IO_COW:
if (ioend->io_bio->bi_error) { xfs_reflink_cancel_cow_range(ip, offset, size, true);
error = xfs_reflink_cancel_cow_range(ip, break;
ioend->io_offset, ioend->io_size, true);
goto done;
} }
error = xfs_reflink_end_cow(ip, ioend->io_offset,
ioend->io_size); goto done;
if (error)
goto done;
} }
/* /*
* For unwritten extents we need to issue transactions to convert a * Success: commit the COW or unwritten blocks if needed.
* range to normal written extens after the data I/O has finished.
* Detecting and handling completion IO errors is done individually
* for each case as different cleanup operations need to be performed
* on error.
*/ */
if (ioend->io_type == XFS_IO_UNWRITTEN) { switch (ioend->io_type) {
if (error) case XFS_IO_COW:
goto done; error = xfs_reflink_end_cow(ip, offset, size);
error = xfs_iomap_write_unwritten(ip, ioend->io_offset, break;
ioend->io_size); case XFS_IO_UNWRITTEN:
} else if (ioend->io_append_trans) { error = xfs_iomap_write_unwritten(ip, offset, size);
error = xfs_setfilesize_ioend(ioend, error); break;
} else { default:
ASSERT(!xfs_ioend_is_append(ioend) || ASSERT(!xfs_ioend_is_append(ioend) || ioend->io_append_trans);
ioend->io_type == XFS_IO_COW); break;
} }
done: done:
if (ioend->io_append_trans)
error = xfs_setfilesize_ioend(ioend, error);
xfs_destroy_ioend(ioend, error); xfs_destroy_ioend(ioend, error);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment