diff options
Diffstat (limited to 'fs/xfs/xfs_aops.c')
-rw-r--r-- | fs/xfs/xfs_aops.c | 54 |
1 files changed, 39 insertions, 15 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index e562dd43f41f..e57e2daa357c 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c | |||
@@ -481,11 +481,17 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh) | |||
481 | * | 481 | * |
482 | * The fix is two passes across the ioend list - one to start writeback on the | 482 | * The fix is two passes across the ioend list - one to start writeback on the |
483 | * buffer_heads, and then submit them for I/O on the second pass. | 483 | * buffer_heads, and then submit them for I/O on the second pass. |
484 | * | ||
485 | * If @fail is non-zero, it means that we have a situation where some part of | ||
486 | * the submission process has failed after we have marked paged for writeback | ||
487 | * and unlocked them. In this situation, we need to fail the ioend chain rather | ||
488 | * than submit it to IO. This typically only happens on a filesystem shutdown. | ||
484 | */ | 489 | */ |
485 | STATIC void | 490 | STATIC void |
486 | xfs_submit_ioend( | 491 | xfs_submit_ioend( |
487 | struct writeback_control *wbc, | 492 | struct writeback_control *wbc, |
488 | xfs_ioend_t *ioend) | 493 | xfs_ioend_t *ioend, |
494 | int fail) | ||
489 | { | 495 | { |
490 | xfs_ioend_t *head = ioend; | 496 | xfs_ioend_t *head = ioend; |
491 | xfs_ioend_t *next; | 497 | xfs_ioend_t *next; |
@@ -506,6 +512,18 @@ xfs_submit_ioend( | |||
506 | next = ioend->io_list; | 512 | next = ioend->io_list; |
507 | bio = NULL; | 513 | bio = NULL; |
508 | 514 | ||
515 | /* | ||
516 | * If we are failing the IO now, just mark the ioend with an | ||
517 | * error and finish it. This will run IO completion immediately | ||
518 | * as there is only one reference to the ioend at this point in | ||
519 | * time. | ||
520 | */ | ||
521 | if (fail) { | ||
522 | ioend->io_error = -fail; | ||
523 | xfs_finish_ioend(ioend); | ||
524 | continue; | ||
525 | } | ||
526 | |||
509 | for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) { | 527 | for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) { |
510 | 528 | ||
511 | if (!bio) { | 529 | if (!bio) { |
@@ -1060,7 +1078,18 @@ xfs_vm_writepage( | |||
1060 | 1078 | ||
1061 | xfs_start_page_writeback(page, 1, count); | 1079 | xfs_start_page_writeback(page, 1, count); |
1062 | 1080 | ||
1063 | if (ioend && imap_valid) { | 1081 | /* if there is no IO to be submitted for this page, we are done */ |
1082 | if (!ioend) | ||
1083 | return 0; | ||
1084 | |||
1085 | ASSERT(iohead); | ||
1086 | |||
1087 | /* | ||
1088 | * Any errors from this point onwards need tobe reported through the IO | ||
1089 | * completion path as we have marked the initial page as under writeback | ||
1090 | * and unlocked it. | ||
1091 | */ | ||
1092 | if (imap_valid) { | ||
1064 | xfs_off_t end_index; | 1093 | xfs_off_t end_index; |
1065 | 1094 | ||
1066 | end_index = imap.br_startoff + imap.br_blockcount; | 1095 | end_index = imap.br_startoff + imap.br_blockcount; |
@@ -1079,20 +1108,15 @@ xfs_vm_writepage( | |||
1079 | wbc, end_index); | 1108 | wbc, end_index); |
1080 | } | 1109 | } |
1081 | 1110 | ||
1082 | if (iohead) { | ||
1083 | /* | ||
1084 | * Reserve log space if we might write beyond the on-disk | ||
1085 | * inode size. | ||
1086 | */ | ||
1087 | if (ioend->io_type != XFS_IO_UNWRITTEN && | ||
1088 | xfs_ioend_is_append(ioend)) { | ||
1089 | err = xfs_setfilesize_trans_alloc(ioend); | ||
1090 | if (err) | ||
1091 | goto error; | ||
1092 | } | ||
1093 | 1111 | ||
1094 | xfs_submit_ioend(wbc, iohead); | 1112 | /* |
1095 | } | 1113 | * Reserve log space if we might write beyond the on-disk inode size. |
1114 | */ | ||
1115 | err = 0; | ||
1116 | if (ioend->io_type != XFS_IO_UNWRITTEN && xfs_ioend_is_append(ioend)) | ||
1117 | err = xfs_setfilesize_trans_alloc(ioend); | ||
1118 | |||
1119 | xfs_submit_ioend(wbc, iohead, err); | ||
1096 | 1120 | ||
1097 | return 0; | 1121 | return 0; |
1098 | 1122 | ||