aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2016-01-11 15:04:01 -0500
committerDave Chinner <david@fromorbit.com>2016-01-11 15:04:01 -0500
commit7d6a13f023567d573ac362502bb702eda716e654 (patch)
treea8d845d1a6db878b5e9373c088e9c2e24c0d1a50 /fs/xfs
parentb79f4a1c68bb99152d0785ee4ea3ab4396cdacc6 (diff)
xfs: handle dquot buffer readahead in log recovery correctly
When we do dquot readahead in log recovery, we do not use a verifier as the underlying buffer may not have dquots in it. e.g. the allocation operation hasn't yet been replayed. Hence we do not want to fail recovery because we detect an operation to be replayed has not been run yet. This problem was addressed for inodes in commit d891400 ("xfs: inode buffers may not be valid during recovery readahead") but the problem was not recognised to exist for dquots and their buffers as the dquot readahead did not have a verifier. The result of not using a verifier is that when the buffer is then next read to replay a dquot modification, the dquot buffer verifier will only be attached to the buffer if *readahead is not complete*. Hence we can read the buffer, replay the dquot changes and then add it to the delwri submission list without it having a verifier attached to it. This then generates warnings in xfs_buf_ioapply(), which catches and warns about this case. Fix this and make it handle the same readahead verifier error cases as for inode buffers by adding a new readahead verifier that has a write operation as well as a read operation that marks the buffer as not done if any corruption is detected. Also make sure we don't run readahead if the dquot buffer has been marked as cancelled by recovery. This will result in readahead either succeeding and the buffer having a valid write verifier, or readahead failing and the buffer state requiring the subsequent read to resubmit the IO with the new verifier. In either case, this will result in the buffer always ending up with a valid write verifier on it. Note: we also need to fix the inode buffer readahead error handling to mark the buffer with EIO. Brian noticed the code I copied from there wrong during review, so fix it at the same time. Add comments linking the two functions that handle readahead verifier errors together so we don't forget this behavioural link in future. cc: <stable@vger.kernel.org> # 3.12 - current Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/libxfs/xfs_dquot_buf.c36
-rw-r--r--fs/xfs/libxfs/xfs_inode_buf.c2
-rw-r--r--fs/xfs/libxfs/xfs_quota_defs.h2
-rw-r--r--fs/xfs/libxfs/xfs_shared.h1
-rw-r--r--fs/xfs/xfs_log_recover.c9
5 files changed, 41 insertions, 9 deletions
diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c
index 11cefb2a372a..3cc3cf767474 100644
--- a/fs/xfs/libxfs/xfs_dquot_buf.c
+++ b/fs/xfs/libxfs/xfs_dquot_buf.c
@@ -54,7 +54,7 @@ xfs_dqcheck(
54 xfs_dqid_t id, 54 xfs_dqid_t id,
55 uint type, /* used only when IO_dorepair is true */ 55 uint type, /* used only when IO_dorepair is true */
56 uint flags, 56 uint flags,
57 char *str) 57 const char *str)
58{ 58{
59 xfs_dqblk_t *d = (xfs_dqblk_t *)ddq; 59 xfs_dqblk_t *d = (xfs_dqblk_t *)ddq;
60 int errs = 0; 60 int errs = 0;
@@ -207,7 +207,8 @@ xfs_dquot_buf_verify_crc(
207STATIC bool 207STATIC bool
208xfs_dquot_buf_verify( 208xfs_dquot_buf_verify(
209 struct xfs_mount *mp, 209 struct xfs_mount *mp,
210 struct xfs_buf *bp) 210 struct xfs_buf *bp,
211 int warn)
211{ 212{
212 struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; 213 struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr;
213 xfs_dqid_t id = 0; 214 xfs_dqid_t id = 0;
@@ -240,8 +241,7 @@ xfs_dquot_buf_verify(
240 if (i == 0) 241 if (i == 0)
241 id = be32_to_cpu(ddq->d_id); 242 id = be32_to_cpu(ddq->d_id);
242 243
243 error = xfs_dqcheck(mp, ddq, id + i, 0, XFS_QMOPT_DOWARN, 244 error = xfs_dqcheck(mp, ddq, id + i, 0, warn, __func__);
244 "xfs_dquot_buf_verify");
245 if (error) 245 if (error)
246 return false; 246 return false;
247 } 247 }
@@ -256,7 +256,7 @@ xfs_dquot_buf_read_verify(
256 256
257 if (!xfs_dquot_buf_verify_crc(mp, bp)) 257 if (!xfs_dquot_buf_verify_crc(mp, bp))
258 xfs_buf_ioerror(bp, -EFSBADCRC); 258 xfs_buf_ioerror(bp, -EFSBADCRC);
259 else if (!xfs_dquot_buf_verify(mp, bp)) 259 else if (!xfs_dquot_buf_verify(mp, bp, XFS_QMOPT_DOWARN))
260 xfs_buf_ioerror(bp, -EFSCORRUPTED); 260 xfs_buf_ioerror(bp, -EFSCORRUPTED);
261 261
262 if (bp->b_error) 262 if (bp->b_error)
@@ -264,6 +264,25 @@ xfs_dquot_buf_read_verify(
264} 264}
265 265
266/* 266/*
267 * readahead errors are silent and simply leave the buffer as !done so a real
268 * read will then be run with the xfs_dquot_buf_ops verifier. See
269 * xfs_inode_buf_verify() for why we use EIO and ~XBF_DONE here rather than
270 * reporting the failure.
271 */
272static void
273xfs_dquot_buf_readahead_verify(
274 struct xfs_buf *bp)
275{
276 struct xfs_mount *mp = bp->b_target->bt_mount;
277
278 if (!xfs_dquot_buf_verify_crc(mp, bp) ||
279 !xfs_dquot_buf_verify(mp, bp, 0)) {
280 xfs_buf_ioerror(bp, -EIO);
281 bp->b_flags &= ~XBF_DONE;
282 }
283}
284
285/*
267 * we don't calculate the CRC here as that is done when the dquot is flushed to 286 * we don't calculate the CRC here as that is done when the dquot is flushed to
268 * the buffer after the update is done. This ensures that the dquot in the 287 * the buffer after the update is done. This ensures that the dquot in the
269 * buffer always has an up-to-date CRC value. 288 * buffer always has an up-to-date CRC value.
@@ -274,7 +293,7 @@ xfs_dquot_buf_write_verify(
274{ 293{
275 struct xfs_mount *mp = bp->b_target->bt_mount; 294 struct xfs_mount *mp = bp->b_target->bt_mount;
276 295
277 if (!xfs_dquot_buf_verify(mp, bp)) { 296 if (!xfs_dquot_buf_verify(mp, bp, XFS_QMOPT_DOWARN)) {
278 xfs_buf_ioerror(bp, -EFSCORRUPTED); 297 xfs_buf_ioerror(bp, -EFSCORRUPTED);
279 xfs_verifier_error(bp); 298 xfs_verifier_error(bp);
280 return; 299 return;
@@ -287,3 +306,8 @@ const struct xfs_buf_ops xfs_dquot_buf_ops = {
287 .verify_write = xfs_dquot_buf_write_verify, 306 .verify_write = xfs_dquot_buf_write_verify,
288}; 307};
289 308
309const struct xfs_buf_ops xfs_dquot_buf_ra_ops = {
310 .name = "xfs_dquot_ra",
311 .verify_read = xfs_dquot_buf_readahead_verify,
312 .verify_write = xfs_dquot_buf_write_verify,
313};
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index ff17c48e7ed3..1aabfda669b0 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -68,6 +68,8 @@ xfs_inobp_check(
68 * recovery and we don't get unnecssary panics on debug kernels. We use EIO here 68 * recovery and we don't get unnecssary panics on debug kernels. We use EIO here
69 * because all we want to do is say readahead failed; there is no-one to report 69 * because all we want to do is say readahead failed; there is no-one to report
70 * the error to, so this will distinguish it from a non-ra verifier failure. 70 * the error to, so this will distinguish it from a non-ra verifier failure.
71 * Changes to this readahead error behavour also need to be reflected in
72 * xfs_dquot_buf_readahead_verify().
71 */ 73 */
72static void 74static void
73xfs_inode_buf_verify( 75xfs_inode_buf_verify(
diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
index 1b0a08379759..f51078f1e92a 100644
--- a/fs/xfs/libxfs/xfs_quota_defs.h
+++ b/fs/xfs/libxfs/xfs_quota_defs.h
@@ -153,7 +153,7 @@ typedef __uint16_t xfs_qwarncnt_t;
153#define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) 153#define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS)
154 154
155extern int xfs_dqcheck(struct xfs_mount *mp, xfs_disk_dquot_t *ddq, 155extern int xfs_dqcheck(struct xfs_mount *mp, xfs_disk_dquot_t *ddq,
156 xfs_dqid_t id, uint type, uint flags, char *str); 156 xfs_dqid_t id, uint type, uint flags, const char *str);
157extern int xfs_calc_dquots_per_chunk(unsigned int nbblks); 157extern int xfs_calc_dquots_per_chunk(unsigned int nbblks);
158 158
159#endif /* __XFS_QUOTA_H__ */ 159#endif /* __XFS_QUOTA_H__ */
diff --git a/fs/xfs/libxfs/xfs_shared.h b/fs/xfs/libxfs/xfs_shared.h
index 5be529707903..15c3ceb845b9 100644
--- a/fs/xfs/libxfs/xfs_shared.h
+++ b/fs/xfs/libxfs/xfs_shared.h
@@ -49,6 +49,7 @@ extern const struct xfs_buf_ops xfs_inobt_buf_ops;
49extern const struct xfs_buf_ops xfs_inode_buf_ops; 49extern const struct xfs_buf_ops xfs_inode_buf_ops;
50extern const struct xfs_buf_ops xfs_inode_buf_ra_ops; 50extern const struct xfs_buf_ops xfs_inode_buf_ra_ops;
51extern const struct xfs_buf_ops xfs_dquot_buf_ops; 51extern const struct xfs_buf_ops xfs_dquot_buf_ops;
52extern const struct xfs_buf_ops xfs_dquot_buf_ra_ops;
52extern const struct xfs_buf_ops xfs_sb_buf_ops; 53extern const struct xfs_buf_ops xfs_sb_buf_ops;
53extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops; 54extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops;
54extern const struct xfs_buf_ops xfs_symlink_buf_ops; 55extern const struct xfs_buf_ops xfs_symlink_buf_ops;
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index c5ecaacdd218..5991cdcb9040 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3204,6 +3204,7 @@ xlog_recover_dquot_ra_pass2(
3204 struct xfs_disk_dquot *recddq; 3204 struct xfs_disk_dquot *recddq;
3205 struct xfs_dq_logformat *dq_f; 3205 struct xfs_dq_logformat *dq_f;
3206 uint type; 3206 uint type;
3207 int len;
3207 3208
3208 3209
3209 if (mp->m_qflags == 0) 3210 if (mp->m_qflags == 0)
@@ -3224,8 +3225,12 @@ xlog_recover_dquot_ra_pass2(
3224 ASSERT(dq_f); 3225 ASSERT(dq_f);
3225 ASSERT(dq_f->qlf_len == 1); 3226 ASSERT(dq_f->qlf_len == 1);
3226 3227
3227 xfs_buf_readahead(mp->m_ddev_targp, dq_f->qlf_blkno, 3228 len = XFS_FSB_TO_BB(mp, dq_f->qlf_len);
3228 XFS_FSB_TO_BB(mp, dq_f->qlf_len), NULL); 3229 if (xlog_peek_buffer_cancelled(log, dq_f->qlf_blkno, len, 0))
3230 return;
3231
3232 xfs_buf_readahead(mp->m_ddev_targp, dq_f->qlf_blkno, len,
3233 &xfs_dquot_buf_ra_ops);
3229} 3234}
3230 3235
3231STATIC void 3236STATIC void