/*
 * Translate an internal style on-disk-dquot to the exportable format.
 * The main differences are that the counters/limits are all in Basic
 * Blocks (BBs) instead of the internal FSBs, and all on-disk data has
 * to be converted to the native endianness.
 */
STATIC void
xfs_qm_export_dquot(
	xfs_mount_t		*mp,
	xfs_disk_dquot_t	*src,
	struct fs_disk_quota	*dst)
{
	memset(dst, 0, sizeof(*dst));
	dst->d_version = FS_DQUOT_VERSION;  /* different from src->d_version */
	dst->d_flags =
		xfs_qm_export_qtype_flags(INT_GET(src->d_flags, ARCH_CONVERT));
	dst->d_id = INT_GET(src->d_id, ARCH_CONVERT);
	dst->d_blk_hardlimit = (__uint64_t)
		XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_hardlimit, ARCH_CONVERT));
	dst->d_blk_softlimit = (__uint64_t)
		XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_softlimit, ARCH_CONVERT));
	dst->d_ino_hardlimit = (__uint64_t)
		INT_GET(src->d_ino_hardlimit, ARCH_CONVERT);
	dst->d_ino_softlimit = (__uint64_t)
		INT_GET(src->d_ino_softlimit, ARCH_CONVERT);
	dst->d_bcount = (__uint64_t)
		XFS_FSB_TO_BB(mp, INT_GET(src->d_bcount, ARCH_CONVERT));
	dst->d_icount = (__uint64_t) INT_GET(src->d_icount, ARCH_CONVERT);
	dst->d_btimer = (__uint32_t) INT_GET(src->d_btimer, ARCH_CONVERT);
	dst->d_itimer = (__uint32_t) INT_GET(src->d_itimer, ARCH_CONVERT);
	dst->d_iwarns = INT_GET(src->d_iwarns, ARCH_CONVERT);
	dst->d_bwarns = INT_GET(src->d_bwarns, ARCH_CONVERT);

	dst->d_rtb_hardlimit = (__uint64_t)
		XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_hardlimit, ARCH_CONVERT));
	dst->d_rtb_softlimit = (__uint64_t)
		XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_softlimit, ARCH_CONVERT));
	dst->d_rtbcount = (__uint64_t)
		XFS_FSB_TO_BB(mp, INT_GET(src->d_rtbcount, ARCH_CONVERT));
	dst->d_rtbtimer = (__uint32_t) INT_GET(src->d_rtbtimer, ARCH_CONVERT);
	dst->d_rtbwarns = INT_GET(src->d_rtbwarns, ARCH_CONVERT);

	/*
	 * Internally, we don't reset all the timers when quota enforcement
	 * gets turned off. No need to confuse the userlevel code,
	 * so return zeroes in that case.
	 */
	if (! XFS_IS_QUOTA_ENFORCED(mp)) {
		dst->d_btimer = 0;
		dst->d_itimer = 0;
		dst->d_rtbtimer = 0;
	}

#ifdef DEBUG
	if (XFS_IS_QUOTA_ENFORCED(mp) && dst->d_id != 0) {
		if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) &&
		    (dst->d_blk_softlimit > 0)) {
			ASSERT(dst->d_btimer != 0);
		}
		if (((int) dst->d_icount >= (int) dst->d_ino_softlimit) &&
		    (dst->d_ino_softlimit > 0)) {
			ASSERT(dst->d_itimer != 0);
		}
	}
#endif
}
Esempio n. 2
0
/*
 * This reserves disk blocks and inodes against a dquot.
 * Flags indicate if the dquot is to be locked here and also
 * if the blk reservation is for RT or regular blocks.
 * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check.
 * Returns EDQUOT if quota is exceeded.
 */
