aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_dquot.c117
-rw-r--r--fs/xfs/xfs_dquot.h1
-rw-r--r--fs/xfs/xfs_qm.c3
3 files changed, 98 insertions, 23 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}
diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
index 7d20af27346d..a08ba92d7da0 100644
--- a/fs/xfs/xfs_dquot.h
+++ b/fs/xfs/xfs_dquot.h
@@ -140,6 +140,7 @@ static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
140 140
141extern int xfs_qm_dqread(struct xfs_mount *, xfs_dqid_t, uint, 141extern int xfs_qm_dqread(struct xfs_mount *, xfs_dqid_t, uint,
142 uint, struct xfs_dquot **); 142 uint, struct xfs_dquot **);
143extern void xfs_dquot_read_verify(struct xfs_buf *bp);
143extern void xfs_qm_dqdestroy(xfs_dquot_t *); 144extern void xfs_qm_dqdestroy(xfs_dquot_t *);
144extern int xfs_qm_dqflush(struct xfs_dquot *, struct xfs_buf **); 145extern int xfs_qm_dqflush(struct xfs_dquot *, struct xfs_buf **);
145extern void xfs_qm_dqunpin_wait(xfs_dquot_t *); 146extern void xfs_qm_dqunpin_wait(xfs_dquot_t *);
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 688f608b3668..a6dfb97490cc 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -892,7 +892,8 @@ xfs_qm_dqiter_bufs(
892 while (blkcnt--) { 892 while (blkcnt--) {
893 error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, 893 error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
894 XFS_FSB_TO_DADDR(mp, bno), 894 XFS_FSB_TO_DADDR(mp, bno),
895 mp->m_quotainfo->qi_dqchunklen, 0, &bp, NULL); 895 mp->m_quotainfo->qi_dqchunklen, 0, &bp,
896 xfs_dquot_read_verify);
896 if (error) 897 if (error)
897 break; 898 break;
898 899