diff options
Diffstat (limited to 'fs/xfs/xfs_aops.c')
-rw-r--r-- | fs/xfs/xfs_aops.c | 59 |
1 files changed, 27 insertions, 32 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index bf65a9ea8642..61494295d92f 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c | |||
@@ -274,54 +274,49 @@ xfs_end_io( | |||
274 | struct xfs_ioend *ioend = | 274 | struct xfs_ioend *ioend = |
275 | container_of(work, struct xfs_ioend, io_work); | 275 | container_of(work, struct xfs_ioend, io_work); |
276 | struct xfs_inode *ip = XFS_I(ioend->io_inode); | 276 | struct xfs_inode *ip = XFS_I(ioend->io_inode); |
277 | xfs_off_t offset = ioend->io_offset; | ||
278 | size_t size = ioend->io_size; | ||
277 | int error = ioend->io_bio->bi_error; | 279 | int error = ioend->io_bio->bi_error; |
278 | 280 | ||
279 | /* | 281 | /* |
280 | * Set an error if the mount has shut down and proceed with end I/O | 282 | * Just clean up the in-memory strutures if the fs has been shut down. |
281 | * processing so it can perform whatever cleanups are necessary. | ||
282 | */ | 283 | */ |
283 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | 284 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { |
284 | error = -EIO; | 285 | error = -EIO; |
286 | goto done; | ||
287 | } | ||
285 | 288 | ||
286 | /* | 289 | /* |
287 | * For a CoW extent, we need to move the mapping from the CoW fork | 290 | * Clean up any COW blocks on an I/O error. |
288 | * to the data fork. If instead an error happened, just dump the | ||
289 | * new blocks. | ||
290 | */ | 291 | */ |
291 | if (ioend->io_type == XFS_IO_COW) { | 292 | if (unlikely(error)) { |
292 | if (error) | 293 | switch (ioend->io_type) { |
293 | goto done; | 294 | case XFS_IO_COW: |
294 | if (ioend->io_bio->bi_error) { | 295 | xfs_reflink_cancel_cow_range(ip, offset, size, true); |
295 | error = xfs_reflink_cancel_cow_range(ip, | 296 | break; |
296 | ioend->io_offset, ioend->io_size); | ||
297 | goto done; | ||
298 | } | 297 | } |
299 | error = xfs_reflink_end_cow(ip, ioend->io_offset, | 298 | |
300 | ioend->io_size); | 299 | goto done; |
301 | if (error) | ||
302 | goto done; | ||
303 | } | 300 | } |
304 | 301 | ||
305 | /* | 302 | /* |
306 | * For unwritten extents we need to issue transactions to convert a | 303 | * Success: commit the COW or unwritten blocks if needed. |
307 | * range to normal written extens after the data I/O has finished. | ||
308 | * Detecting and handling completion IO errors is done individually | ||
309 | * for each case as different cleanup operations need to be performed | ||
310 | * on error. | ||
311 | */ | 304 | */ |
312 | if (ioend->io_type == XFS_IO_UNWRITTEN) { | 305 | switch (ioend->io_type) { |
313 | if (error) | 306 | case XFS_IO_COW: |
314 | goto done; | 307 | error = xfs_reflink_end_cow(ip, offset, size); |
315 | error = xfs_iomap_write_unwritten(ip, ioend->io_offset, | 308 | break; |
316 | ioend->io_size); | 309 | case XFS_IO_UNWRITTEN: |
317 | } else if (ioend->io_append_trans) { | 310 | error = xfs_iomap_write_unwritten(ip, offset, size); |
318 | error = xfs_setfilesize_ioend(ioend, error); | 311 | break; |
319 | } else { | 312 | default: |
320 | ASSERT(!xfs_ioend_is_append(ioend) || | 313 | ASSERT(!xfs_ioend_is_append(ioend) || ioend->io_append_trans); |
321 | ioend->io_type == XFS_IO_COW); | 314 | break; |
322 | } | 315 | } |
323 | 316 | ||
324 | done: | 317 | done: |
318 | if (ioend->io_append_trans) | ||
319 | error = xfs_setfilesize_ioend(ioend, error); | ||
325 | xfs_destroy_ioend(ioend, error); | 320 | xfs_destroy_ioend(ioend, error); |
326 | } | 321 | } |
327 | 322 | ||