STATIC int
xfs_trans_dqresv(
	xfs_trans_t	*tp,
	xfs_dquot_t	*dqp,
	long		nblks,
	long		ninos,
	uint		flags)
{
	int		error;
	xfs_qcnt_t	hardlimit;
	xfs_qcnt_t	softlimit;
	time_t		btimer;
	xfs_qcnt_t	*resbcountp;

	if (! (flags & XFS_QMOPT_DQLOCK)) {
		xfs_dqlock(dqp);
	}
	ASSERT(XFS_DQ_IS_LOCKED(dqp));
	if (flags & XFS_TRANS_DQ_RES_BLKS) {
		hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT);
		softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT);
		btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT);
		resbcountp = &dqp->q_res_bcount;
	} else {
		ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
		hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT);
		softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT);
		btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT);
		resbcountp = &dqp->q_res_rtbcount;
	}
	error = 0;

	if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
	    !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT) &&
	    XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) {
#ifdef QUOTADEBUG
		printk("BLK Res: nblks=%ld + resbcount=%Ld > hardlimit=%Ld?\n",
			nblks, *resbcountp, hardlimit);
#endif
		if (nblks > 0) {
			/*
			 * dquot is locked already. See if we'd go over the
			 * hardlimit or exceed the timelimit if we allocate
			 * nblks.
			 */
			if (hardlimit > 0ULL &&
			     (hardlimit <= nblks + *resbcountp)) {
				error = EDQUOT;
				goto error_return;
			}

			if (softlimit > 0ULL &&
			     (softlimit <= nblks + *resbcountp)) {
				/*
				 * If timer or warnings has expired,
				 * return EDQUOT
				 */
				if ((btimer != 0 && CURRENT_TIME > btimer) ||
				    (!INT_ISZERO(dqp->q_core.d_bwarns, ARCH_CONVERT) &&
				     INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >=
				     XFS_QI_BWARNLIMIT(dqp->q_mount))) {
					error = EDQUOT;
					goto error_return;
				}
			}
		}
		if (ninos > 0) {
			if (INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) > 0ULL &&
			    INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
			    INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT)) {
				error = EDQUOT;
				goto error_return;
			} else if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) > 0ULL &&
				   INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
				   INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) {
				/*
				 * If timer or warnings has expired,
				 * return EDQUOT
				 */
				if ((!INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) &&
				     CURRENT_TIME > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) ||
				    (!INT_ISZERO(dqp->q_core.d_iwarns, ARCH_CONVERT) &&
				     INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >=
				     XFS_QI_IWARNLIMIT(dqp->q_mount))) {
					error = EDQUOT;
					goto error_return;
				}
			}
		}
	}

	/*
	 * Change the reservation, but not the actual usage.
	 * Note that q_res_bcount = q_core.d_bcount + resv
	 */
	(*resbcountp) += (xfs_qcnt_t)nblks;
	if (ninos != 0)
		dqp->q_res_icount += (xfs_qcnt_t)ninos;

	/*
	 * note the reservation amt in the trans struct too,
	 * so that the transaction knows how much was reserved by
	 * it against this particular dquot.
	 * We don't do this when we are reserving for a delayed allocation,
	 * because we don't have the luxury of a transaction envelope then.
	 */
	if (tp) {
		ASSERT(tp->t_dqinfo);
		ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
		if (nblks != 0)
			xfs_trans_mod_dquot(tp, dqp,
					    flags & XFS_QMOPT_RESBLK_MASK,
					    nblks);
		if (ninos != 0)
			xfs_trans_mod_dquot(tp, dqp,
					    XFS_TRANS_DQ_RES_INOS,
					    ninos);
	}
	ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
	ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
	ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));

error_return:
	if (! (flags & XFS_QMOPT_DQLOCK)) {
		xfs_dqunlock(dqp);
	}
	return (error);
}
Esempio n. 3
0
/*
 * This reserves disk blocks and inodes against a dquot.
 * Flags indicate if the dquot is to be locked here and also
 * if the blk reservation is for RT or regular blocks.
 * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check.
 * Returns EDQUOT if quota is exceeded.
 */
