Skip to content

Commit d891400

Browse files
Dave ChinnerBen Myers
authored andcommitted
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 <[email protected]> Reviewed-by: Ben Myers <[email protected]> Signed-off-by: Ben Myers <[email protected]>
1 parent 50d5c8d commit d891400

File tree

3 files changed

+35
-4
lines changed

3 files changed

+35
-4
lines changed

fs/xfs/xfs_inode_buf.c

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,22 @@ xfs_inobp_check(
6161
}
6262
#endif
6363

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+
*/
6476
static void
6577
xfs_inode_buf_verify(
66-
struct xfs_buf *bp)
78+
struct xfs_buf *bp,
79+
bool readahead)
6780
{
6881
struct xfs_mount *mp = bp->b_target->bt_mount;
6982
int i;
@@ -84,6 +97,11 @@ xfs_inode_buf_verify(
8497
if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
8598
XFS_ERRTAG_ITOBP_INOTOBP,
8699
XFS_RANDOM_ITOBP_INOTOBP))) {
100+
if (readahead) {
101+
bp->b_flags &= ~XBF_DONE;
102+
return;
103+
}
104+
87105
xfs_buf_ioerror(bp, EFSCORRUPTED);
88106
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH,
89107
mp, dip);
@@ -104,21 +122,33 @@ static void
104122
xfs_inode_buf_read_verify(
105123
struct xfs_buf *bp)
106124
{
107-
xfs_inode_buf_verify(bp);
125+
xfs_inode_buf_verify(bp, false);
126+
}
127+
128+
static void
129+
xfs_inode_buf_readahead_verify(
130+
struct xfs_buf *bp)
131+
{
132+
xfs_inode_buf_verify(bp, true);
108133
}
109134

110135
static void
111136
xfs_inode_buf_write_verify(
112137
struct xfs_buf *bp)
113138
{
114-
xfs_inode_buf_verify(bp);
139+
xfs_inode_buf_verify(bp, false);
115140
}
116141

117142
const struct xfs_buf_ops xfs_inode_buf_ops = {
118143
.verify_read = xfs_inode_buf_read_verify,
119144
.verify_write = xfs_inode_buf_write_verify,
120145
};
121146

147+
const 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+
122152

123153
/*
124154
* This routine is called to map an inode to the buffer containing the on-disk

fs/xfs/xfs_inode_buf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,6 @@ void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *);
4848
#endif /* DEBUG */
4949

5050
extern const struct xfs_buf_ops xfs_inode_buf_ops;
51+
extern const struct xfs_buf_ops xfs_inode_buf_ra_ops;
5152

5253
#endif /* __XFS_INODE_BUF_H__ */

fs/xfs/xfs_log_recover.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3309,7 +3309,7 @@ xlog_recover_inode_ra_pass2(
33093309
return;
33103310

33113311
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);
33133313
}
33143314

33153315
STATIC void

0 commit comments

Comments
 (0)