[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: Nathan Scott <nathans@sgi.com>
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 73c1e5e8..7fb5eca 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -2624,7 +2624,7 @@
 {
 	int		error;
 	xfs_mount_t	*mp;
-	uint		delblks, blkflags;
+	uint		delblks, blkflags, prjflags = 0;
 	xfs_dquot_t	*unresudq, *unresgdq, *delblksudq, *delblksgdq;
 
 	ASSERT(XFS_ISLOCKED_INODE(ip));
@@ -2650,10 +2650,13 @@
 		}
 	}
 	if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) {
-		if ((XFS_IS_GQUOTA_ON(ip->i_mount) &&
-		     ip->i_d.di_gid != be32_to_cpu(gdqp->q_core.d_id)) ||
-		    (XFS_IS_PQUOTA_ON(ip->i_mount) &&
-		     ip->i_d.di_projid != be32_to_cpu(gdqp->q_core.d_id))) {
+		if (XFS_IS_PQUOTA_ON(ip->i_mount) &&
+		     ip->i_d.di_projid != be32_to_cpu(gdqp->q_core.d_id))
+			prjflags = XFS_QMOPT_ENOSPC;
+
+		if (prjflags ||
+		    (XFS_IS_GQUOTA_ON(ip->i_mount) &&
+		     ip->i_d.di_gid != be32_to_cpu(gdqp->q_core.d_id))) {
 			delblksgdq = gdqp;
 			if (delblks) {
 				ASSERT(ip->i_gdquot);
@@ -2664,7 +2667,7 @@
 
 	if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
 				delblksudq, delblksgdq, ip->i_d.di_nblocks, 1,
-				flags | blkflags)))
+				flags | blkflags | prjflags)))
 		return (error);
 
 	/*
@@ -2681,7 +2684,7 @@
 		ASSERT(unresudq || unresgdq);
 		if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
 				delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0,
-				flags | blkflags)))
+				flags | blkflags | prjflags)))
 			return (error);
 		xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
 				unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0,
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c
index d8e131e..9168918 100644
--- a/fs/xfs/quota/xfs_trans_dquot.c
+++ b/fs/xfs/quota/xfs_trans_dquot.c
@@ -595,12 +595,19 @@
 	}
 }
 
+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.
  * 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(
@@ -666,19 +673,15 @@
 			 */
 			if (hardlimit > 0ULL &&
 			     (hardlimit <= nblks + *resbcountp)) {
-				error = EDQUOT;
+				error = xfs_quota_error(flags);
 				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;
+					error = xfs_quota_error(flags);
 					goto error_return;
 				}
 			}
@@ -695,16 +698,12 @@
 			if (!softlimit)
 				softlimit = q->qi_isoftlimit;
 			if (hardlimit > 0ULL && count >= hardlimit) {
-				error = EDQUOT;
+				error = xfs_quota_error(flags);
 				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;
+					error = xfs_quota_error(flags);
 					goto error_return;
 				}
 			}
@@ -751,13 +750,14 @@
 
 
 /*
- * 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
- * grp quotas is important, because this follows a both-or-nothing
+ * grp/prj quotas is important, because this follows a both-or-nothing
  * approach.
  *
  * flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked.
  *	   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_RTBLKS reserves realtime disk blocks
  * dquots are unlocked on return, if they were not locked by caller.
@@ -772,25 +772,27 @@
 	long		ninos,
 	uint		flags)
 {
-	int		resvd;
+	int		resvd = 0, error;
 
-	if (! XFS_IS_QUOTA_ON(mp))
-		return (0);
+	if (!XFS_IS_QUOTA_ON(mp))
+		return 0;
 
 	if (tp && tp->t_dqinfo == NULL)
 		xfs_trans_alloc_dqinfo(tp);
 
 	ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
-	resvd = 0;
 
 	if (udqp) {
-		if (xfs_trans_dqresv(tp, mp, udqp, nblks, ninos, flags))
-			return (EDQUOT);
+		error = xfs_trans_dqresv(tp, mp, udqp, nblks, ninos,
+					(flags & ~XFS_QMOPT_ENOSPC));
+		if (error)
+			return error;
 		resvd = 1;
 	}
 
 	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
 			 */
@@ -799,14 +801,14 @@
 				xfs_trans_dqresv(tp, mp, udqp,
 						 -nblks, -ninos, flags);
 			}
-			return (EDQUOT);
+			return error;
 		}
 	}
 
 	/*
 	 * Didn't change anything critical, so, no need to log
 	 */
-	return (0);
+	return 0;
 }
 
 
@@ -814,8 +816,6 @@
  * Lock the dquot and change the reservation if we can.
  * This doesn't change the actual usage, just the reservation.
  * The inode sent in is locked.
- *
- * Returns 0 on success, EDQUOT or other errors otherwise
  */
 STATIC int
 xfs_trans_reserve_quota_nblks(
@@ -824,20 +824,24 @@
 	xfs_inode_t	*ip,
 	long		nblks,
 	long		ninos,
-	uint		type)
+	uint		flags)
 {
 	int		error;
 
 	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_gquotino);
 
 	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
 	ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
-	ASSERT((type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_RTBLKS ||
-	       (type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_BLKS);
+	ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
+				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.
@@ -845,8 +849,8 @@
 	error = xfs_trans_reserve_quota_bydquots(tp, mp,
 						 ip->i_udquot, ip->i_gdquot,
 						 nblks, ninos,
-						 type);
-	return (error);
+						 flags);
+	return error;
 }
 
 /*
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index d384e48..26939d3 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -4719,18 +4719,17 @@
 				/*
 				 * Make a transaction-less quota reservation for
 				 * delayed allocation blocks. This number gets
-				 * adjusted later.
-				 * We return EDQUOT if we haven't allocated
-				 * blks already inside this loop;
+				 * adjusted later.  We return if we haven't
+				 * allocated blocks already inside this loop.
 				 */
-				if (XFS_TRANS_RESERVE_QUOTA_NBLKS(
+				if ((error = XFS_TRANS_RESERVE_QUOTA_NBLKS(
 						mp, NULL, ip, (long)alen, 0,
 						rt ? XFS_QMOPT_RES_RTBLKS :
-						     XFS_QMOPT_RES_REGBLKS)) {
+						     XFS_QMOPT_RES_REGBLKS))) {
 					if (n == 0) {
 						*nmap = 0;
 						ASSERT(cur == NULL);
-						return XFS_ERROR(EDQUOT);
+						return error;
 					}
 					break;
 				}
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index 4f6a034..7fbef97 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -196,10 +196,11 @@
 #define XFS_QMOPT_QUOTAOFF	0x0000080 /* quotas are being turned off */
 #define XFS_QMOPT_UMOUNTING	0x0000100 /* filesys is being unmounted */
 #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_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_ENOSPC	0x0004000 /* enospc instead of edquot (prj) */
 
 /*
  * flags to xfs_trans_mod_dquot to indicate which field needs to be