Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 339427
b: refs/heads/master
c: c631919
h: refs/heads/master
i:
  339425: 39639f6
  339423: 7f63789
v: v3
  • Loading branch information
Dave Chinner authored and Ben Myers committed Nov 16, 2012
1 parent a63dbb2 commit b894a2c
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 24 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3d3e6f64e22c94115d47de670611bcd3ecda3796
refs/heads/master: c6319198702350a2215a8c0cacd6cc4283728a1b
117 changes: 95 additions & 22 deletions trunk/fs/xfs/xfs_dquot.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,89 @@ xfs_qm_dqalloc(
return (error);
}

void
xfs_dquot_read_verify(
struct xfs_buf *bp)
{
struct xfs_mount *mp = bp->b_target->bt_mount;
struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr;
struct xfs_disk_dquot *ddq;
xfs_dqid_t id = 0;
int i;

/*
* On the first read of the buffer, verify that each dquot is valid.
* We don't know what the id of the dquot is supposed to be, just that
* they should be increasing monotonically within the buffer. If the
* first id is corrupt, then it will fail on the second dquot in the
* buffer so corruptions could point to the wrong dquot in this case.
*/
for (i = 0; i < mp->m_quotainfo->qi_dqperchunk; i++) {
int error;

ddq = &d[i].dd_diskdq;

if (i == 0)
id = be32_to_cpu(ddq->d_id);

error = xfs_qm_dqcheck(mp, ddq, id + i, 0, XFS_QMOPT_DOWARN,
"xfs_dquot_read_verify");
if (error) {
XFS_CORRUPTION_ERROR("xfs_dquot_read_verify",
XFS_ERRLEVEL_LOW, mp, d);
xfs_buf_ioerror(bp, EFSCORRUPTED);
break;
}
}
bp->b_iodone = NULL;
xfs_buf_ioend(bp, 0);
}

STATIC int
xfs_qm_dqrepair(
struct xfs_mount *mp,
struct xfs_trans *tp,
struct xfs_dquot *dqp,
xfs_dqid_t firstid,
struct xfs_buf **bpp)
{
int error;
struct xfs_disk_dquot *ddq;
struct xfs_dqblk *d;
int i;

/*
* Read the buffer without verification so we get the corrupted
* buffer returned to us.
*/
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, dqp->q_blkno,
mp->m_quotainfo->qi_dqchunklen,
0, bpp, NULL);

if (error) {
ASSERT(*bpp == NULL);
return XFS_ERROR(error);
}

ASSERT(xfs_buf_islocked(*bpp));
d = (struct xfs_dqblk *)(*bpp)->b_addr;

/* Do the actual repair of dquots in this buffer */
for (i = 0; i < mp->m_quotainfo->qi_dqperchunk; i++) {
ddq = &d[i].dd_diskdq;
error = xfs_qm_dqcheck(mp, ddq, firstid + i,
dqp->dq_flags & XFS_DQ_ALLTYPES,
XFS_QMOPT_DQREPAIR, "xfs_qm_dqrepair");
if (error) {
/* repair failed, we're screwed */
xfs_trans_brelse(tp, *bpp);
return XFS_ERROR(EIO);
}
}

return 0;
}

/*
* Maps a dquot to the buffer containing its on-disk version.
* This returns a ptr to the buffer containing the on-disk dquot
Expand All @@ -378,7 +461,6 @@ xfs_qm_dqtobp(
xfs_buf_t *bp;
xfs_inode_t *quotip = XFS_DQ_TO_QIP(dqp);
xfs_mount_t *mp = dqp->q_mount;
xfs_disk_dquot_t *ddq;
xfs_dqid_t id = be32_to_cpu(dqp->q_core.d_id);
xfs_trans_t *tp = (tpp ? *tpp : NULL);

Expand Down Expand Up @@ -439,33 +521,24 @@ xfs_qm_dqtobp(
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
dqp->q_blkno,
mp->m_quotainfo->qi_dqchunklen,
0, &bp, NULL);
if (error || !bp)
return XFS_ERROR(error);
}
0, &bp, xfs_dquot_read_verify);

ASSERT(xfs_buf_islocked(bp));

/*
* calculate the location of the dquot inside the buffer.
*/
ddq = bp->b_addr + dqp->q_bufoffset;
if (error == EFSCORRUPTED && (flags & XFS_QMOPT_DQREPAIR)) {
xfs_dqid_t firstid = (xfs_dqid_t)map.br_startoff *
mp->m_quotainfo->qi_dqperchunk;
ASSERT(bp == NULL);
error = xfs_qm_dqrepair(mp, tp, dqp, firstid, &bp);
}

/*
* A simple sanity check in case we got a corrupted dquot...
*/
error = xfs_qm_dqcheck(mp, ddq, id, dqp->dq_flags & XFS_DQ_ALLTYPES,
flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN),
"dqtobp");
if (error) {
if (!(flags & XFS_QMOPT_DQREPAIR)) {
xfs_trans_brelse(tp, bp);
return XFS_ERROR(EIO);
if (error) {
ASSERT(bp == NULL);
return XFS_ERROR(error);
}
}

ASSERT(xfs_buf_islocked(bp));
*O_bpp = bp;
*O_ddpp = ddq;
*O_ddpp = bp->b_addr + dqp->q_bufoffset;

return (0);
}
Expand Down
1 change: 1 addition & 0 deletions trunk/fs/xfs/xfs_dquot.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)

extern int xfs_qm_dqread(struct xfs_mount *, xfs_dqid_t, uint,
uint, struct xfs_dquot **);
extern void xfs_dquot_read_verify(struct xfs_buf *bp);
extern void xfs_qm_dqdestroy(xfs_dquot_t *);
extern int xfs_qm_dqflush(struct xfs_dquot *, struct xfs_buf **);
extern void xfs_qm_dqunpin_wait(xfs_dquot_t *);
Expand Down
3 changes: 2 additions & 1 deletion trunk/fs/xfs/xfs_qm.c
Original file line number Diff line number Diff line change
Expand Up @@ -892,7 +892,8 @@ xfs_qm_dqiter_bufs(
while (blkcnt--) {
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
XFS_FSB_TO_DADDR(mp, bno),
mp->m_quotainfo->qi_dqchunklen, 0, &bp, NULL);
mp->m_quotainfo->qi_dqchunklen, 0, &bp,
xfs_dquot_read_verify);
if (error)
break;

Expand Down

0 comments on commit b894a2c

Please sign in to comment.