Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a2a7de2 authored by Nathan Scott's avatar Nathan Scott
Browse files

[XFS] Make project quota enforcement return an error code consistent with


its use.

SGI-PV: 951300
SGI-Modid: xfs-linux-melb:xfs-kern:25633a

Signed-off-by: default avatarNathan Scott <nathans@sgi.com>
parent 764d1f89
Loading
Loading
Loading
Loading
+10 −7
Original line number Original line Diff line number Diff line
@@ -2624,7 +2624,7 @@ xfs_qm_vop_chown_reserve(
{
{
	int		error;
	int		error;
	xfs_mount_t	*mp;
	xfs_mount_t	*mp;
	uint		delblks, blkflags;
	uint		delblks, blkflags, prjflags = 0;
	xfs_dquot_t	*unresudq, *unresgdq, *delblksudq, *delblksgdq;
	xfs_dquot_t	*unresudq, *unresgdq, *delblksudq, *delblksgdq;


	ASSERT(XFS_ISLOCKED_INODE(ip));
	ASSERT(XFS_ISLOCKED_INODE(ip));
@@ -2650,10 +2650,13 @@ xfs_qm_vop_chown_reserve(
		}
		}
	}
	}
	if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) {
	if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) {
		if ((XFS_IS_GQUOTA_ON(ip->i_mount) &&
		if (XFS_IS_PQUOTA_ON(ip->i_mount) &&
		     ip->i_d.di_gid != be32_to_cpu(gdqp->q_core.d_id)) ||
		     ip->i_d.di_projid != be32_to_cpu(gdqp->q_core.d_id))
		    (XFS_IS_PQUOTA_ON(ip->i_mount) &&
			prjflags = XFS_QMOPT_ENOSPC;
		     ip->i_d.di_projid != be32_to_cpu(gdqp->q_core.d_id))) {

		if (prjflags ||
		    (XFS_IS_GQUOTA_ON(ip->i_mount) &&
		     ip->i_d.di_gid != be32_to_cpu(gdqp->q_core.d_id))) {
			delblksgdq = gdqp;
			delblksgdq = gdqp;
			if (delblks) {
			if (delblks) {
				ASSERT(ip->i_gdquot);
				ASSERT(ip->i_gdquot);
@@ -2664,7 +2667,7 @@ xfs_qm_vop_chown_reserve(


	if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
	if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
				delblksudq, delblksgdq, ip->i_d.di_nblocks, 1,
				delblksudq, delblksgdq, ip->i_d.di_nblocks, 1,
				flags | blkflags)))
				flags | blkflags | prjflags)))
		return (error);
		return (error);


	/*
	/*
@@ -2681,7 +2684,7 @@ xfs_qm_vop_chown_reserve(
		ASSERT(unresudq || unresgdq);
		ASSERT(unresudq || unresgdq);
		if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
		if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
				delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0,
				delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0,
				flags | blkflags)))
				flags | blkflags | prjflags)))
			return (error);
			return (error);
		xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
		xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
				unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0,
				unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0,
+36 −32
Original line number Original line Diff line number Diff line
@@ -595,12 +595,19 @@ xfs_trans_unreserve_and_mod_dquots(
	}
	}
}
}


STATIC int
xfs_quota_error(uint flags)
{
	if (flags & XFS_QMOPT_ENOSPC)
		return ENOSPC;
	return EDQUOT;
}

/*
/*
 * This reserves disk blocks and inodes against a dquot.
 * This reserves disk blocks and inodes against a dquot.
 * Flags indicate if the dquot is to be locked here and also
 * Flags indicate if the dquot is to be locked here and also
 * if the blk reservation is for RT or regular blocks.
 * if the blk reservation is for RT or regular blocks.
 * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check.
 * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check.
 * Returns EDQUOT if quota is exceeded.
 */
 */
