aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_dquot.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-11-14 01:50:13 -0500
committerBen Myers <bpm@sgi.com>2012-11-15 22:34:33 -0500
commitc6319198702350a2215a8c0cacd6cc4283728a1b (patch)
tree3016229da9ca0c4c6a657c7b587d20ee41a9eaab /fs/xfs/xfs_dquot.c
parent3d3e6f64e22c94115d47de670611bcd3ecda3796 (diff)
xfs: verify dquot blocks as they are read from disk
Add a dquot buffer verify callback function and pass it into the buffer read functions. This checks all the dquots in a buffer, but cannot completely verify the dquot ids are correct. Also, errors cannot be repaired, so an additional function is added to repair bad dquots in the buffer if such an error is detected in a context where repair is allowed. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Phil White <pwhite@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_dquot.c')
-rw-r--r--fs/xfs/xfs_dquot.c117
1 files changed, 95 insertions, 22 deletions
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index e95f800333d4..0ba0f0992d6e 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -360,6 +360,89 @@ xfs_qm_dqalloc(
360 return (error); 360 return (error);
361} 361}
362 362
363void
364xfs_dquot_read_verify(
365 struct xfs_buf *bp)
366{
367 struct xfs_mount *mp = bp->b_target->bt_mount;
368 struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr;
369 struct xfs_disk_dquot *ddq;
370 xfs_dqid_t id = 0;
371 int i;
372
373 /*
374 * On the first read of the buffer, verify that each dquot is valid.
375 * We don't know what the id of the dquot is supposed to be, just that
376 * they should be increasing monotonically within the buffer. If the
377 * first id is corrupt, then it will fail on the second dquot in the
378 * buffer so corruptions could point to the wrong dquot in this case.
379 */
380 for (i = 0; i < mp->m_quotainfo->qi_dqperchunk; i++) {
381 int error;
382
383 ddq = &d[i].dd_diskdq;
384
385 if (i == 0)
386 id = be32_to_cpu(ddq->d_id);
387
388 error = xfs_qm_dqcheck(mp, ddq, id + i, 0, XFS_QMOPT_DOWARN,
389 "xfs_dquot_read_verify");
390 if (error) {
391 XFS_CORRUPTION_ERROR("xfs_dquot_read_verify",
392 XFS_ERRLEVEL_LOW, mp, d);
393 xfs_buf_ioerror(bp, EFSCORRUPTED);
394 break;
395 }
396 }
397 bp->b_iodone = NULL;
398 xfs_buf_ioend(bp, 0);
399}
400
401STATIC int
402xfs_qm_dqrepair(
403 struct xfs_mount *mp,
404 struct xfs_trans *tp,
405 struct xfs_dquot *dqp,
406 xfs_dqid_t firstid,
407 struct xfs_buf **bpp)
408{
409 int error;
410 struct xfs_disk_dquot *ddq;
411 struct xfs_dqblk *d;
412 int i;
413
414 /*
415 * Read the buffer without verification so we get the corrupted
416 * buffer returned to us.
417 */
418 error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, dqp->q_blkno,
419 mp->m_quotainfo->qi_dqchunklen,
420 0, bpp, NULL);
421
422 if (error) {
423 ASSERT(*bpp == NULL);
424 return XFS_ERROR(error);
425 }
426
427 ASSERT(xfs_buf_islocked(*bpp));
428 d = (struct xfs_dqblk *)(*bpp)->b_addr;
429
430 /* Do the actual repair of dquots in this buffer */
431 for (i = 0; i < mp->m_quotainfo->qi_dqperchunk; i++) {
432 ddq = &d[i].dd_diskdq;
433 error = xfs_qm_dqcheck(mp, ddq, firstid + i,
434 dqp->dq_flags & XFS_DQ_ALLTYPES,
435 XFS_QMOPT_DQREPAIR, "xfs_qm_dqrepair");
436 if (error) {
437 /* repair failed, we're screwed */
438 xfs_trans_brelse(tp, *bpp);
439 return XFS_ERROR(EIO);
440 }
441 }
442
443 return 0;
444}
445
363/* 446/*
364 * Maps a dquot to the buffer containing its on-disk version. 447 * Maps a dquot to the buffer containing its on-disk version.
365 * This returns a ptr to the buffer containing the on-disk dquot 448 * This returns a ptr to the buffer containing the on-disk dquot
@@ -378,7 +461,6 @@ xfs_qm_dqtobp(
378 xfs_buf_t *bp; 461 xfs_buf_t *bp;
379 xfs_inode_t *quotip = XFS_DQ_TO_QIP(dqp); 462 xfs_inode_t *quotip = XFS_DQ_TO_QIP(dqp);
380 xfs_mount_t *mp = dqp->q_mount; 463 xfs_mount_t *mp = dqp->q_mount;
381 xfs_disk_dquot_t *ddq;
382 xfs_dqid_t id = be32_to_cpu(dqp->q_core.d_id); 464 xfs_dqid_t id = be32_to_cpu(dqp->q_core.d_id);
383 xfs_trans_t *tp = (tpp ? *tpp : NULL); 465 xfs_trans_t *tp = (tpp ? *tpp : NULL);
384 466
@@ -439,33 +521,24 @@ xfs_qm_dqtobp(
439 error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, 521 error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
440 dqp->q_blkno, 522 dqp->q_blkno,
441 mp->m_quotainfo->qi_dqchunklen, 523 mp->m_quotainfo->qi_dqchunklen,
442 0, &bp, NULL); 524 0, &bp, xfs_dquot_read_verify);
443 if (error || !bp)
444 return XFS_ERROR(error);
445 }
446 525
447 ASSERT(xfs_buf_islocked(bp)); 526 if (error == EFSCORRUPTED && (flags & XFS_QMOPT_DQREPAIR)) {
448 527 xfs_dqid_t firstid = (xfs_dqid_t)map.br_startoff *
449 /* 528 mp->m_quotainfo->qi_dqperchunk;
450 * calculate the location of the dquot inside the buffer. 529 ASSERT(bp == NULL);
451 */ 530 error = xfs_qm_dqrepair(mp, tp, dqp, firstid, &bp);
452 ddq = bp->b_addr + dqp->q_bufoffset; 531 }
453 532
454 /* 533 if (error) {
455 * A simple sanity check in case we got a corrupted dquot... 534 ASSERT(bp == NULL);
456 */ 535 return XFS_ERROR(error);
457 error = xfs_qm_dqcheck(mp, ddq, id, dqp->dq_flags & XFS_DQ_ALLTYPES,
458 flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN),
459 "dqtobp");
460 if (error) {
461 if (!(flags & XFS_QMOPT_DQREPAIR)) {
462 xfs_trans_brelse(tp, bp);
463 return XFS_ERROR(EIO);
464 } 536 }
465 } 537 }
466 538
539 ASSERT(xfs_buf_islocked(bp));
467 *O_bpp = bp; 540 *O_bpp = bp;
468 *O_ddpp = ddq; 541 *O_ddpp = bp->b_addr + dqp->q_bufoffset;
469 542
470 return (0); 543 return (0);
471} 544}