aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-08-26 21:39:37 -0400
committerBen Myers <bpm@sgi.com>2013-08-30 14:45:49 -0400
commitd8914002a0391331a88d9f5de4a235220735d4cc (patch)
tree4fbdcc1bae11941554c98651985878cf1e47ad36 /fs/xfs
parent50d5c8d8e938e3c4c0d21db9fc7d64282dc7be20 (diff)
xfs: inode buffers may not be valid during recovery readahead
CRC enabled filesystems fail log recovery with 100% reliability on xfstests xfs/085 with the following failure: XFS (vdb): Mounting Filesystem XFS (vdb): Starting recovery (logdev: internal) XFS (vdb): Corruption detected. Unmount and run xfs_repair XFS (vdb): bad inode magic/vsn daddr 144 #0 (magic=0) XFS: Assertion failed: 0, file: fs/xfs/xfs_inode_buf.c, line: 95 The problem is that the inode buffer has not been recovered before the readahead on the inode buffer is issued. The checkpoint being recovered actually allocates the inode chunk we are doing readahead from, so what comes from disk during readahead is essentially random and the verifier barfs on it. This inode buffer readahead problem affects non-crc filesystems, too, but xfstests does not trigger it at all on such configurations.... Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Ben Myers <bpm@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_inode_buf.c36
-rw-r--r--fs/xfs/xfs_inode_buf.h1
-rw-r--r--fs/xfs/xfs_log_recover.c2
3 files changed, 35 insertions, 4 deletions
diff --git a/fs/xfs/xfs_inode_buf.c b/fs/xfs/xfs_inode_buf.c
index 38fe509827dd..e011d597f12f 100644
--- a/fs/xfs/xfs_inode_buf.c
+++ b/fs/xfs/xfs_inode_buf.c
@@ -61,9 +61,22 @@ xfs_inobp_check(
61} 61}
62#endif 62#endif
63 63
64/*
65 * If we are doing readahead on an inode buffer, we might be in log recovery
66 * reading an inode allocation buffer that hasn't yet been replayed, and hence
67 * has not had the inode cores stamped into it. Hence for readahead, the buffer
68 * may be potentially invalid.
69 *
70 * If the readahead buffer is invalid, we don't want to mark it with an error,
71 * but we do want to clear the DONE status of the buffer so that a followup read
72 * will re-read it from disk. This will ensure that we don't get an unnecessary
73 * warnings during log recovery and we don't get unnecssary panics on debug
74 * kernels.
75 */
64static void 76static void
65xfs_inode_buf_verify( 77xfs_inode_buf_verify(
66 struct xfs_buf *bp) 78 struct xfs_buf *bp,
79 bool readahead)
67{ 80{
68 struct xfs_mount *mp = bp->b_target->bt_mount; 81 struct xfs_mount *mp = bp->b_target->bt_mount;
69 int i; 82 int i;
@@ -84,6 +97,11 @@ xfs_inode_buf_verify(
84 if (unlikely(XFS_TEST_ERROR(!di_ok, mp, 97 if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
85 XFS_ERRTAG_ITOBP_INOTOBP, 98 XFS_ERRTAG_ITOBP_INOTOBP,
86 XFS_RANDOM_ITOBP_INOTOBP))) { 99 XFS_RANDOM_ITOBP_INOTOBP))) {
100 if (readahead) {
101 bp->b_flags &= ~XBF_DONE;
102 return;
103 }
104
87 xfs_buf_ioerror(bp, EFSCORRUPTED); 105 xfs_buf_ioerror(bp, EFSCORRUPTED);
88 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH, 106 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH,
89 mp, dip); 107 mp, dip);
@@ -104,14 +122,21 @@ static void
104xfs_inode_buf_read_verify( 122xfs_inode_buf_read_verify(
105 struct xfs_buf *bp) 123 struct xfs_buf *bp)
106{ 124{
107 xfs_inode_buf_verify(bp); 125 xfs_inode_buf_verify(bp, false);
126}
127
128static void
129xfs_inode_buf_readahead_verify(
130 struct xfs_buf *bp)
131{
132 xfs_inode_buf_verify(bp, true);
108} 133}
109 134
110static void 135static void
111xfs_inode_buf_write_verify( 136xfs_inode_buf_write_verify(
112 struct xfs_buf *bp) 137 struct xfs_buf *bp)
113{ 138{
114 xfs_inode_buf_verify(bp); 139 xfs_inode_buf_verify(bp, false);
115} 140}
116 141
117const struct xfs_buf_ops xfs_inode_buf_ops = { 142const struct xfs_buf_ops xfs_inode_buf_ops = {
@@ -119,6 +144,11 @@ const struct xfs_buf_ops xfs_inode_buf_ops = {
119 .verify_write = xfs_inode_buf_write_verify, 144 .verify_write = xfs_inode_buf_write_verify,
120}; 145};
121 146
147const struct xfs_buf_ops xfs_inode_buf_ra_ops = {
148 .verify_read = xfs_inode_buf_readahead_verify,
149 .verify_write = xfs_inode_buf_write_verify,
150};
151
122 152
123/* 153/*
124 * This routine is called to map an inode to the buffer containing the on-disk 154 * This routine is called to map an inode to the buffer containing the on-disk
diff --git a/fs/xfs/xfs_inode_buf.h b/fs/xfs/xfs_inode_buf.h
index aae9fc465fe0..599e6c0ca2a9 100644
--- a/fs/xfs/xfs_inode_buf.h
+++ b/fs/xfs/xfs_inode_buf.h
@@ -48,5 +48,6 @@ void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *);
48#endif /* DEBUG */ 48#endif /* DEBUG */
49 49
50extern const struct xfs_buf_ops xfs_inode_buf_ops; 50extern const struct xfs_buf_ops xfs_inode_buf_ops;
51extern const struct xfs_buf_ops xfs_inode_buf_ra_ops;
51 52
52#endif /* __XFS_INODE_BUF_H__ */ 53#endif /* __XFS_INODE_BUF_H__ */
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index dc100fed1973..7c0c1fdc728b 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3309,7 +3309,7 @@ xlog_recover_inode_ra_pass2(
3309 return; 3309 return;
3310 3310
3311 xfs_buf_readahead(mp->m_ddev_targp, ilfp->ilf_blkno, 3311 xfs_buf_readahead(mp->m_ddev_targp, ilfp->ilf_blkno,
3312 ilfp->ilf_len, &xfs_inode_buf_ops); 3312 ilfp->ilf_len, &xfs_inode_buf_ra_ops);
3313} 3313}
3314 3314
3315STATIC void 3315STATIC void