STATIC int
STATIC int
xfs_trans_dqresv(
xfs_trans_dqresv(
@@ -666,19 +673,15 @@ xfs_trans_dqresv(
			 */
			 */
			if (hardlimit > 0ULL &&
			if (hardlimit > 0ULL &&
			     (hardlimit <= nblks + *resbcountp)) {
			     (hardlimit <= nblks + *resbcountp)) {
				error = EDQUOT;
				error = xfs_quota_error(flags);
				goto error_return;
				goto error_return;
			}
			}


			if (softlimit > 0ULL &&
			if (softlimit > 0ULL &&
			     (softlimit <= nblks + *resbcountp)) {
			     (softlimit <= nblks + *resbcountp)) {
				/*
				 * If timer or warnings has expired,
				 * return EDQUOT
				 */
				if ((timer != 0 && get_seconds() > timer) ||
				if ((timer != 0 && get_seconds() > timer) ||
				    (warns != 0 && warns >= warnlimit)) {
				    (warns != 0 && warns >= warnlimit)) {
					error = EDQUOT;
					error = xfs_quota_error(flags);
					goto error_return;
					goto error_return;
				}
				}
			}
			}
@@ -695,16 +698,12 @@ xfs_trans_dqresv(
			if (!softlimit)
			if (!softlimit)
				softlimit = q->qi_isoftlimit;
				softlimit = q->qi_isoftlimit;
			if (hardlimit > 0ULL && count >= hardlimit) {
			if (hardlimit > 0ULL && count >= hardlimit) {
				error = EDQUOT;
				error = xfs_quota_error(flags);
				goto error_return;
				goto error_return;
			} else if (softlimit > 0ULL && count >= softlimit) {
			} else if (softlimit > 0ULL && count >= softlimit) {
				/*
				 * If timer or warnings has expired,
				 * return EDQUOT
				 */
				if ((timer != 0 && get_seconds() > timer) ||
				if ((timer != 0 && get_seconds() > timer) ||
				     (warns != 0 && warns >= warnlimit)) {
				     (warns != 0 && warns >= warnlimit)) {
					error = EDQUOT;
					error = xfs_quota_error(flags);
					goto error_return;
					goto error_return;
				}
				}
			}
			}
@@ -751,13 +750,14 @@ xfs_trans_dqresv(




/*
/*
 * Given a dquot(s), make disk block and/or inode reservations against them.
 * Given dquot(s), make disk block and/or inode reservations against them.
 * The fact that this does the reservation against both the usr and
 * The fact that this does the reservation against both the usr and
 * grp quotas is important, because this follows a both-or-nothing
 * grp/prj quotas is important, because this follows a both-or-nothing
 * approach.
 * approach.
 *
 *
 * flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked.
 * flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked.
 *	   XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
 *	   XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
 *	   XFS_QMOPT_ENOSPC returns ENOSPC not EDQUOT.  Used by pquota.
 *	   XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks
 *	   XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks
 *	   XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks
 *	   XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks
 * dquots are unlocked on return, if they were not locked by caller.
 * dquots are unlocked on return, if they were not locked by caller.
@@ -772,25 +772,27 @@ xfs_trans_reserve_quota_bydquots(
	long		ninos,
	long		ninos,
	uint		flags)
	uint		flags)
{
{
	int		resvd;
	int		resvd = 0, error;


	if (!XFS_IS_QUOTA_ON(mp))
	if (!XFS_IS_QUOTA_ON(mp))
		return (0);
		return 0;


	if (tp && tp->t_dqinfo == NULL)
	if (tp && tp->t_dqinfo == NULL)
		xfs_trans_alloc_dqinfo(tp);
		xfs_trans_alloc_dqinfo(tp);


	ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
	ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
	resvd = 0;


	if (udqp) {
	if (udqp) {
		if (xfs_trans_dqresv(tp, mp, udqp, nblks, ninos, flags))
		error = xfs_trans_dqresv(tp, mp, udqp, nblks, ninos,
			return (EDQUOT);
					(flags & ~XFS_QMOPT_ENOSPC));
		if (error)
			return error;
		resvd = 1;
		resvd = 1;
	}
	}


	if (gdqp) {
	if (gdqp) {
		if (xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags)) {
		error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags);
		if (error) {
			/*
			/*
			 * can't do it, so backout previous reservation
			 * can't do it, so backout previous reservation
			 */
			 */
@@ -799,14 +801,14 @@ xfs_trans_reserve_quota_bydquots(
				xfs_trans_dqresv(tp, mp, udqp,
				xfs_trans_dqresv(tp, mp, udqp,
						 -nblks, -ninos, flags);
						 -nblks, -ninos, flags);
			}
			}
			return (EDQUOT);
			return error;
		}
		}
	}
	}


	/*
	/*
	 * Didn't change anything critical, so, no need to log
	 * Didn't change anything critical, so, no need to log
	 */
	 */
	return (0);
	return 0;
}
}




