Skip to content

Commit 73f6aa4

Browse files
Christoph Hellwigtorvalds
authored andcommitted
Fix barrier fail detection in XFS
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 <[email protected]> Reviewed-by: Eric Sandeen <[email protected]> Reviewed-by: David Chinner <[email protected]> Signed-off-by: Tim Shimmin <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 445e1ce commit 73f6aa4

File tree

3 files changed

+14
-4
lines changed

3 files changed

+14
-4
lines changed

fs/xfs/linux-2.6/xfs_buf.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1001,12 +1001,13 @@ xfs_buf_iodone_work(
10011001
* We can get an EOPNOTSUPP to ordered writes. Here we clear the
10021002
* ordered flag and reissue them. Because we can't tell the higher
10031003
* layers directly that they should not issue ordered I/O anymore, they
1004-
* need to check if the ordered flag was cleared during I/O completion.
1004+
* need to check if the _XFS_BARRIER_FAILED flag was set during I/O completion.
10051005
*/
10061006
if ((bp->b_error == EOPNOTSUPP) &&
10071007
(bp->b_flags & (XBF_ORDERED|XBF_ASYNC)) == (XBF_ORDERED|XBF_ASYNC)) {
10081008
XB_TRACE(bp, "ordered_retry", bp->b_iodone);
10091009
bp->b_flags &= ~XBF_ORDERED;
1010+
bp->b_flags |= _XFS_BARRIER_FAILED;
10101011
xfs_buf_iorequest(bp);
10111012
} else if (bp->b_iodone)
10121013
(*(bp->b_iodone))(bp);

fs/xfs/linux-2.6/xfs_buf.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,14 @@ typedef enum {
8585
* modifications being lost.
8686
*/
8787
_XBF_PAGE_LOCKED = (1 << 22),
88+
89+
/*
90+
* If we try a barrier write, but it fails we have to communicate
91+
* this to the upper layers. Unfortunately b_error gets overwritten
92+
* when the buffer is re-issued so we have to add another flag to
93+
* keep this information.
94+
*/
95+
_XFS_BARRIER_FAILED = (1 << 23),
8896
} xfs_buf_flags_t;
8997

9098
typedef enum {

fs/xfs/xfs_log.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,11 +1033,12 @@ xlog_iodone(xfs_buf_t *bp)
10331033
l = iclog->ic_log;
10341034

10351035
/*
1036-
* If the ordered flag has been removed by a lower
1037-
* layer, it means the underlyin device no longer supports
1036+
* If the _XFS_BARRIER_FAILED flag was set by a lower
1037+
* layer, it means the underlying device no longer supports
10381038
* barrier I/O. Warn loudly and turn off barriers.
10391039
*/
1040-
if ((l->l_mp->m_flags & XFS_MOUNT_BARRIER) && !XFS_BUF_ISORDERED(bp)) {
1040+
if (bp->b_flags & _XFS_BARRIER_FAILED) {
1041+
bp->b_flags &= ~_XFS_BARRIER_FAILED;
10411042
l->l_mp->m_flags &= ~XFS_MOUNT_BARRIER;
10421043
xfs_fs_cmn_err(CE_WARN, l->l_mp,
10431044
"xlog_iodone: Barriers are no longer supported"

0 commit comments

Comments
 (0)