aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_buf.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-12-12 00:34:38 -0500
committerBen Myers <bpm@sgi.com>2013-12-17 10:40:23 -0500
commitac8809f9ab01a73de1a47b5a37bd8dcca8712fb3 (patch)
tree69be412f26ab598149abe559fc1541a14b151a07 /fs/xfs/xfs_buf.c
parent33177f05364c6cd13b06d0f3500dad07cf4647c2 (diff)
xfs: abort metadata writeback on permanent errors
If we are doing aysnc writeback of metadata, we can get write errors but have nobody to report them to. At the moment, we simply attempt to reissue the write from io completion in the hope that it's a transient error. When it's not a transient error, the buffer is stuck forever in this loop, and we cannot break out of it. Eventually, unmount will hang because the AIL cannot be emptied and everything goes downhill from them. To solve this problem, only retry the write IO once before aborting it. We don't throw the buffer away because some transient errors can last minutes (e.g. FC path failover) or even hours (thin provisioned devices that have run out of backing space) before they go away. Hence we really want to keep trying until we can't try any more. Because the buffer was not cleaned, however, it does not get removed from the AIL and hence the next pass across the AIL will start IO on it again. As such, we still get the "retry forever" semantics that we currently have, but we allow other access to the buffer in the mean time. Meanwhile the filesystem can continue to modify the buffer and relog it, so the IO errors won't hang the log or the filesystem. Now when we are pushing the AIL, we can see all these "permanent IO error" buffers and we can issue a warning about failures before we retry the IO. We can also catch these buffers when unmounting an issue a corruption warning, too. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_buf.c')
-rw-r--r--fs/xfs/xfs_buf.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 9fa9c4304613..afe7645e4b2b 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -1156,7 +1156,7 @@ xfs_bwrite(
1156 ASSERT(xfs_buf_islocked(bp)); 1156 ASSERT(xfs_buf_islocked(bp));
1157 1157
1158 bp->b_flags |= XBF_WRITE; 1158 bp->b_flags |= XBF_WRITE;
1159 bp->b_flags &= ~(XBF_ASYNC | XBF_READ | _XBF_DELWRI_Q); 1159 bp->b_flags &= ~(XBF_ASYNC | XBF_READ | _XBF_DELWRI_Q | XBF_WRITE_FAIL);
1160 1160
1161 xfs_bdstrat_cb(bp); 1161 xfs_bdstrat_cb(bp);
1162 1162
@@ -1501,6 +1501,12 @@ xfs_wait_buftarg(
1501 struct xfs_buf *bp; 1501 struct xfs_buf *bp;
1502 bp = list_first_entry(&dispose, struct xfs_buf, b_lru); 1502 bp = list_first_entry(&dispose, struct xfs_buf, b_lru);
1503 list_del_init(&bp->b_lru); 1503 list_del_init(&bp->b_lru);
1504 if (bp->b_flags & XBF_WRITE_FAIL) {
1505 xfs_alert(btp->bt_mount,
1506"Corruption Alert: Buffer at block 0x%llx had permanent write failures!\n"
1507"Please run xfs_repair to determine the extent of the problem.",
1508 (long long)bp->b_bn);
1509 }
1504 xfs_buf_rele(bp); 1510 xfs_buf_rele(bp);
1505 } 1511 }
1506 if (loop++ != 0) 1512 if (loop++ != 0)
@@ -1784,7 +1790,7 @@ __xfs_buf_delwri_submit(
1784 1790
1785 blk_start_plug(&plug); 1791 blk_start_plug(&plug);
1786 list_for_each_entry_safe(bp, n, io_list, b_list) { 1792 list_for_each_entry_safe(bp, n, io_list, b_list) {
1787 bp->b_flags &= ~(_XBF_DELWRI_Q | XBF_ASYNC); 1793 bp->b_flags &= ~(_XBF_DELWRI_Q | XBF_ASYNC | XBF_WRITE_FAIL);
1788 bp->b_flags |= XBF_WRITE; 1794 bp->b_flags |= XBF_WRITE;
1789 1795
1790 if (!wait) { 1796 if (!wait) {