STATIC int
xfs_trans_dqresv(
	xfs_trans_t	*tp,
	xfs_mount_t	*mp,
	xfs_dquot_t	*dqp,
	long		nblks,
	long		ninos,
	uint		flags)
{
	int		error;
	xfs_qcnt_t	hardlimit;
	xfs_qcnt_t	softlimit;
	time_t		timer;
	xfs_qwarncnt_t	warns;
	xfs_qwarncnt_t	warnlimit;
	xfs_qcnt_t	count;
	xfs_qcnt_t	*resbcountp;
	xfs_quotainfo_t	*q = mp->m_quotainfo;

	if (! (flags & XFS_QMOPT_DQLOCK)) {
		xfs_dqlock(dqp);
	}
	ASSERT(XFS_DQ_IS_LOCKED(dqp));
	if (flags & XFS_TRANS_DQ_RES_BLKS) {
		hardlimit = be64_to_cpu(dqp->q_core.d_blk_hardlimit);
		if (!hardlimit)
			hardlimit = q->qi_bhardlimit;
		softlimit = be64_to_cpu(dqp->q_core.d_blk_softlimit);
		if (!softlimit)
			softlimit = q->qi_bsoftlimit;
		timer = be32_to_cpu(dqp->q_core.d_btimer);
		warns = be16_to_cpu(dqp->q_core.d_bwarns);
		warnlimit = XFS_QI_BWARNLIMIT(dqp->q_mount);
		resbcountp = &dqp->q_res_bcount;
	} else {
		ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
		hardlimit = be64_to_cpu(dqp->q_core.d_rtb_hardlimit);
		if (!hardlimit)
			hardlimit = q->qi_rtbhardlimit;
		softlimit = be64_to_cpu(dqp->q_core.d_rtb_softlimit);
		if (!softlimit)
			softlimit = q->qi_rtbsoftlimit;
		timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
		warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
		warnlimit = XFS_QI_RTBWARNLIMIT(dqp->q_mount);
		resbcountp = &dqp->q_res_rtbcount;
	}
	error = 0;

	if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
	    dqp->q_core.d_id &&
	    XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) {
#ifdef QUOTADEBUG
		cmn_err(CE_DEBUG, "BLK Res: nblks=%ld + resbcount=%Ld"
			  " > hardlimit=%Ld?", nblks, *resbcountp, hardlimit);
#endif
		if (nblks > 0) {
			/*
			 * dquot is locked already. See if we'd go over the
			 * hardlimit or exceed the timelimit if we allocate
			 * nblks.
			 */
			if (hardlimit > 0ULL &&
			     (hardlimit <= nblks + *resbcountp)) {
				error = EDQUOT;
				goto error_return;
			}

			if (softlimit > 0ULL &&
			     (softlimit <= nblks + *resbcountp)) {
				/*
				 * If timer or warnings has expired,
				 * return EDQUOT
				 */
				if ((timer != 0 && get_seconds() > timer) ||
				    (warns != 0 && warns >= warnlimit)) {
					error = EDQUOT;
					goto error_return;
				}
			}
		}
		if (ninos > 0) {
			count = be64_to_cpu(dqp->q_core.d_icount);
			timer = be32_to_cpu(dqp->q_core.d_itimer);
			warns = be16_to_cpu(dqp->q_core.d_iwarns);
			warnlimit = XFS_QI_IWARNLIMIT(dqp->q_mount);
			hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);
			if (!hardlimit)
				hardlimit = q->qi_ihardlimit;
			softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit);
			if (!softlimit)
				softlimit = q->qi_isoftlimit;
			if (hardlimit > 0ULL && count >= hardlimit) {
				error = EDQUOT;
				goto error_return;
			} else if (softlimit > 0ULL && count >= softlimit) {
				/*
				 * If timer or warnings has expired,
				 * return EDQUOT
				 */
				if ((timer != 0 && get_seconds() > timer) ||
				     (warns != 0 && warns >= warnlimit)) {
					error = EDQUOT;
					goto error_return;
				}
			}
		}
	}

	/*
	 * Change the reservation, but not the actual usage.
	 * Note that q_res_bcount = q_core.d_bcount + resv
	 */
	(*resbcountp) += (xfs_qcnt_t)nblks;
	if (ninos != 0)
		dqp->q_res_icount += (xfs_qcnt_t)ninos;

	/*
	 * note the reservation amt in the trans struct too,
	 * so that the transaction knows how much was reserved by
	 * it against this particular dquot.
	 * We don't do this when we are reserving for a delayed allocation,
	 * because we don't have the luxury of a transaction envelope then.
	 */
	if (tp) {
		ASSERT(tp->t_dqinfo);
		ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
		if (nblks != 0)
			xfs_trans_mod_dquot(tp, dqp,
					    flags & XFS_QMOPT_RESBLK_MASK,
					    nblks);
		if (ninos != 0)
			xfs_trans_mod_dquot(tp, dqp,
					    XFS_TRANS_DQ_RES_INOS,
					    ninos);
	}
	ASSERT(dqp->q_res_bcount >= be64_to_cpu(dqp->q_core.d_bcount));
	ASSERT(dqp->q_res_rtbcount >= be64_to_cpu(dqp->q_core.d_rtbcount));
	ASSERT(dqp->q_res_icount >= be64_to_cpu(dqp->q_core.d_icount));

error_return:
	if (! (flags & XFS_QMOPT_DQLOCK)) {
		xfs_dqunlock(dqp);
	}
	return (error);
}