@@ -814,8 +816,6 @@ xfs_trans_reserve_quota_bydquots(
 * Lock the dquot and change the reservation if we can.
 * Lock the dquot and change the reservation if we can.
 * This doesn't change the actual usage, just the reservation.
 * This doesn't change the actual usage, just the reservation.
 * The inode sent in is locked.
 * The inode sent in is locked.
 *
 * Returns 0 on success, EDQUOT or other errors otherwise
 */
 */
STATIC int
STATIC int
xfs_trans_reserve_quota_nblks(
xfs_trans_reserve_quota_nblks(
@@ -824,20 +824,24 @@ xfs_trans_reserve_quota_nblks(
	xfs_inode_t	*ip,
	xfs_inode_t	*ip,
	long		nblks,
	long		nblks,
	long		ninos,
	long		ninos,
	uint		type)
	uint		flags)
{
{
	int		error;
	int		error;


	if (!XFS_IS_QUOTA_ON(mp))
	if (!XFS_IS_QUOTA_ON(mp))
		return (0);
		return 0;
	if (XFS_IS_PQUOTA_ON(mp))
		flags |= XFS_QMOPT_ENOSPC;


	ASSERT(ip->i_ino != mp->m_sb.sb_uquotino);
	ASSERT(ip->i_ino != mp->m_sb.sb_uquotino);
	ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);
	ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);


	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
	ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
	ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
	ASSERT((type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_RTBLKS ||
	ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
	       (type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_BLKS);
				XFS_TRANS_DQ_RES_RTBLKS ||
	       (flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
				XFS_TRANS_DQ_RES_BLKS);


	/*
	/*
	 * Reserve nblks against these dquots, with trans as the mediator.
	 * Reserve nblks against these dquots, with trans as the mediator.
@@ -845,8 +849,8 @@ xfs_trans_reserve_quota_nblks(
	error = xfs_trans_reserve_quota_bydquots(tp, mp,
	error = xfs_trans_reserve_quota_bydquots(tp, mp,
						 ip->i_udquot, ip->i_gdquot,
						 ip->i_udquot, ip->i_gdquot,
						 nblks, ninos,
						 nblks, ninos,
						 type);
						 flags);
	return (error);
	return error;
}
}


/*
/*
+5 −6
Original line number Original line Diff line number Diff line
@@ -4719,18 +4719,17 @@ xfs_bmapi(
				/*
				/*
				 * Make a transaction-less quota reservation for
				 * Make a transaction-less quota reservation for
				 * delayed allocation blocks. This number gets
				 * delayed allocation blocks. This number gets
				 * adjusted later.
				 * adjusted later.  We return if we haven't
				 * We return EDQUOT if we haven't allocated
				 * allocated blocks already inside this loop.
				 * blks already inside this loop;
				 */
				 */
				if (XFS_TRANS_RESERVE_QUOTA_NBLKS(
				if ((error = XFS_TRANS_RESERVE_QUOTA_NBLKS(
						mp, NULL, ip, (long)alen, 0,
						mp, NULL, ip, (long)alen, 0,
						rt ? XFS_QMOPT_RES_RTBLKS :
						rt ? XFS_QMOPT_RES_RTBLKS :
						     XFS_QMOPT_RES_REGBLKS)) {
						     XFS_QMOPT_RES_REGBLKS))) {
					if (n == 0) {
					if (n == 0) {
						*nmap = 0;
						*nmap = 0;
						ASSERT(cur == NULL);
						ASSERT(cur == NULL);
						return XFS_ERROR(EDQUOT);
						return error;
					}
					}
					break;
					break;
				}
				}
+3 −2
Original line number Original line Diff line number Diff line
@@ -196,10 +196,11 @@ typedef struct xfs_qoff_logformat {
#define XFS_QMOPT_QUOTAOFF	0x0000080 /* quotas are being turned off */
#define XFS_QMOPT_QUOTAOFF	0x0000080 /* quotas are being turned off */
#define XFS_QMOPT_UMOUNTING	0x0000100 /* filesys is being unmounted */
#define XFS_QMOPT_UMOUNTING	0x0000100 /* filesys is being unmounted */
#define XFS_QMOPT_DOLOG		0x0000200 /* log buf changes (in quotacheck) */
#define XFS_QMOPT_DOLOG		0x0000200 /* log buf changes (in quotacheck) */
#define XFS_QMOPT_DOWARN        0x0000400 /* increase warning cnt if necessary */
#define XFS_QMOPT_DOWARN        0x0000400 /* increase warning cnt if needed */
#define XFS_QMOPT_ILOCKED	0x0000800 /* inode is already locked (excl) */
#define XFS_QMOPT_ILOCKED	0x0000800 /* inode is already locked (excl) */
#define XFS_QMOPT_DQREPAIR	0x0001000 /* repair dquot, if damaged. */
#define XFS_QMOPT_DQREPAIR	0x0001000 /* repair dquot if damaged */
#define XFS_QMOPT_GQUOTA	0x0002000 /* group dquot requested */
#define XFS_QMOPT_GQUOTA	0x0002000 /* group dquot requested */
#define XFS_QMOPT_ENOSPC	0x0004000 /* enospc instead of edquot (prj) */


/*
/*
 * flags to xfs_trans_mod_dquot to indicate which field needs to be
 * flags to xfs_trans_mod_dquot to indicate which field needs to be