Commit eebf3cab authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: standardize quota verification function outputs



Rename xfs_dqcheck to xfs_dquot_verify and make it return an
xfs_failaddr_t like every other structure verifier function.
This enables us to check on-disk quotas in the same way that we check
everything else.  Callers are now responsible for logging errors, as
XFS_QMOPT_DOWARN goes away.

Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
parent eeea7980
Loading
Loading
Loading
Loading
+51 −91
Original line number Diff line number Diff line
@@ -42,17 +42,14 @@ xfs_calc_dquots_per_chunk(
/*
 * Do some primitive error checking on ondisk dquot data structures.
 */
int
xfs_dqcheck(
xfs_failaddr_t
xfs_dquot_verify(
	struct xfs_mount *mp,
	xfs_disk_dquot_t *ddq,
	xfs_dqid_t	 id,
	uint		 type,	  /* used only when IO_dorepair is true */
	uint		 flags,
	const char	 *str)
	uint		 flags)
{
	int		errs = 0;

	/*
	 * We can encounter an uninitialized dquot buffer for 2 reasons:
	 * 1. If we crash while deleting the quotainode(s), and those blks got
@@ -68,77 +65,38 @@ xfs_dqcheck(
	 * This is all fine; things are still consistent, and we haven't lost
	 * any quota information. Just don't complain about bad dquot blks.
	 */
	if (ddq->d_magic != cpu_to_be16(XFS_DQUOT_MAGIC)) {
		if (flags & XFS_QMOPT_DOWARN)
			xfs_alert(mp,
			"%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x",
			str, id, be16_to_cpu(ddq->d_magic), XFS_DQUOT_MAGIC);
		errs++;
	}
	if (ddq->d_version != XFS_DQUOT_VERSION) {
		if (flags & XFS_QMOPT_DOWARN)
			xfs_alert(mp,
			"%s : XFS dquot ID 0x%x, version 0x%x != 0x%x",
			str, id, ddq->d_version, XFS_DQUOT_VERSION);
		errs++;
	}
	if (ddq->d_magic != cpu_to_be16(XFS_DQUOT_MAGIC))
		return __this_address;
	if (ddq->d_version != XFS_DQUOT_VERSION)
		return __this_address;

	if (ddq->d_flags != XFS_DQ_USER &&
	    ddq->d_flags != XFS_DQ_PROJ &&
	    ddq->d_flags != XFS_DQ_GROUP) {
		if (flags & XFS_QMOPT_DOWARN)
			xfs_alert(mp,
			"%s : XFS dquot ID 0x%x, unknown flags 0x%x",
			str, id, ddq->d_flags);
		errs++;
	}
	    ddq->d_flags != XFS_DQ_GROUP)
		return __this_address;

	if (id != -1 && id != be32_to_cpu(ddq->d_id)) {
		if (flags & XFS_QMOPT_DOWARN)
			xfs_alert(mp,
			"%s : ondisk-dquot 0x%p, ID mismatch: "
			"0x%x expected, found id 0x%x",
			str, ddq, id, be32_to_cpu(ddq->d_id));
		errs++;
	}
	if (id != -1 && id != be32_to_cpu(ddq->d_id))
		return __this_address;

	if (!ddq->d_id)
		return NULL;

	if (!errs && ddq->d_id) {
	if (ddq->d_blk_softlimit &&
		    be64_to_cpu(ddq->d_bcount) >
				be64_to_cpu(ddq->d_blk_softlimit)) {
			if (!ddq->d_btimer) {
				if (flags & XFS_QMOPT_DOWARN)
					xfs_alert(mp,
			"%s : Dquot ID 0x%x (0x%p) BLK TIMER NOT STARTED",
					str, (int)be32_to_cpu(ddq->d_id), ddq);
				errs++;
			}
		}
	    be64_to_cpu(ddq->d_bcount) > be64_to_cpu(ddq->d_blk_softlimit) &&
	    !ddq->d_btimer)
		return __this_address;

	if (ddq->d_ino_softlimit &&
		    be64_to_cpu(ddq->d_icount) >
				be64_to_cpu(ddq->d_ino_softlimit)) {
			if (!ddq->d_itimer) {
				if (flags & XFS_QMOPT_DOWARN)
					xfs_alert(mp,
			"%s : Dquot ID 0x%x (0x%p) INODE TIMER NOT STARTED",
					str, (int)be32_to_cpu(ddq->d_id), ddq);
				errs++;
			}
		}
	    be64_to_cpu(ddq->d_icount) > be64_to_cpu(ddq->d_ino_softlimit) &&
	    !ddq->d_itimer)
		return __this_address;

	if (ddq->d_rtb_softlimit &&
		    be64_to_cpu(ddq->d_rtbcount) >
				be64_to_cpu(ddq->d_rtb_softlimit)) {
			if (!ddq->d_rtbtimer) {
				if (flags & XFS_QMOPT_DOWARN)
					xfs_alert(mp,
			"%s : Dquot ID 0x%x (0x%p) RTBLK TIMER NOT STARTED",
					str, (int)be32_to_cpu(ddq->d_id), ddq);
				errs++;
			}
		}
	}
	    be64_to_cpu(ddq->d_rtbcount) > be64_to_cpu(ddq->d_rtb_softlimit) &&
	    !ddq->d_rtbtimer)
		return __this_address;

	return errs;
	return NULL;
}

