| From 73f6aa4d44ab6157badc456ddfa05b31e58de5f0 Mon Sep 17 00:00:00 2001 |
| From: Christoph Hellwig <hch@lst.de> |
| Date: Fri, 10 Oct 2008 17:28:29 +1100 |
| Subject: Fix barrier fail detection in XFS |
| |
| From: Christoph Hellwig <hch@lst.de> |
| |
| commit 73f6aa4d44ab6157badc456ddfa05b31e58de5f0 upstream. |
| |
| Currently we disable barriers as soon as we get a buffer in xlog_iodone |
| that has the XBF_ORDERED flag cleared. But this can be the case not only |
| for buffers where the barrier failed, but also the first buffer of a |
| split log write in case of a log wraparound. Due to the disabled |
| barriers we can easily get directory corruption on unclean shutdowns. |
| So instead of using this check add a new buffer flag for failed barrier |
| writes. |
| |
| This is a regression vs 2.6.26 caused by patch to use the right macro |
| to check for the ORDERED flag, as we previously got true returned for |
| every buffer. |
| |
| Thanks to Toei Rei for reporting the bug. |
| |
| Signed-off-by: Christoph Hellwig <hch@lst.de> |
| Reviewed-by: Eric Sandeen <sandeen@sandeen.net> |
| Reviewed-by: David Chinner <david@fromorbit.com> |
| Signed-off-by: Tim Shimmin <tes@sgi.com> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| fs/xfs/linux-2.6/xfs_buf.c | 3 ++- |
| fs/xfs/linux-2.6/xfs_buf.h | 8 ++++++++ |
| fs/xfs/xfs_log.c | 7 ++++--- |
| 3 files changed, 14 insertions(+), 4 deletions(-) |
| |
| --- a/fs/xfs/linux-2.6/xfs_buf.c |
| +++ b/fs/xfs/linux-2.6/xfs_buf.c |
| @@ -1001,12 +1001,13 @@ xfs_buf_iodone_work( |
| * We can get an EOPNOTSUPP to ordered writes. Here we clear the |
| * ordered flag and reissue them. Because we can't tell the higher |
| * layers directly that they should not issue ordered I/O anymore, they |
| - * need to check if the ordered flag was cleared during I/O completion. |
| + * need to check if the _XFS_BARRIER_FAILED flag was set during I/O completion. |
| */ |
| if ((bp->b_error == EOPNOTSUPP) && |
| (bp->b_flags & (XBF_ORDERED|XBF_ASYNC)) == (XBF_ORDERED|XBF_ASYNC)) { |
| XB_TRACE(bp, "ordered_retry", bp->b_iodone); |
| bp->b_flags &= ~XBF_ORDERED; |
| + bp->b_flags |= _XFS_BARRIER_FAILED; |
| xfs_buf_iorequest(bp); |
| } else if (bp->b_iodone) |
| (*(bp->b_iodone))(bp); |
| --- a/fs/xfs/linux-2.6/xfs_buf.h |
| +++ b/fs/xfs/linux-2.6/xfs_buf.h |
| @@ -85,6 +85,14 @@ typedef enum { |
| * modifications being lost. |
| */ |
| _XBF_PAGE_LOCKED = (1 << 22), |
| + |
| + /* |
| + * If we try a barrier write, but it fails we have to communicate |
| + * this to the upper layers. Unfortunately b_error gets overwritten |
| + * when the buffer is re-issued so we have to add another flag to |
| + * keep this information. |
| + */ |
| + _XFS_BARRIER_FAILED = (1 << 23), |
| } xfs_buf_flags_t; |
| |
| typedef enum { |
| --- a/fs/xfs/xfs_log.c |
| +++ b/fs/xfs/xfs_log.c |
| @@ -1033,11 +1033,12 @@ xlog_iodone(xfs_buf_t *bp) |
| l = iclog->ic_log; |
| |
| /* |
| - * If the ordered flag has been removed by a lower |
| - * layer, it means the underlyin device no longer supports |
| + * If the _XFS_BARRIER_FAILED flag was set by a lower |
| + * layer, it means the underlying device no longer supports |
| * barrier I/O. Warn loudly and turn off barriers. |
| */ |
| - if ((l->l_mp->m_flags & XFS_MOUNT_BARRIER) && !XFS_BUF_ISORDERED(bp)) { |
| + if (bp->b_flags & _XFS_BARRIER_FAILED) { |
| + bp->b_flags &= ~_XFS_BARRIER_FAILED; |
| l->l_mp->m_flags &= ~XFS_MOUNT_BARRIER; |
| xfs_fs_cmn_err(CE_WARN, l->l_mp, |
| "xlog_iodone: Barriers are no longer supported" |