/*
@@ -206,13 +164,13 @@ xfs_dquot_buf_verify_crc(
	return true;
}

STATIC bool
STATIC xfs_failaddr_t
xfs_dquot_buf_verify(
	struct xfs_mount	*mp,
	struct xfs_buf		*bp,
	int			warn)
	struct xfs_buf		*bp)
{
	struct xfs_dqblk	*d = (struct xfs_dqblk *)bp->b_addr;
	xfs_failaddr_t		fa;
	xfs_dqid_t		id = 0;
	int			ndquots;
	int			i;
@@ -236,18 +194,18 @@ xfs_dquot_buf_verify(
	 */
	for (i = 0; i < ndquots; i++) {
		struct xfs_disk_dquot	*ddq;
		int			error;

		ddq = &d[i].dd_diskdq;

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

		error = xfs_dqcheck(mp, ddq, id + i, 0, warn, __func__);
		if (error)
			return false;
		fa = xfs_dquot_verify(mp, ddq, id + i, 0, 0);
		if (fa)
			return fa;
	}
	return true;

	return NULL;
}

static xfs_failaddr_t
@@ -256,9 +214,7 @@ xfs_dquot_buf_verify_struct(
{
	struct xfs_mount	*mp = bp->b_target->bt_mount;

	if (!xfs_dquot_buf_verify(mp, bp, 0))
		return __this_address;
	return NULL;
	return xfs_dquot_buf_verify(mp, bp);
}

static void
@@ -266,12 +222,16 @@ xfs_dquot_buf_read_verify(
	struct xfs_buf		*bp)
{
	struct xfs_mount	*mp = bp->b_target->bt_mount;
	xfs_failaddr_t		fa;

	if (!xfs_dquot_buf_verify_crc(mp, bp))
		xfs_verifier_error(bp, -EFSBADCRC, __this_address);
	else if (!xfs_dquot_buf_verify(mp, bp, XFS_QMOPT_DOWARN))
	else {
		fa = xfs_dquot_buf_verify(mp, bp);
		if (fa)
			xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
	}
}

/*
 * readahead errors are silent and simply leave the buffer as !done so a real
@@ -286,7 +246,7 @@ xfs_dquot_buf_readahead_verify(
	struct xfs_mount	*mp = bp->b_target->bt_mount;

	if (!xfs_dquot_buf_verify_crc(mp, bp) ||
	    !xfs_dquot_buf_verify(mp, bp, 0)) {
	    xfs_dquot_buf_verify(mp, bp) != NULL) {
		xfs_buf_ioerror(bp, -EIO);
		bp->b_flags &= ~XBF_DONE;
	}
@@ -302,11 +262,11 @@ xfs_dquot_buf_write_verify(
	struct xfs_buf		*bp)
{
	struct xfs_mount	*mp = bp->b_target->bt_mount;
	xfs_failaddr_t		fa;

	if (!xfs_dquot_buf_verify(mp, bp, XFS_QMOPT_DOWARN)) {
	fa = xfs_dquot_buf_verify(mp, bp);
	if (fa)
		xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
		return;
	}
}

const struct xfs_buf_ops xfs_dquot_buf_ops = {
+3 −3
Original line number Diff line number Diff line
@@ -112,7 +112,6 @@ typedef uint16_t xfs_qwarncnt_t;
#define XFS_QMOPT_PQUOTA	0x0000008 /* project dquot requested */
#define XFS_QMOPT_FORCE_RES	0x0000010 /* ignore quota limits */
#define XFS_QMOPT_SBVERSION	0x0000040 /* change superblock version num */
#define XFS_QMOPT_DOWARN        0x0000400 /* increase warning cnt if needed */
#define XFS_QMOPT_GQUOTA	0x0002000 /* group dquot requested */
#define XFS_QMOPT_ENOSPC	0x0004000 /* enospc instead of edquot (prj) */
#define XFS_QMOPT_DQNEXT	0x0008000 /* return next dquot >= this ID */
@@ -152,8 +151,9 @@ typedef uint16_t xfs_qwarncnt_t;
		(XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA)
#define XFS_QMOPT_RESBLK_MASK	(XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS)

extern int xfs_dqcheck(struct xfs_mount *mp, xfs_disk_dquot_t *ddq,
		       xfs_dqid_t id, uint type, uint flags, const char *str);
extern xfs_failaddr_t xfs_dquot_verify(struct xfs_mount *mp,
		struct xfs_disk_dquot *ddq, xfs_dqid_t id, uint type,
		uint flags);
extern int xfs_calc_dquots_per_chunk(unsigned int nbblks);
extern int xfs_dquot_repair(struct xfs_mount *mp, struct xfs_disk_dquot *ddq,
		xfs_dqid_t id, uint type);
+5 −3
Original line number Diff line number Diff line
@@ -956,6 +956,7 @@ xfs_qm_dqflush(
	struct xfs_mount	*mp = dqp->q_mount;
	struct xfs_buf		*bp;
	struct xfs_disk_dquot	*ddqp;
	xfs_failaddr_t		fa;
	int			error;

	ASSERT(XFS_DQ_IS_LOCKED(dqp));
@@ -1002,9 +1003,10 @@ xfs_qm_dqflush(
	/*
	 * A simple sanity check in case we got a corrupted dquot..
	 */
	error = xfs_dqcheck(mp, &dqp->q_core, be32_to_cpu(ddqp->d_id), 0,
			   XFS_QMOPT_DOWARN, "dqflush (incore copy)");
	if (error) {
	fa = xfs_dquot_verify(mp, &dqp->q_core, be32_to_cpu(ddqp->d_id), 0, 0);
	if (fa) {
		xfs_alert(mp, "corrupt dquot ID 0x%x in memory at %pS",
				be32_to_cpu(ddqp->d_id), fa);
		xfs_buf_relse(bp);
		xfs_dqfunlock(dqp);
		xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+15 −9
Original line number Diff line number Diff line
@@ -2652,7 +2652,7 @@ xlog_recover_do_reg_buffer(
	int			i;
	int			bit;
	int			nbits;
	int                     error;
	xfs_failaddr_t		fa;

	trace_xfs_log_recover_buf_reg_buf(mp->m_log, buf_f);

@@ -2687,7 +2687,7 @@ xlog_recover_do_reg_buffer(
		 * the first dquot in the buffer should do. XXXThis is
		 * probably a good thing to do for other buf types also.
		 */
		error = 0;
		fa = NULL;
		if (buf_f->blf_flags &
		   (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) {
			if (item->ri_buf[i].i_addr == NULL) {
@@ -2701,12 +2701,15 @@ xlog_recover_do_reg_buffer(
					item->ri_buf[i].i_len, __func__);
				goto next;
			}
			error = xfs_dqcheck(mp, item->ri_buf[i].i_addr,
					       -1, 0, XFS_QMOPT_DOWARN,
					       "dquot_buf_recover");
			if (error)
			fa = xfs_dquot_verify(mp, item->ri_buf[i].i_addr,
					       -1, 0, 0);
			if (fa) {
				xfs_alert(mp,
	"dquot corrupt at %pS trying to replay into block 0x%llx",
					fa, bp->b_bn);
				goto next;
			}
		}

		memcpy(xfs_buf_offset(bp,
			(uint)bit << XFS_BLF_SHIFT),	/* dest */
@@ -3307,6 +3310,7 @@ xlog_recover_dquot_pass2(
	xfs_mount_t		*mp = log->l_mp;
	xfs_buf_t		*bp;
	struct xfs_disk_dquot	*ddq, *recddq;
	xfs_failaddr_t		fa;
	int			error;
	xfs_dq_logformat_t	*dq_f;
	uint			type;
@@ -3349,10 +3353,12 @@ xlog_recover_dquot_pass2(
	 */
	dq_f = item->ri_buf[0].i_addr;
	ASSERT(dq_f);
	error = xfs_dqcheck(mp, recddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN,
			   "xlog_recover_dquot_pass2 (log copy)");
	if (error)
	fa = xfs_dquot_verify(mp, recddq, dq_f->qlf_id, 0, 0);
	if (fa) {
		xfs_alert(mp, "corrupt dquot ID 0x%x in log at %pS",
				dq_f->qlf_id, fa);
		return -EIO;
	}
	ASSERT(dq_f->qlf_len == 1);

	/*
+12 −16
Original line number Diff line number Diff line
@@ -291,8 +291,7 @@ xfs_qm_dqattach_one(
	 * exist on disk and we didn't ask it to allocate; ESRCH if quotas got
	 * turned off suddenly.
	 */
	error = xfs_qm_dqget(ip->i_mount, ip, id, type,
			     doalloc | XFS_QMOPT_DOWARN, &dqp);
	error = xfs_qm_dqget(ip->i_mount, ip, id, type, doalloc, &dqp);
	if (error)
		return error;

@@ -574,7 +573,7 @@ xfs_qm_set_defquota(
	struct xfs_def_quota    *defq;
	int			error;

	error = xfs_qm_dqread(mp, 0, type, XFS_QMOPT_DOWARN, &dqp);
	error = xfs_qm_dqread(mp, 0, type, 0, &dqp);

	if (!error) {
		xfs_disk_dquot_t        *ddqp = &dqp->q_core;
@@ -652,7 +651,7 @@ xfs_qm_init_quotainfo(
			XFS_IS_UQUOTA_RUNNING(mp) ? XFS_DQ_USER :
			 (XFS_IS_GQUOTA_RUNNING(mp) ? XFS_DQ_GROUP :
			  XFS_DQ_PROJ),
			XFS_QMOPT_DOWARN, &dqp);
			0, &dqp);

	if (!error) {
		xfs_disk_dquot_t	*ddqp = &dqp->q_core;
@@ -843,7 +842,7 @@ xfs_qm_reset_dqcounts(
{
	struct xfs_dqblk	*dqb;
	int			j;
	int			error;
	xfs_failaddr_t		fa;

	trace_xfs_reset_dqcounts(bp, _RET_IP_);

@@ -865,10 +864,11 @@ xfs_qm_reset_dqcounts(
		/*
		 * Do a sanity check, and if needed, repair the dqblk. Don't
		 * output any warnings because it's perfectly possible to
		 * find uninitialised dquot blks. See comment in xfs_dqcheck.
		 * find uninitialised dquot blks. See comment in
		 * xfs_dquot_verify.
		 */
		error = xfs_dqcheck(mp, ddq, id+j, type, 0, "xfs_quotacheck");
		if (error)
		fa = xfs_dquot_verify(mp, ddq, id + j, type, 0);
		if (fa)
			xfs_dquot_repair(mp, ddq, id + j, type);

		/*
@@ -1077,8 +1077,7 @@ xfs_qm_quotacheck_dqadjust(
	struct xfs_dquot	*dqp;
	int			error;

	error = xfs_qm_dqget(mp, ip, id, type,
			     XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN, &dqp);
	error = xfs_qm_dqget(mp, ip, id, type, XFS_QMOPT_DQALLOC, &dqp);
	if (error) {
		/*
		 * Shouldn't be able to turn off quotas here.
@@ -1699,8 +1698,7 @@ xfs_qm_vop_dqalloc(
			xfs_iunlock(ip, lockflags);
			error = xfs_qm_dqget(mp, NULL, uid,
						 XFS_DQ_USER,
						 XFS_QMOPT_DQALLOC |
						 XFS_QMOPT_DOWARN,
						 XFS_QMOPT_DQALLOC,
						 &uq);
			if (error) {
				ASSERT(error != -ENOENT);
@@ -1726,8 +1724,7 @@ xfs_qm_vop_dqalloc(
			xfs_iunlock(ip, lockflags);
			error = xfs_qm_dqget(mp, NULL, gid,
						 XFS_DQ_GROUP,
						 XFS_QMOPT_DQALLOC |
						 XFS_QMOPT_DOWARN,
						 XFS_QMOPT_DQALLOC,
						 &gq);
			if (error) {
				ASSERT(error != -ENOENT);
@@ -1746,8 +1743,7 @@ xfs_qm_vop_dqalloc(
			xfs_iunlock(ip, lockflags);
			error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid,
						 XFS_DQ_PROJ,
						 XFS_QMOPT_DQALLOC |
						 XFS_QMOPT_DOWARN,
						 XFS_QMOPT_DQALLOC,
						 &pq);
			if (error) {
				ASSERT(error != -ENOENT);