All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v8 0/5] xfs: Allow pquota and gquota to be used together
@ 2013-05-10 21:21 Chandra Seetharaman
  2013-05-10 21:21 ` [PATCH v8 1/5] xfs: Remove incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD Chandra Seetharaman
                   ` (4 more replies)
  0 siblings, 5 replies; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-10 21:21 UTC (permalink / raw)
  To: xfs; +Cc: Chandra Seetharaman

Hello All,

This is the version 8 of the changes to allow pquota and gquota to be used
together.

Patchset applies cleanly on top of 7dfbcbefad4b24d9822d04dbd7b5dd5c3fd45076
in xfs git tree.

Ran latest xfstests against it.

Changes from version 7 to version 8:
 - Rebased to the current code.
 - Modified code to use the new pquotino field in version 5
   of the superblock.

Version 7 can be found at:
http://oss.sgi.com/archives/xfs/2013-03/msg00671.html

Changes from version 6 to version 7:
 - Made all the changes suggested by Dave Chinner
 - Added padding to fs_quota_stat, which made the new
   data structure field ordering different from the old data
   structure field ordering. So, copied the old version
   to be _v1 version and used that if old version of data
   structure was provided from user space.

Version 6 can be found at:
http://oss.sgi.com/archives/xfs/2012-07/msg00286.html

Changes from version 5 to version 6:
- Use radix tree instead of hash table

Version 5 can be found at:
http://oss.sgi.com/archives/xfs/2012-03/msg00310.html

Changes fron version 4 to version 5:
rebase with the current tree one simple change.

Version 4 can be found at
http://oss.sgi.com/archives/xfs/2012-02/msg00528.html

Changes from version 3 to version 4:
- Remove save_flags with storing the value (in to superblock) 
  based on field type info
- fix checkpatch.pl warnings and errors

Version 3 of the posting can be found at
http://oss.sgi.com/archives/xfs/2012-01/msg00309.html

Changes from version 2 to version 3:
 - hash table for pquota is added.
 - changes to apply cleanly with the latest tree

version 2 of the posting can be found at
http://oss.sgi.com/archives/xfs/2011-10/msg00470.html

Changes from version 1 to version 2:

 - Created a new prep patch to accomodate some generic changes that ease
   the later patches.
 - Created a new patch to add a new field qs_pquota to fs_quota_stat
   with appropriate versioning changes
 - Changed the logic to allow XFS_OQUOTA.* flags to be allowed only in
   the older versions.
 - Changed couple of places where PQUOTA checking was on the else if
   construct so as to allow both GQUOTA and PQUOTA in those places.
 - Fixed comments in xfs_quota.h to reflect the current changes.
 - Changed the name of the macro XFS_SB_VERSION2_SEPER_PQUOTA to 
   XFS_SB_VERSION2_NO_OQUOTA
 - got rid of the macros XFS_MOUNT_QUOTA_SET1 and XFS_MOUNT_QUOTA_SET2
 - added a new inline function xfs_inode_dquot(ip, type) to simplify
   the error path in xfs_qm_dqget()
 - got rid of the macro XFS_IS_THIS_QUOTA_OFF
 - added comment to explain why sb_qflags is saved and restored in 
   xfs_sb_to_disk()

version 1 of the posting can be found at
http://oss.sgi.com/archives/xfs/2011-10/msg00341.html

Thanks & Regards,

chandra
Chandra Seetharaman (5):
  xfs: Remove incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD
  xfs: Add pquota fields where gquota is used.
  xfs: Start using pquotaino from the superblock
  xfs: Add proper versioning support to fs_quota_stat
  xfs: Use new qs_pquota field in fs_quota_stat for Q_XGETQSTAT

 fs/gfs2/quota.c                |    3 -
 fs/quota/quota.c               |   40 ++++-
 fs/xfs/xfs_dquot.c             |   33 +++-
 fs/xfs/xfs_dquot.h             |   13 +-
 fs/xfs/xfs_icache.c            |    4 +-
 fs/xfs/xfs_inode.h             |    1 +
 fs/xfs/xfs_ioctl.c             |   14 +-
 fs/xfs/xfs_iops.c              |    4 +-
 fs/xfs/xfs_itable.c            |    3 +-
 fs/xfs/xfs_mount.c             |  102 +++++++++++
 fs/xfs/xfs_qm.c                |  379 ++++++++++++++++++++++++++--------------
 fs/xfs/xfs_qm.h                |   53 ++++--
 fs/xfs/xfs_qm_bhv.c            |    2 +-
 fs/xfs/xfs_qm_syscalls.c       |  125 +++++++++-----
 fs/xfs/xfs_quota.h             |   78 +++++----
 fs/xfs/xfs_quotaops.c          |    6 +-
 fs/xfs/xfs_sb.h                |    5 +
 fs/xfs/xfs_super.c             |   35 ++--
 fs/xfs/xfs_symlink.c           |   13 +-
 fs/xfs/xfs_trans_dquot.c       |  102 ++++++-----
 fs/xfs/xfs_vnodeops.c          |   12 +-
 include/uapi/linux/dqblk_xfs.h |   37 ++++-
 22 files changed, 731 insertions(+), 333 deletions(-)

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v8 1/5] xfs: Remove incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD
  2013-05-10 21:21 [PATCH v8 0/5] xfs: Allow pquota and gquota to be used together Chandra Seetharaman
@ 2013-05-10 21:21 ` Chandra Seetharaman
  2013-05-13  3:15   ` Jeff Liu
  2013-05-17  2:55   ` Dave Chinner
  2013-05-10 21:21 ` [PATCH v8 2/5] xfs: Add pquota fields where gquota is used Chandra Seetharaman
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-10 21:21 UTC (permalink / raw)
  To: xfs; +Cc: Chandra Seetharaman

Remove all incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD. Instead,
start using XFS_GQUOTA_.* XFS_PQUOTA_.* counterparts for GQUOTA and
PQUOTA respectively.

On-disk copy still uses XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD.

Read and write of the superblock does the conversion from *OQUOTA*
to *[PG]QUOTA*.

Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/xfs_mount.c       |   41 +++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_qm.c          |    9 ++++++---
 fs/xfs/xfs_qm_syscalls.c |   39 +++++++++++++++++++++------------------
 fs/xfs/xfs_quota.h       |   42 ++++++++++++++++++++++++++++--------------
 fs/xfs/xfs_quotaops.c    |    6 ++++--
 fs/xfs/xfs_super.c       |   16 ++++++++--------
 fs/xfs/xfs_trans_dquot.c |    4 ++--
 7 files changed, 110 insertions(+), 47 deletions(-)

diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index f6bfbd7..1b79906 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -564,6 +564,8 @@ xfs_sb_from_disk(
 	struct xfs_sb	*to,
 	xfs_dsb_t	*from)
 {
+	bool force_quota_check = false;
+
 	to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
 	to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
 	to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
@@ -599,6 +601,21 @@ xfs_sb_from_disk(
 	to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
 	to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
 	to->sb_qflags = be16_to_cpu(from->sb_qflags);
+	if ((to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) &&
+			(to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
+				XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))) {
+		xfs_notice(NULL, "Super block has XFS_OQUOTA bits along with "
+		    "XFS_PQUOTA and/or XFS_GQUOTA bits. Quota check forced.\n");
+		force_quota_check = true;
+	}
+	if (to->sb_qflags & XFS_OQUOTA_ENFD)
+		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
+					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
+	if (to->sb_qflags & XFS_OQUOTA_CHKD)
+		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
+					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
+	to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
+
 	to->sb_flags = from->sb_flags;
 	to->sb_shared_vn = from->sb_shared_vn;
 	to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
@@ -618,6 +635,9 @@ xfs_sb_from_disk(
 	to->sb_pad = 0;
 	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
 	to->sb_lsn = be64_to_cpu(from->sb_lsn);
+
+	if (force_quota_check)
+		to->sb_qflags &= ~(XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD);
 }
 
 /*
@@ -636,11 +656,30 @@ xfs_sb_to_disk(
 	xfs_sb_field_t	f;
 	int		first;
 	int		size;
+	__uint16_t	qflags = from->sb_qflags;
 
 	ASSERT(fields);
 	if (!fields)
 		return;
 
+	if (fields & XFS_SB_QFLAGS) {
+		/*
+		 * The in-core version of sb_qflags do not have
+		 * XFS_OQUOTA_* flags, whereas the on-disk version
+		 * does.  So, convert incore XFS_{PG}QUOTA_* flags 
+		 * to on-disk XFS_OQUOTA_* flags.
+		 */
+		qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
+				XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
+
+		if (from->sb_qflags &
+				(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
+			qflags |= XFS_OQUOTA_ENFD;
+		if (from->sb_qflags &
+				(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
+			qflags |= XFS_OQUOTA_CHKD;
+	}
+
 	while (fields) {
 		f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
 		first = xfs_sb_info[f].offset;
@@ -650,6 +689,8 @@ xfs_sb_to_disk(
 
 		if (size == 1 || xfs_sb_info[f].type == 1) {
 			memcpy(to_ptr + first, from_ptr + first, size);
+		} else if (f == XFS_SBS_QFLAGS) {
+			*(__be16 *)(to_ptr + first) = cpu_to_be16(qflags);
 		} else {
 			switch (size) {
 			case 2:
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index f41702b..fe4c743 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -298,8 +298,10 @@ xfs_qm_mount_quotas(
 	 */
 	if (!XFS_IS_UQUOTA_ON(mp))
 		mp->m_qflags &= ~XFS_UQUOTA_CHKD;
-	if (!(XFS_IS_GQUOTA_ON(mp) || XFS_IS_PQUOTA_ON(mp)))
-		mp->m_qflags &= ~XFS_OQUOTA_CHKD;
+	if (!XFS_IS_GQUOTA_ON(mp))
+		mp->m_qflags &= ~XFS_GQUOTA_CHKD;
+	if (!XFS_IS_PQUOTA_ON(mp))
+		mp->m_qflags &= ~XFS_PQUOTA_CHKD;
 
  write_changes:
 	/*
@@ -1280,7 +1282,8 @@ xfs_qm_quotacheck(
 					 &buffer_list);
 		if (error)
 			goto error_return;
-		flags |= XFS_OQUOTA_CHKD;
+		flags |= XFS_IS_GQUOTA_ON(mp) ?
+					XFS_GQUOTA_CHKD : XFS_PQUOTA_CHKD;
 	}
 
 	do {
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index c41190c..f005f1d 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -117,11 +117,11 @@ xfs_qm_scall_quotaoff(
 	}
 	if (flags & XFS_GQUOTA_ACCT) {
 		dqtype |= XFS_QMOPT_GQUOTA;
-		flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
+		flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
 		inactivate_flags |= XFS_GQUOTA_ACTIVE;
 	} else if (flags & XFS_PQUOTA_ACCT) {
 		dqtype |= XFS_QMOPT_PQUOTA;
-		flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
+		flags |= (XFS_PQUOTA_CHKD | XFS_PQUOTA_ENFD);
 		inactivate_flags |= XFS_PQUOTA_ACTIVE;
 	}
 
@@ -335,14 +335,14 @@ xfs_qm_scall_quotaon(
 	 * quota acct on ondisk without m_qflags' knowing.
 	 */
 	if (((flags & XFS_UQUOTA_ACCT) == 0 &&
-	    (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
-	    (flags & XFS_UQUOTA_ENFD))
-	    ||
+	     (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
+	     (flags & XFS_UQUOTA_ENFD)) ||
 	    ((flags & XFS_PQUOTA_ACCT) == 0 &&
-	    (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
-	    (flags & XFS_GQUOTA_ACCT) == 0 &&
-	    (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
-	    (flags & XFS_OQUOTA_ENFD))) {
+	     (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
+	     (flags & XFS_PQUOTA_ENFD)) ||
+	    ((flags & XFS_GQUOTA_ACCT) == 0 &&
+	     (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
+	     (flags & XFS_GQUOTA_ENFD))) {
 		xfs_debug(mp,
 			"%s: Can't enforce without acct, flags=%x sbflags=%x\n",
 			__func__, flags, mp->m_sb.sb_qflags);
@@ -770,9 +770,12 @@ xfs_qm_scall_getquota(
 	 * gets turned off. No need to confuse the user level code,
 	 * so return zeroes in that case.
 	 */
-	if ((!XFS_IS_UQUOTA_ENFORCED(mp) && dqp->q_core.d_flags == XFS_DQ_USER) ||
-	    (!XFS_IS_OQUOTA_ENFORCED(mp) &&
-			(dqp->q_core.d_flags & (XFS_DQ_PROJ | XFS_DQ_GROUP)))) {
+	if ((!XFS_IS_UQUOTA_ENFORCED(mp) &&
+	     dqp->q_core.d_flags == XFS_DQ_USER) ||
+	    (!XFS_IS_PQUOTA_ENFORCED(mp) &&
+	     dqp->q_core.d_flags == XFS_DQ_PROJ) ||
+	    (!XFS_IS_GQUOTA_ENFORCED(mp) &&
+	     dqp->q_core.d_flags == XFS_DQ_GROUP)) {
 		dst->d_btimer = 0;
 		dst->d_itimer = 0;
 		dst->d_rtbtimer = 0;
@@ -780,8 +783,8 @@ xfs_qm_scall_getquota(
 
 #ifdef DEBUG
 	if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == FS_USER_QUOTA) ||
-	     (XFS_IS_OQUOTA_ENFORCED(mp) &&
-			(dst->d_flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)))) &&
+	     (XFS_IS_PQUOTA_ENFORCED(mp) && dst->d_flags == FS_PROJ_QUOTA) ||
+	     (XFS_IS_GQUOTA_ENFORCED(mp) && dst->d_flags == FS_GROUP_QUOTA)) &&
 	    dst->d_id != 0) {
 		if ((dst->d_bcount > dst->d_blk_softlimit) &&
 		    (dst->d_blk_softlimit > 0)) {
@@ -833,10 +836,10 @@ xfs_qm_export_flags(
 		uflags |= FS_QUOTA_GDQ_ACCT;
 	if (flags & XFS_UQUOTA_ENFD)
 		uflags |= FS_QUOTA_UDQ_ENFD;
-	if (flags & (XFS_OQUOTA_ENFD)) {
-		uflags |= (flags & XFS_GQUOTA_ACCT) ?
-			FS_QUOTA_GDQ_ENFD : FS_QUOTA_PDQ_ENFD;
-	}
+	if (flags & XFS_PQUOTA_ENFD)
+		uflags |= FS_QUOTA_PDQ_ENFD;
+	if (flags & XFS_GQUOTA_ENFD)
+		uflags |= FS_QUOTA_GDQ_ENFD;
 	return (uflags);
 }
 
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index c61e31c..ccff1a6 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -159,28 +159,43 @@ typedef struct xfs_qoff_logformat {
 #define XFS_GQUOTA_ACCT	0x0040  /* group quota accounting ON */
 
 /*
+ * Start differentiating group quota and project quota in-core
+ * using distinct flags, instead of using the combined OQUOTA flags.
+ *
+ * Conversion to and from the combined OQUOTA flag (if necessary)
+ * is done only in xfs_sb_{to,from}_disk()
+ */
+#define XFS_GQUOTA_ENFD	0x0080  /* group quota limits enforced */
+#define XFS_GQUOTA_CHKD	0x0100  /* quotacheck run on group quotas */
+#define XFS_PQUOTA_ENFD	0x0200  /* project quota limits enforced */
+#define XFS_PQUOTA_CHKD	0x0400  /* quotacheck run on project quotas */
+
+/*
  * Quota Accounting/Enforcement flags
  */
 #define XFS_ALL_QUOTA_ACCT	\
 		(XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT)
-#define XFS_ALL_QUOTA_ENFD	(XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD)
-#define XFS_ALL_QUOTA_CHKD	(XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD)
+#define XFS_ALL_QUOTA_ENFD	\
+		(XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD | XFS_PQUOTA_ENFD)
+#define XFS_ALL_QUOTA_CHKD	\
+		(XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD)
 
 #define XFS_IS_QUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
 #define XFS_IS_UQUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_UQUOTA_ACCT)
 #define XFS_IS_PQUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_PQUOTA_ACCT)
 #define XFS_IS_GQUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_GQUOTA_ACCT)
 #define XFS_IS_UQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_UQUOTA_ENFD)
-#define XFS_IS_OQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_OQUOTA_ENFD)
+#define XFS_IS_PQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_PQUOTA_ENFD)
+#define XFS_IS_GQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_GQUOTA_ENFD)
 
 /*
  * Incore only flags for quotaoff - these bits get cleared when quota(s)
  * are in the process of getting turned off. These flags are in m_qflags but
  * never in sb_qflags.
  */
-#define XFS_UQUOTA_ACTIVE	0x0100  /* uquotas are being turned off */
-#define XFS_PQUOTA_ACTIVE	0x0200  /* pquotas are being turned off */
-#define XFS_GQUOTA_ACTIVE	0x0400  /* gquotas are being turned off */
+#define XFS_UQUOTA_ACTIVE	0x1000  /* uquotas are being turned off */
+#define XFS_PQUOTA_ACTIVE	0x2000  /* pquotas are being turned off */
+#define XFS_GQUOTA_ACTIVE	0x4000  /* gquotas are being turned off */
 #define XFS_ALL_QUOTA_ACTIVE	\
 	(XFS_UQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE)
 
@@ -266,24 +281,23 @@ typedef struct xfs_qoff_logformat {
 	((XFS_IS_UQUOTA_ON(mp) && \
 		(mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD) == 0) || \
 	 (XFS_IS_GQUOTA_ON(mp) && \
-		((mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD) == 0 || \
-		 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT))) || \
+		(mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD) == 0) || \
 	 (XFS_IS_PQUOTA_ON(mp) && \
-		((mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD) == 0 || \
-		 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT))))
+		(mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD) == 0))
 
 #define XFS_MOUNT_QUOTA_SET1	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
 				 XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
-				 XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD)
+				 XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD)
 
 #define XFS_MOUNT_QUOTA_SET2	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
 				 XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
-				 XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD)
+				 XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD)
 
 #define XFS_MOUNT_QUOTA_ALL	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
 				 XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
-				 XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD|\
-				 XFS_GQUOTA_ACCT)
+				 XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD|\
+				 XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD|\
+				 XFS_GQUOTA_CHKD)
 
 
 /*
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index 71926d6..056d62e 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -75,8 +75,10 @@ xfs_fs_set_xstate(
 		flags |= XFS_GQUOTA_ACCT;
 	if (uflags & FS_QUOTA_UDQ_ENFD)
 		flags |= XFS_UQUOTA_ENFD;
-	if (uflags & (FS_QUOTA_PDQ_ENFD|FS_QUOTA_GDQ_ENFD))
-		flags |= XFS_OQUOTA_ENFD;
+	if (uflags & FS_QUOTA_PDQ_ENFD)
+		flags |= XFS_PQUOTA_ENFD;
+	if (uflags & FS_QUOTA_GDQ_ENFD)
+		flags |= XFS_GQUOTA_ENFD;
 
 	switch (op) {
 	case Q_XQUOTAON:
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index ea341ce..873fa5a 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -359,17 +359,17 @@ xfs_parseargs(
 		} else if (!strcmp(this_char, MNTOPT_PQUOTA) ||
 			   !strcmp(this_char, MNTOPT_PRJQUOTA)) {
 			mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE |
-					 XFS_OQUOTA_ENFD);
+					 XFS_PQUOTA_ENFD);
 		} else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) {
 			mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE);
-			mp->m_qflags &= ~XFS_OQUOTA_ENFD;
+			mp->m_qflags &= ~XFS_PQUOTA_ENFD;
 		} else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
 			   !strcmp(this_char, MNTOPT_GRPQUOTA)) {
 			mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE |
-					 XFS_OQUOTA_ENFD);
+					 XFS_GQUOTA_ENFD);
 		} else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
 			mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
-			mp->m_qflags &= ~XFS_OQUOTA_ENFD;
+			mp->m_qflags &= ~XFS_GQUOTA_ENFD;
 		} else if (!strcmp(this_char, MNTOPT_DELAYLOG)) {
 			xfs_warn(mp,
 	"delaylog is the default now, option is deprecated.");
@@ -563,12 +563,12 @@ xfs_showargs(
 	/* Either project or group quotas can be active, not both */
 
 	if (mp->m_qflags & XFS_PQUOTA_ACCT) {
-		if (mp->m_qflags & XFS_OQUOTA_ENFD)
+		if (mp->m_qflags & XFS_PQUOTA_ENFD)
 			seq_puts(m, "," MNTOPT_PRJQUOTA);
 		else
 			seq_puts(m, "," MNTOPT_PQUOTANOENF);
 	} else if (mp->m_qflags & XFS_GQUOTA_ACCT) {
-		if (mp->m_qflags & XFS_OQUOTA_ENFD)
+		if (mp->m_qflags & XFS_GQUOTA_ENFD)
 			seq_puts(m, "," MNTOPT_GRPQUOTA);
 		else
 			seq_puts(m, "," MNTOPT_GQUOTANOENF);
@@ -1136,8 +1136,8 @@ xfs_fs_statfs(
 	spin_unlock(&mp->m_sb_lock);
 
 	if ((ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
-	    ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))) ==
-			      (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))
+	    ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))) ==
+			      (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))
 		xfs_qm_statvfs(ip, statp);
 	return 0;
 }
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index fec75d0..8cdbd62 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -640,8 +640,8 @@ xfs_trans_dqresv(
 	if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
 	    dqp->q_core.d_id &&
 	    ((XFS_IS_UQUOTA_ENFORCED(dqp->q_mount) && XFS_QM_ISUDQ(dqp)) ||
-	     (XFS_IS_OQUOTA_ENFORCED(dqp->q_mount) &&
-	      (XFS_QM_ISPDQ(dqp) || XFS_QM_ISGDQ(dqp))))) {
+	     (XFS_IS_PQUOTA_ENFORCED(dqp->q_mount) && XFS_QM_ISPDQ(dqp)) ||
+	     (XFS_IS_GQUOTA_ENFORCED(dqp->q_mount) && XFS_QM_ISGDQ(dqp)))) {
 		if (nblks > 0) {
 			/*
 			 * dquot is locked already. See if we'd go over the
-- 
1.7.1

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v8 2/5] xfs: Add pquota fields where gquota is used.
  2013-05-10 21:21 [PATCH v8 0/5] xfs: Allow pquota and gquota to be used together Chandra Seetharaman
  2013-05-10 21:21 ` [PATCH v8 1/5] xfs: Remove incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD Chandra Seetharaman
@ 2013-05-10 21:21 ` Chandra Seetharaman
  2013-05-13  3:59   ` Jeff Liu
  2013-05-17  4:23   ` Dave Chinner
  2013-05-10 21:21 ` [PATCH v8 3/5] xfs: Start using pquotaino from the superblock Chandra Seetharaman
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-10 21:21 UTC (permalink / raw)
  To: xfs; +Cc: Chandra Seetharaman

Add project quota changes to all the places where group quota field
is used:
   * add separate project quota members into various structures
   * split project quota and group quotas so that instead of overriding
     the group quota members incore, the new project quota members are
     used instead
   * get rid of usage of the OQUOTA flag incore, in favor of separate
   * group
     and project quota flags.
   * add a project dquot argument to various functions.

No externally visible interfaces changed.

Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
---
 fs/xfs/xfs_dquot.c       |   33 ++++-
 fs/xfs/xfs_dquot.h       |   13 +-
 fs/xfs/xfs_icache.c      |    4 +-
 fs/xfs/xfs_inode.h       |    1 +
 fs/xfs/xfs_ioctl.c       |   14 +-
 fs/xfs/xfs_iops.c        |    4 +-
 fs/xfs/xfs_qm.c          |  355 ++++++++++++++++++++++++++++++----------------
 fs/xfs/xfs_qm.h          |   53 +++++---
 fs/xfs/xfs_qm_bhv.c      |    2 +-
 fs/xfs/xfs_qm_syscalls.c |   19 ++-
 fs/xfs/xfs_quota.h       |   32 +++--
 fs/xfs/xfs_super.c       |    5 +-
 fs/xfs/xfs_symlink.c     |   13 ++-
 fs/xfs/xfs_trans_dquot.c |   94 +++++++------
 fs/xfs/xfs_vnodeops.c    |   12 +-
 15 files changed, 416 insertions(+), 238 deletions(-)

diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index a41f8bf..a25ba5d 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -68,8 +68,7 @@ static struct lock_class_key xfs_dquot_other_class;
  * This is called to free all the memory associated with a dquot
  */
 void
-xfs_qm_dqdestroy(
-	xfs_dquot_t	*dqp)
+xfs_qm_dqdestroy(xfs_dquot_t	*dqp)
 {
 	ASSERT(list_empty(&dqp->q_lru));
 
@@ -568,6 +567,17 @@ xfs_qm_dqrepair(
 	return 0;
 }
 
+struct xfs_inode *
+xfs_dq_to_quota_inode(struct xfs_dquot *dqp)
+{
+	if (XFS_QM_ISUDQ(dqp))
+		return dqp->q_mount->m_quotainfo->qi_uquotaip;
+	if (XFS_QM_ISGDQ(dqp))
+		return dqp->q_mount->m_quotainfo->qi_gquotaip;
+	ASSERT(XFS_QM_ISPDQ(dqp));
+	return dqp->q_mount->m_quotainfo->qi_pquotaip;
+}
+
 /*
  * Maps a dquot to the buffer containing its on-disk version.
  * This returns a ptr to the buffer containing the on-disk dquot
@@ -584,7 +594,7 @@ xfs_qm_dqtobp(
 	xfs_bmbt_irec_t map;
 	int		nmaps = 1, error;
 	xfs_buf_t	*bp;
-	xfs_inode_t	*quotip = XFS_DQ_TO_QIP(dqp);
+	xfs_inode_t	*quotip = xfs_dq_to_quota_inode(dqp);
 	xfs_mount_t	*mp = dqp->q_mount;
 	xfs_dqid_t	id = be32_to_cpu(dqp->q_core.d_id);
 	xfs_trans_t	*tp = (tpp ? *tpp : NULL);
@@ -815,7 +825,7 @@ xfs_qm_dqget(
 	xfs_dquot_t	**O_dqpp) /* OUT : locked incore dquot */
 {
 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
-	struct radix_tree_root *tree = XFS_DQUOT_TREE(qi, type);
+	struct radix_tree_root *tree = xfs_dquot_tree(qi, type);
 	struct xfs_dquot	*dqp;
 	int			error;
 
@@ -947,6 +957,7 @@ xfs_qm_dqput_final(
 {
 	struct xfs_quotainfo	*qi = dqp->q_mount->m_quotainfo;
 	struct xfs_dquot	*gdqp;
+	struct xfs_dquot	*pdqp;
 
 	trace_xfs_dqput_free(dqp);
 
@@ -960,21 +971,29 @@ xfs_qm_dqput_final(
 
 	/*
 	 * If we just added a udquot to the freelist, then we want to release
-	 * the gdquot reference that it (probably) has. Otherwise it'll keep
-	 * the gdquot from getting reclaimed.
+	 * the gdquot/pdquot reference that it (probably) has. Otherwise it'll
+	 * keep the gdquot/pdquot from getting reclaimed.
 	 */
 	gdqp = dqp->q_gdquot;
 	if (gdqp) {
 		xfs_dqlock(gdqp);
 		dqp->q_gdquot = NULL;
 	}
+
+	pdqp = dqp->q_pdquot;
+	if (pdqp) {
+		xfs_dqlock(pdqp);
+		dqp->q_pdquot = NULL;
+	}
 	xfs_dqunlock(dqp);
 
 	/*
-	 * If we had a group quota hint, release it now.
+	 * If we had a group/project quota hint, release it now.
 	 */
 	if (gdqp)
 		xfs_qm_dqput(gdqp);
+	if (pdqp)
+		xfs_qm_dqput(pdqp);
 }
 
 /*
diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
index 4f0ebfc..00ccbf1 100644
--- a/fs/xfs/xfs_dquot.h
+++ b/fs/xfs/xfs_dquot.h
@@ -29,7 +29,6 @@
  * when quotas are off.
  */
 
-struct xfs_mount;
 struct xfs_trans;
 
 enum {
@@ -52,7 +51,8 @@ typedef struct xfs_dquot {
 	int		 q_bufoffset;	/* off of dq in buffer (# dquots) */
 	xfs_fileoff_t	 q_fileoffset;	/* offset in quotas file */
 
-	struct xfs_dquot*q_gdquot;	/* group dquot, hint only */
+	struct xfs_dquot *q_gdquot;	/* group dquot, hint only */
+	struct xfs_dquot *q_pdquot;	/* project dquot, hint only */
 	xfs_disk_dquot_t q_core;	/* actual usage & quotas */
 	xfs_dq_logitem_t q_logitem;	/* dquot log item */
 	xfs_qcnt_t	 q_res_bcount;	/* total regular nblks used+reserved */
@@ -118,8 +118,9 @@ static inline int xfs_this_quota_on(struct xfs_mount *mp, int type)
 	case XFS_DQ_USER:
 		return XFS_IS_UQUOTA_ON(mp);
 	case XFS_DQ_GROUP:
+		return XFS_IS_GQUOTA_ON(mp);
 	case XFS_DQ_PROJ:
-		return XFS_IS_OQUOTA_ON(mp);
+		return XFS_IS_PQUOTA_ON(mp);
 	default:
 		return 0;
 	}
@@ -131,8 +132,9 @@ static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
 	case XFS_DQ_USER:
 		return ip->i_udquot;
 	case XFS_DQ_GROUP:
-	case XFS_DQ_PROJ:
 		return ip->i_gdquot;
+	case XFS_DQ_PROJ:
+		return ip->i_pdquot;
 	default:
 		return NULL;
 	}
@@ -144,9 +146,6 @@ static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
 #define XFS_QM_ISPDQ(dqp)	((dqp)->dq_flags & XFS_DQ_PROJ)
 #define XFS_QM_ISGDQ(dqp)	((dqp)->dq_flags & XFS_DQ_GROUP)
 #define XFS_DQ_TO_QINF(dqp)	((dqp)->q_mount->m_quotainfo)
-#define XFS_DQ_TO_QIP(dqp)	(XFS_QM_ISUDQ(dqp) ? \
-				 XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \
-				 XFS_DQ_TO_QINF(dqp)->qi_gquotaip)
 
 extern int		xfs_qm_dqread(struct xfs_mount *, xfs_dqid_t, uint,
 					uint, struct xfs_dquot	**);
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 96e344e..3f90e1c 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -335,7 +335,9 @@ xfs_iget_cache_miss(
 	iflags = XFS_INEW;
 	if (flags & XFS_IGET_DONTCACHE)
 		iflags |= XFS_IDONTCACHE;
-	ip->i_udquot = ip->i_gdquot = NULL;
+	ip->i_udquot = NULL;
+	ip->i_gdquot = NULL;
+	ip->i_pdquot = NULL;
 	xfs_iflags_set(ip, iflags);
 
 	/* insert the new inode */
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 9112979..b55fd34 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -250,6 +250,7 @@ typedef struct xfs_inode {
 	struct xfs_mount	*i_mount;	/* fs mount struct ptr */
 	struct xfs_dquot	*i_udquot;	/* user dquot */
 	struct xfs_dquot	*i_gdquot;	/* group dquot */
+	struct xfs_dquot	*i_pdquot;	/* project dquot */
 
 	/* Inode location stuff */
 	xfs_ino_t		i_ino;		/* inode number (agno/agino)*/
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 5e99968..71a8bc5 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -928,7 +928,7 @@ xfs_ioctl_setattr(
 	struct xfs_trans	*tp;
 	unsigned int		lock_flags = 0;
 	struct xfs_dquot	*udqp = NULL;
-	struct xfs_dquot	*gdqp = NULL;
+	struct xfs_dquot	*pdqp = NULL;
 	struct xfs_dquot	*olddquot = NULL;
 	int			code;
 
@@ -957,7 +957,7 @@ xfs_ioctl_setattr(
 	if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
 		code = xfs_qm_vop_dqalloc(ip, ip->i_d.di_uid,
 					 ip->i_d.di_gid, fa->fsx_projid,
-					 XFS_QMOPT_PQUOTA, &udqp, &gdqp);
+					 XFS_QMOPT_PQUOTA, &udqp, NULL, &pdqp);
 		if (code)
 			return code;
 	}
@@ -994,8 +994,8 @@ xfs_ioctl_setattr(
 		    XFS_IS_PQUOTA_ON(mp) &&
 		    xfs_get_projid(ip) != fa->fsx_projid) {
 			ASSERT(tp);
-			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
-						capable(CAP_FOWNER) ?
+			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL,
+						pdqp, capable(CAP_FOWNER) ?
 						XFS_QMOPT_FORCE_RES : 0);
 			if (code)	/* out of quota */
 				goto error_return;
@@ -1113,7 +1113,7 @@ xfs_ioctl_setattr(
 		if (xfs_get_projid(ip) != fa->fsx_projid) {
 			if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
 				olddquot = xfs_qm_vop_chown(tp, ip,
-							&ip->i_gdquot, gdqp);
+							&ip->i_pdquot, pdqp);
 			}
 			xfs_set_projid(ip, fa->fsx_projid);
 
@@ -1160,13 +1160,13 @@ xfs_ioctl_setattr(
 	 */
 	xfs_qm_dqrele(olddquot);
 	xfs_qm_dqrele(udqp);
-	xfs_qm_dqrele(gdqp);
+	xfs_qm_dqrele(pdqp);
 
 	return code;
 
  error_return:
 	xfs_qm_dqrele(udqp);
-	xfs_qm_dqrele(gdqp);
+	xfs_qm_dqrele(pdqp);
 	xfs_trans_cancel(tp, 0);
 	if (lock_flags)
 		xfs_iunlock(ip, lock_flags);
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index d82efaa..7c54ea4 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -517,7 +517,7 @@ xfs_setattr_nonsize(
 		ASSERT(udqp == NULL);
 		ASSERT(gdqp == NULL);
 		error = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip),
-					 qflags, &udqp, &gdqp);
+					 qflags, &udqp, &gdqp, NULL);
 		if (error)
 			return error;
 	}
@@ -553,7 +553,7 @@ xfs_setattr_nonsize(
 		     (XFS_IS_GQUOTA_ON(mp) && igid != gid))) {
 			ASSERT(tp);
 			error = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
-						capable(CAP_FOWNER) ?
+						NULL, capable(CAP_FOWNER) ?
 						XFS_QMOPT_FORCE_RES : 0);
 			if (error)	/* out of quota */
 				goto out_trans_cancel;
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index fe4c743..97912cb 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -69,7 +69,7 @@ xfs_qm_dquot_walk(
 	void			*data)
 {
 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
-	struct radix_tree_root	*tree = XFS_DQUOT_TREE(qi, type);
+	struct radix_tree_root	*tree = xfs_dquot_tree(qi, type);
 	uint32_t		next_index;
 	int			last_error = 0;
 	int			skipped;
@@ -136,6 +136,7 @@ xfs_qm_dqpurge(
 	struct xfs_mount	*mp = dqp->q_mount;
 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
 	struct xfs_dquot	*gdqp = NULL;
+	struct xfs_dquot	*pdqp = NULL;
 
 	xfs_dqlock(dqp);
 	if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) {
@@ -144,8 +145,7 @@ xfs_qm_dqpurge(
 	}
 
 	/*
-	 * If this quota has a group hint attached, prepare for releasing it
-	 * now.
+	 * If this quota has a hint attached, prepare for releasing it now.
 	 */
 	gdqp = dqp->q_gdquot;
 	if (gdqp) {
@@ -153,6 +153,12 @@ xfs_qm_dqpurge(
 		dqp->q_gdquot = NULL;
 	}
 
+	pdqp = dqp->q_pdquot;
+	if (pdqp) {
+		xfs_dqlock(pdqp);
+		dqp->q_pdquot = NULL;
+	}
+
 	dqp->dq_flags |= XFS_DQ_FREEING;
 
 	xfs_dqflock(dqp);
@@ -188,7 +194,7 @@ xfs_qm_dqpurge(
 	xfs_dqfunlock(dqp);
 	xfs_dqunlock(dqp);
 
-	radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags),
+	radix_tree_delete(xfs_dquot_tree(qi, dqp->q_core.d_flags),
 			  be32_to_cpu(dqp->q_core.d_id));
 	qi->qi_dquots--;
 
@@ -207,6 +213,8 @@ xfs_qm_dqpurge(
 
 	if (gdqp)
 		xfs_qm_dqput(gdqp);
+	if (pdqp)
+		xfs_qm_dqput(pdqp);
 	return 0;
 }
 
@@ -363,6 +371,10 @@ xfs_qm_unmount_quotas(
 			IRELE(mp->m_quotainfo->qi_gquotaip);
 			mp->m_quotainfo->qi_gquotaip = NULL;
 		}
+		if (mp->m_quotainfo->qi_pquotaip) {
+			IRELE(mp->m_quotainfo->qi_pquotaip);
+			mp->m_quotainfo->qi_pquotaip = NULL;
+		}
 	}
 }
 
@@ -409,7 +421,10 @@ xfs_qm_dqattach_one(
 		 * be reclaimed as long as we have a ref from inode and we
 		 * hold the ilock.
 		 */
-		dqp = udqhint->q_gdquot;
+		if (type == XFS_DQ_GROUP)
+			dqp = udqhint->q_gdquot;
+		else
+			dqp = udqhint->q_pdquot;
 		if (dqp && be32_to_cpu(dqp->q_core.d_id) == id) {
 			ASSERT(*IO_idqpp == NULL);
 
@@ -452,28 +467,38 @@ xfs_qm_dqattach_one(
 
 
 /*
- * Given a udquot and gdquot, attach a ptr to the group dquot in the
+ * Given a udquot and gdquot, attach a ptr to the group/project dquot in the
  * udquot as a hint for future lookups.
  */
 STATIC void
-xfs_qm_dqattach_grouphint(
-	xfs_dquot_t	*udq,
-	xfs_dquot_t	*gdq)
+xfs_qm_dqattach_grouphint(xfs_inode_t *ip, int type)
 {
-	xfs_dquot_t	*tmp;
+	struct xfs_dquot **dqhint;
+	struct xfs_dquot *gpdq;
+	struct xfs_dquot *udq = ip->i_udquot;
 
 	xfs_dqlock(udq);
 
-	tmp = udq->q_gdquot;
-	if (tmp) {
-		if (tmp == gdq)
+	if (type == XFS_DQ_GROUP) {
+		gpdq = ip->i_gdquot;
+		dqhint = &udq->q_gdquot;
+	} else {
+		gpdq = ip->i_pdquot;
+		dqhint = &udq->q_pdquot;
+	}
+
+	if (*dqhint) {
+		struct xfs_dquot *tmp;
+
+		if (*dqhint == gpdq)
 			goto done;
 
-		udq->q_gdquot = NULL;
+		tmp = *dqhint;
+		*dqhint = NULL;
 		xfs_qm_dqrele(tmp);
 	}
 
-	udq->q_gdquot = xfs_qm_dqhold(gdq);
+	*dqhint = xfs_qm_dqhold(gpdq);
 done:
 	xfs_dqunlock(udq);
 }
@@ -527,12 +552,8 @@ xfs_qm_dqattach_locked(
 	}
 
 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-	if (XFS_IS_OQUOTA_ON(mp)) {
-		error = XFS_IS_GQUOTA_ON(mp) ?
-			xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
-						flags & XFS_QMOPT_DQALLOC,
-						ip->i_udquot, &ip->i_gdquot) :
-			xfs_qm_dqattach_one(ip, xfs_get_projid(ip), XFS_DQ_PROJ,
+	if (XFS_IS_GQUOTA_ON(mp)) {
+		error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
 						flags & XFS_QMOPT_DQALLOC,
 						ip->i_udquot, &ip->i_gdquot);
 		/*
@@ -544,14 +565,28 @@ xfs_qm_dqattach_locked(
 		nquotas++;
 	}
 
+	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+	if (XFS_IS_PQUOTA_ON(mp)) {
+		error = xfs_qm_dqattach_one(ip, xfs_get_projid(ip), XFS_DQ_PROJ,
+						flags & XFS_QMOPT_DQALLOC,
+						ip->i_udquot, &ip->i_pdquot);
+		/*
+		 * Don't worry about the udquot that we may have
+		 * attached above. It'll get detached, if not already.
+		 */
+		if (error)
+			goto done;
+		nquotas++;
+	}
+
 	/*
-	 * Attach this group quota to the user quota as a hint.
+	 * Attach this group/project quota to the user quota as a hint.
 	 * This WON'T, in general, result in a thrash.
 	 */
-	if (nquotas == 2) {
+	if (nquotas > 1 && ip->i_udquot) {
 		ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-		ASSERT(ip->i_udquot);
-		ASSERT(ip->i_gdquot);
+		ASSERT(ip->i_gdquot || !XFS_IS_GQUOTA_ON(mp));
+		ASSERT(ip->i_pdquot || !XFS_IS_PQUOTA_ON(mp));
 
 		/*
 		 * We do not have i_udquot locked at this point, but this check
@@ -559,8 +594,13 @@ xfs_qm_dqattach_locked(
 		 * 100% all the time. It is just a hint, and this will
 		 * succeed in general.
 		 */
-		if (ip->i_udquot->q_gdquot != ip->i_gdquot)
-			xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot);
+		if (XFS_IS_GQUOTA_ON(mp) &&
+				ip->i_udquot->q_gdquot != ip->i_gdquot)
+			xfs_qm_dqattach_grouphint(ip, XFS_DQ_GROUP);
+
+		if (XFS_IS_PQUOTA_ON(mp) &&
+				ip->i_udquot->q_pdquot != ip->i_pdquot)
+			xfs_qm_dqattach_grouphint(ip, XFS_DQ_PROJ);
 	}
 
  done:
@@ -568,8 +608,10 @@ xfs_qm_dqattach_locked(
 	if (!error) {
 		if (XFS_IS_UQUOTA_ON(mp))
 			ASSERT(ip->i_udquot);
-		if (XFS_IS_OQUOTA_ON(mp))
+		if (XFS_IS_GQUOTA_ON(mp))
 			ASSERT(ip->i_gdquot);
+		if (XFS_IS_PQUOTA_ON(mp))
+			ASSERT(ip->i_pdquot);
 	}
 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 #endif
@@ -602,7 +644,7 @@ void
 xfs_qm_dqdetach(
 	xfs_inode_t	*ip)
 {
-	if (!(ip->i_udquot || ip->i_gdquot))
+	if (!(ip->i_udquot || ip->i_gdquot || ip->i_pdquot))
 		return;
 
 	trace_xfs_dquot_dqdetach(ip);
@@ -617,6 +659,10 @@ xfs_qm_dqdetach(
 		xfs_qm_dqrele(ip->i_gdquot);
 		ip->i_gdquot = NULL;
 	}
+	if (ip->i_pdquot) {
+		xfs_qm_dqrele(ip->i_pdquot);
+		ip->i_pdquot = NULL;
+	}
 }
 
 int
@@ -661,6 +707,7 @@ xfs_qm_init_quotainfo(
 
 	INIT_RADIX_TREE(&qinf->qi_uquota_tree, GFP_NOFS);
 	INIT_RADIX_TREE(&qinf->qi_gquota_tree, GFP_NOFS);
+	INIT_RADIX_TREE(&qinf->qi_pquota_tree, GFP_NOFS);
 	mutex_init(&qinf->qi_tree_lock);
 
 	INIT_LIST_HEAD(&qinf->qi_lru_list);
@@ -762,6 +809,10 @@ xfs_qm_destroy_quotainfo(
 		IRELE(qi->qi_gquotaip);
 		qi->qi_gquotaip = NULL;
 	}
+	if (qi->qi_pquotaip) {
+		IRELE(qi->qi_pquotaip);
+		qi->qi_pquotaip = NULL;
+	}
 	mutex_destroy(&qi->qi_quotaofflock);
 	kmem_free(qi);
 	mp->m_quotainfo = NULL;
@@ -1247,16 +1298,18 @@ xfs_qm_quotacheck(
 	int		done, count, error, error2;
 	xfs_ino_t	lastino;
 	size_t		structsz;
-	xfs_inode_t	*uip, *gip;
 	uint		flags;
 	LIST_HEAD	(buffer_list);
+	struct xfs_inode	*uip = mp->m_quotainfo->qi_uquotaip;
+	struct xfs_inode	*gip = mp->m_quotainfo->qi_gquotaip;
+	struct xfs_inode	*pip = mp->m_quotainfo->qi_pquotaip;
 
 	count = INT_MAX;
 	structsz = 1;
 	lastino = 0;
 	flags = 0;
 
-	ASSERT(mp->m_quotainfo->qi_uquotaip || mp->m_quotainfo->qi_gquotaip);
+	ASSERT(uip || gip || pip);
 	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
 	xfs_notice(mp, "Quotacheck needed: Please wait.");
@@ -1266,7 +1319,6 @@ xfs_qm_quotacheck(
 	 * their counters to zero. We need a clean slate.
 	 * We don't log our changes till later.
 	 */
-	uip = mp->m_quotainfo->qi_uquotaip;
 	if (uip) {
 		error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA,
 					 &buffer_list);
@@ -1275,15 +1327,20 @@ xfs_qm_quotacheck(
 		flags |= XFS_UQUOTA_CHKD;
 	}
 
-	gip = mp->m_quotainfo->qi_gquotaip;
 	if (gip) {
-		error = xfs_qm_dqiterate(mp, gip, XFS_IS_GQUOTA_ON(mp) ?
-					 XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA,
+		error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA,
+					 &buffer_list);
+		if (error)
+			goto error_return;
+		flags |= XFS_GQUOTA_CHKD;
+	}
+
+	if (pip) {
+		error = xfs_qm_dqiterate(mp, pip, XFS_QMOPT_PQUOTA,
 					 &buffer_list);
 		if (error)
 			goto error_return;
-		flags |= XFS_IS_GQUOTA_ON(mp) ?
-					XFS_GQUOTA_CHKD : XFS_PQUOTA_CHKD;
+		flags |= XFS_PQUOTA_CHKD;
 	}
 
 	do {
@@ -1378,13 +1435,14 @@ STATIC int
 xfs_qm_init_quotainos(
 	xfs_mount_t	*mp)
 {
-	xfs_inode_t	*uip, *gip;
+	struct xfs_inode	*uip = NULL;
+	struct xfs_inode	*gip = NULL;
+	struct xfs_inode	*pip = NULL;
 	int		error;
 	__int64_t	sbflags;
 	uint		flags;
 
 	ASSERT(mp->m_quotainfo);
-	uip = gip = NULL;
 	sbflags = 0;
 	flags = 0;
 
@@ -1395,19 +1453,27 @@ xfs_qm_init_quotainos(
 		if (XFS_IS_UQUOTA_ON(mp) &&
 		    mp->m_sb.sb_uquotino != NULLFSINO) {
 			ASSERT(mp->m_sb.sb_uquotino > 0);
-			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
-					     0, 0, &uip)))
+			error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
+					     0, 0, &uip);
+			if (error)
 				return XFS_ERROR(error);
 		}
-		if (XFS_IS_OQUOTA_ON(mp) &&
+		if (XFS_IS_GQUOTA_ON(mp) &&
 		    mp->m_sb.sb_gquotino != NULLFSINO) {
 			ASSERT(mp->m_sb.sb_gquotino > 0);
-			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
-					     0, 0, &gip))) {
-				if (uip)
-					IRELE(uip);
-				return XFS_ERROR(error);
-			}
+			error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+					     0, 0, &gip);
+			if (error)
+				goto error_rele;
+		}
+		/* Use sb_gquotino for now */
+		if (XFS_IS_PQUOTA_ON(mp) &&
+		    mp->m_sb.sb_gquotino != NULLFSINO) {
+			ASSERT(mp->m_sb.sb_gquotino > 0);
+			error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+					     0, 0, &pip);
+			if (error)
+				goto error_rele;
 		}
 	} else {
 		flags |= XFS_QMOPT_SBVERSION;
@@ -1416,36 +1482,50 @@ xfs_qm_init_quotainos(
 	}
 
 	/*
-	 * Create the two inodes, if they don't exist already. The changes
+	 * Create the three inodes, if they don't exist already. The changes
 	 * made above will get added to a transaction and logged in one of
 	 * the qino_alloc calls below.  If the device is readonly,
 	 * temporarily switch to read-write to do this.
 	 */
 	if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) {
-		if ((error = xfs_qm_qino_alloc(mp, &uip,
+		error = xfs_qm_qino_alloc(mp, &uip,
 					      sbflags | XFS_SB_UQUOTINO,
-					      flags | XFS_QMOPT_UQUOTA)))
+					      flags | XFS_QMOPT_UQUOTA);
+		if (error)
 			return XFS_ERROR(error);
 
 		flags &= ~XFS_QMOPT_SBVERSION;
 	}
-	if (XFS_IS_OQUOTA_ON(mp) && gip == NULL) {
-		flags |= (XFS_IS_GQUOTA_ON(mp) ?
-				XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA);
+	if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
 		error = xfs_qm_qino_alloc(mp, &gip,
-					  sbflags | XFS_SB_GQUOTINO, flags);
-		if (error) {
-			if (uip)
-				IRELE(uip);
-
-			return XFS_ERROR(error);
-		}
+					     sbflags | XFS_SB_GQUOTINO,
+					     flags | XFS_QMOPT_GQUOTA);
+		if (error)
+			goto error_rele;
+	}
+	if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
+		error = xfs_qm_qino_alloc(mp, &pip,
+					     sbflags | XFS_SB_GQUOTINO,
+					     flags | XFS_QMOPT_PQUOTA);
+		if (error)
+			goto error_rele;
 	}
 
 	mp->m_quotainfo->qi_uquotaip = uip;
 	mp->m_quotainfo->qi_gquotaip = gip;
+	mp->m_quotainfo->qi_pquotaip = pip;
 
 	return 0;
+
+error_rele:
+	if (uip)
+		IRELE(uip);
+	if (gip)
+		IRELE(gip);
+	if (pip)
+		IRELE(pip);
+	return XFS_ERROR(error);
+
 }
 
 STATIC void
@@ -1456,7 +1536,7 @@ xfs_qm_dqfree_one(
 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
 
 	mutex_lock(&qi->qi_tree_lock);
-	radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags),
+	radix_tree_delete(xfs_dquot_tree(qi, dqp->q_core.d_flags),
 			  be32_to_cpu(dqp->q_core.d_id));
 
 	qi->qi_dquots--;
@@ -1639,10 +1719,13 @@ xfs_qm_vop_dqalloc(
 	prid_t			prid,
 	uint			flags,
 	struct xfs_dquot	**O_udqpp,
-	struct xfs_dquot	**O_gdqpp)
+	struct xfs_dquot	**O_gdqpp,
+	struct xfs_dquot	**O_pdqpp)
 {
 	struct xfs_mount	*mp = ip->i_mount;
-	struct xfs_dquot	*uq, *gq;
+	struct xfs_dquot	*uq = NULL;
+	struct xfs_dquot	*gq = NULL;
+	struct xfs_dquot	*pq = NULL;
 	int			error;
 	uint			lockflags;
 
@@ -1667,7 +1750,6 @@ xfs_qm_vop_dqalloc(
 		}
 	}
 
-	uq = gq = NULL;
 	if ((flags & XFS_QMOPT_UQUOTA) && XFS_IS_UQUOTA_ON(mp)) {
 		if (ip->i_d.di_uid != uid) {
 			/*
@@ -1680,14 +1762,14 @@ xfs_qm_vop_dqalloc(
 			 * holding ilock.
 			 */
 			xfs_iunlock(ip, lockflags);
-			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid,
+			error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid,
 						 XFS_DQ_USER,
 						 XFS_QMOPT_DQALLOC |
 						 XFS_QMOPT_DOWARN,
-						 &uq))) {
-				ASSERT(error != ENOENT);
+						 &uq);
+			ASSERT(error != ENOENT);
+			if (error)
 				return error;
-			}
 			/*
 			 * Get the ilock in the right order.
 			 */
@@ -1706,16 +1788,15 @@ xfs_qm_vop_dqalloc(
 	if ((flags & XFS_QMOPT_GQUOTA) && XFS_IS_GQUOTA_ON(mp)) {
 		if (ip->i_d.di_gid != gid) {
 			xfs_iunlock(ip, lockflags);
-			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,
+			error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,
 						 XFS_DQ_GROUP,
 						 XFS_QMOPT_DQALLOC |
 						 XFS_QMOPT_DOWARN,
-						 &gq))) {
-				if (uq)
-					xfs_qm_dqrele(uq);
-				ASSERT(error != ENOENT);
-				return error;
-			}
+						 &gq);
+			ASSERT(error != ENOENT);
+			if (error)
+				goto error_rele;
+
 			xfs_dqunlock(gq);
 			lockflags = XFS_ILOCK_SHARED;
 			xfs_ilock(ip, lockflags);
@@ -1723,25 +1804,25 @@ xfs_qm_vop_dqalloc(
 			ASSERT(ip->i_gdquot);
 			gq = xfs_qm_dqhold(ip->i_gdquot);
 		}
-	} else if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) {
+	}
+	if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) {
 		if (xfs_get_projid(ip) != prid) {
 			xfs_iunlock(ip, lockflags);
-			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid,
+			error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid,
 						 XFS_DQ_PROJ,
 						 XFS_QMOPT_DQALLOC |
 						 XFS_QMOPT_DOWARN,
-						 &gq))) {
-				if (uq)
-					xfs_qm_dqrele(uq);
-				ASSERT(error != ENOENT);
-				return (error);
-			}
-			xfs_dqunlock(gq);
+						 &pq);
+			ASSERT(error != ENOENT);
+			if (error)
+				goto error_rele;
+
+			xfs_dqunlock(pq);
 			lockflags = XFS_ILOCK_SHARED;
 			xfs_ilock(ip, lockflags);
 		} else {
-			ASSERT(ip->i_gdquot);
-			gq = xfs_qm_dqhold(ip->i_gdquot);
+			ASSERT(ip->i_pdquot);
+			pq = xfs_qm_dqhold(ip->i_pdquot);
 		}
 	}
 	if (uq)
@@ -1756,7 +1837,18 @@ xfs_qm_vop_dqalloc(
 		*O_gdqpp = gq;
 	else if (gq)
 		xfs_qm_dqrele(gq);
+	if (O_pdqpp)
+		*O_pdqpp = pq;
+	else if (pq)
+		xfs_qm_dqrele(pq);
 	return 0;
+
+error_rele:
+	if (uq)
+		xfs_qm_dqrele(uq);
+	if (gq)
+		xfs_qm_dqrele(gq);
+	return error;
 }
 
 /*
@@ -1804,15 +1896,21 @@ xfs_qm_vop_chown(
  */
 int
 xfs_qm_vop_chown_reserve(
-	xfs_trans_t	*tp,
-	xfs_inode_t	*ip,
-	xfs_dquot_t	*udqp,
-	xfs_dquot_t	*gdqp,
-	uint		flags)
+	xfs_trans_t		*tp,
+	xfs_inode_t		*ip,
+	struct xfs_dquot	*udqp,
+	struct xfs_dquot	*gdqp,
+	struct xfs_dquot	*pdqp,
+	uint			flags)
 {
 	xfs_mount_t	*mp = ip->i_mount;
 	uint		delblks, blkflags, prjflags = 0;
-	xfs_dquot_t	*unresudq, *unresgdq, *delblksudq, *delblksgdq;
+	struct xfs_dquot	*unresudq = NULL;
+	struct xfs_dquot	*unresgdq = NULL;
+	struct xfs_dquot	*unrespdq = NULL;
+	struct xfs_dquot	*delblksudq = NULL;
+	struct xfs_dquot	*delblksgdq = NULL;
+	struct xfs_dquot	*delblkspdq = NULL;
 	int		error;
 
 
@@ -1820,7 +1918,6 @@ xfs_qm_vop_chown_reserve(
 	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
 	delblks = ip->i_delayed_blks;
-	delblksudq = delblksgdq = unresudq = unresgdq = NULL;
 	blkflags = XFS_IS_REALTIME_INODE(ip) ?
 			XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS;
 
@@ -1837,25 +1934,29 @@ xfs_qm_vop_chown_reserve(
 			unresudq = ip->i_udquot;
 		}
 	}
-	if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) {
-		if (XFS_IS_PQUOTA_ON(ip->i_mount) &&
-		     xfs_get_projid(ip) != 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);
-				unresgdq = ip->i_gdquot;
-			}
+	if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp &&
+	    ip->i_d.di_gid != be32_to_cpu(gdqp->q_core.d_id)) {
+		delblksgdq = gdqp;
+		if (delblks) {
+			ASSERT(ip->i_gdquot);
+			unresgdq = ip->i_gdquot;
+		}
+	}
+
+	if (XFS_IS_PQUOTA_ON(ip->i_mount) && pdqp &&
+	    xfs_get_projid(ip) != be32_to_cpu(pdqp->q_core.d_id)) {
+		prjflags = XFS_QMOPT_ENOSPC;
+		delblkspdq = pdqp;
+		if (delblks) {
+			ASSERT(ip->i_pdquot);
+			unrespdq = ip->i_pdquot;
 		}
 	}
 
-	if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
-				delblksudq, delblksgdq, ip->i_d.di_nblocks, 1,
-				flags | blkflags | prjflags)))
+	error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
+			delblksudq, delblksgdq, delblkspdq, ip->i_d.di_nblocks,
+			1, flags | blkflags | prjflags);
+	if (error)
 		return (error);
 
 	/*
@@ -1868,15 +1969,17 @@ xfs_qm_vop_chown_reserve(
 		/*
 		 * Do the reservations first. Unreservation can't fail.
 		 */
-		ASSERT(delblksudq || delblksgdq);
-		ASSERT(unresudq || unresgdq);
-		if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
-				delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0,
-				flags | blkflags | prjflags)))
+		ASSERT(delblksudq || delblksgdq || delblkspdq);
+		ASSERT(unresudq || unresgdq || unrespdq);
+		error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
+				delblksudq, delblksgdq, delblkspdq,
+				(xfs_qcnt_t)delblks, 0,
+				flags | blkflags | prjflags);
+		if (error)
 			return (error);
 		xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
-				unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0,
-				blkflags);
+				unresudq, unresgdq, unrespdq,
+				-((xfs_qcnt_t)delblks), 0, blkflags);
 	}
 
 	return (0);
@@ -1915,7 +2018,8 @@ xfs_qm_vop_create_dqattach(
 	struct xfs_trans	*tp,
 	struct xfs_inode	*ip,
 	struct xfs_dquot	*udqp,
-	struct xfs_dquot	*gdqp)
+	struct xfs_dquot	*gdqp,
+	struct xfs_dquot	*pdqp)
 {
 	struct xfs_mount	*mp = tp->t_mountp;
 
@@ -1935,13 +2039,18 @@ xfs_qm_vop_create_dqattach(
 	}
 	if (gdqp) {
 		ASSERT(ip->i_gdquot == NULL);
-		ASSERT(XFS_IS_OQUOTA_ON(mp));
-		ASSERT((XFS_IS_GQUOTA_ON(mp) ?
-			ip->i_d.di_gid : xfs_get_projid(ip)) ==
-				be32_to_cpu(gdqp->q_core.d_id));
-
+		ASSERT(XFS_IS_GQUOTA_ON(mp));
+		ASSERT(ip->i_d.di_gid == be32_to_cpu(gdqp->q_core.d_id));
 		ip->i_gdquot = xfs_qm_dqhold(gdqp);
 		xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
 	}
+	if (pdqp) {
+		ASSERT(ip->i_pdquot == NULL);
+		ASSERT(XFS_IS_PQUOTA_ON(mp));
+		ASSERT(xfs_get_projid(ip) == be32_to_cpu(pdqp->q_core.d_id));
+
+		ip->i_pdquot = xfs_qm_dqhold(pdqp);
+		xfs_trans_mod_dquot(tp, pdqp, XFS_TRANS_DQ_ICOUNT, 1);
+	}
 }
 
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 5d16a6e..f23b06b 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -44,9 +44,11 @@ extern struct kmem_zone	*xfs_qm_dqtrxzone;
 typedef struct xfs_quotainfo {
 	struct radix_tree_root qi_uquota_tree;
 	struct radix_tree_root qi_gquota_tree;
+	struct radix_tree_root qi_pquota_tree;
 	struct mutex qi_tree_lock;
-	xfs_inode_t	*qi_uquotaip;	 /* user quota inode */
-	xfs_inode_t	*qi_gquotaip;	 /* group quota inode */
+	struct xfs_inode *qi_uquotaip;	 /* user quota inode */
+	struct xfs_inode *qi_gquotaip;	 /* group quota inode */
+	struct xfs_inode *qi_pquotaip;	 /* project quota inode */
 	struct list_head qi_lru_list;
 	struct mutex	 qi_lru_lock;
 	int		 qi_lru_count;
@@ -69,30 +71,45 @@ typedef struct xfs_quotainfo {
 	struct shrinker  qi_shrinker;
 } xfs_quotainfo_t;
 
-#define XFS_DQUOT_TREE(qi, type) \
-	((type & XFS_DQ_USER) ? \
-	 &((qi)->qi_uquota_tree) : \
-	 &((qi)->qi_gquota_tree))
-
+static inline struct radix_tree_root *
+xfs_dquot_tree(
+	struct xfs_quotainfo	*qi,
+	int			type)
+{
+	switch (type) {
+	case XFS_DQ_USER:
+		return &qi->qi_uquota_tree;
+	case XFS_DQ_GROUP:
+		return &qi->qi_gquota_tree;
+	case XFS_DQ_PROJ:
+		return &qi->qi_pquota_tree;
+	default:
+		ASSERT(0);
+	}
+	return NULL;
+}
 
 extern int	xfs_qm_calc_dquots_per_chunk(struct xfs_mount *mp,
 					     unsigned int nbblks);
-extern void	xfs_trans_mod_dquot(xfs_trans_t *, xfs_dquot_t *, uint, long);
-extern int	xfs_trans_reserve_quota_bydquots(xfs_trans_t *, xfs_mount_t *,
-			xfs_dquot_t *, xfs_dquot_t *, long, long, uint);
-extern void	xfs_trans_dqjoin(xfs_trans_t *, xfs_dquot_t *);
-extern void	xfs_trans_log_dquot(xfs_trans_t *, xfs_dquot_t *);
+extern void	xfs_trans_mod_dquot(xfs_trans_t *, struct xfs_dquot *, uint, long);
+extern void	xfs_trans_dqjoin(xfs_trans_t *, struct xfs_dquot *);
+extern void	xfs_trans_log_dquot(xfs_trans_t *, struct xfs_dquot *);
 
 /*
- * We keep the usr and grp dquots separately so that locking will be easier
- * to do at commit time. All transactions that we know of at this point
+ * We keep the usr, grp, and prj dquots separately so that locking will be
+ * easier to do at commit time. All transactions that we know of at this point
  * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value.
  */
+enum {
+	XFS_QM_TRANS_USR = 0,
+	XFS_QM_TRANS_GRP,
+	XFS_QM_TRANS_PROJ,
+	XFS_QM_TRANS_DQTYPES
+};
 #define XFS_QM_TRANS_MAXDQS		2
-typedef struct xfs_dquot_acct {
-	xfs_dqtrx_t	dqa_usrdquots[XFS_QM_TRANS_MAXDQS];
-	xfs_dqtrx_t	dqa_grpdquots[XFS_QM_TRANS_MAXDQS];
-} xfs_dquot_acct_t;
+struct xfs_dquot_acct {
+	struct xfs_dqtrx dqs[XFS_QM_TRANS_DQTYPES][XFS_QM_TRANS_MAXDQS];
+};
 
 /*
  * Users are allowed to have a usage exceeding their softlimit for
diff --git a/fs/xfs/xfs_qm_bhv.c b/fs/xfs/xfs_qm_bhv.c
index 2d02eac..72a4fdd 100644
--- a/fs/xfs/xfs_qm_bhv.c
+++ b/fs/xfs/xfs_qm_bhv.c
@@ -115,7 +115,7 @@ xfs_qm_newmount(
 	     (pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
 	    (!pquotaondisk &&  XFS_IS_PQUOTA_ON(mp)) ||
 	     (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
-	    (!gquotaondisk &&  XFS_IS_OQUOTA_ON(mp)))  &&
+	    (!gquotaondisk &&  XFS_IS_GQUOTA_ON(mp)))  &&
 	    xfs_dev_is_read_only(mp, "changing quota state")) {
 		xfs_warn(mp, "please mount with%s%s%s%s.",
 			(!quotaondisk ? "out quota" : ""),
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index f005f1d..9bec772 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -119,7 +119,8 @@ xfs_qm_scall_quotaoff(
 		dqtype |= XFS_QMOPT_GQUOTA;
 		flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
 		inactivate_flags |= XFS_GQUOTA_ACTIVE;
-	} else if (flags & XFS_PQUOTA_ACCT) {
+	}
+	if (flags & XFS_PQUOTA_ACCT) {
 		dqtype |= XFS_QMOPT_PQUOTA;
 		flags |= (XFS_PQUOTA_CHKD | XFS_PQUOTA_ENFD);
 		inactivate_flags |= XFS_PQUOTA_ACTIVE;
@@ -214,10 +215,14 @@ xfs_qm_scall_quotaoff(
 		IRELE(q->qi_uquotaip);
 		q->qi_uquotaip = NULL;
 	}
-	if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && q->qi_gquotaip) {
+	if ((dqtype & XFS_QMOPT_GQUOTA) && q->qi_gquotaip) {
 		IRELE(q->qi_gquotaip);
 		q->qi_gquotaip = NULL;
 	}
+	if ((dqtype & XFS_QMOPT_PQUOTA) && q->qi_pquotaip) {
+		IRELE(q->qi_pquotaip);
+		q->qi_pquotaip = NULL;
+	}
 
 out_unlock:
 	mutex_unlock(&q->qi_quotaofflock);
@@ -853,9 +858,11 @@ xfs_dqrele_inode(
 {
 	/* skip quota inodes */
 	if (ip == ip->i_mount->m_quotainfo->qi_uquotaip ||
-	    ip == ip->i_mount->m_quotainfo->qi_gquotaip) {
+	    ip == ip->i_mount->m_quotainfo->qi_gquotaip ||
+	    ip == ip->i_mount->m_quotainfo->qi_pquotaip) {
 		ASSERT(ip->i_udquot == NULL);
 		ASSERT(ip->i_gdquot == NULL);
+		ASSERT(ip->i_pdquot == NULL);
 		return 0;
 	}
 
@@ -864,10 +871,14 @@ xfs_dqrele_inode(
 		xfs_qm_dqrele(ip->i_udquot);
 		ip->i_udquot = NULL;
 	}
-	if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) && ip->i_gdquot) {
+	if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) {
 		xfs_qm_dqrele(ip->i_gdquot);
 		ip->i_gdquot = NULL;
 	}
+	if ((flags & XFS_PQUOTA_ACCT) && ip->i_pdquot) {
+		xfs_qm_dqrele(ip->i_pdquot);
+		ip->i_pdquot = NULL;
+	}
 	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	return 0;
 }
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index ccff1a6..fe46c0c 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -272,10 +272,10 @@ typedef struct xfs_qoff_logformat {
  * we didn't have the inode locked, the appropriate dquot(s) will be
  * attached atomically.
  */
-#define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\
-				     (ip)->i_udquot == NULL) || \
-				    (XFS_IS_OQUOTA_ON(mp) && \
-				     (ip)->i_gdquot == NULL))
+#define XFS_NOT_DQATTACHED(mp, ip) \
+	((XFS_IS_UQUOTA_ON(mp) && (ip)->i_udquot == NULL) || \
+	 (XFS_IS_GQUOTA_ON(mp) && (ip)->i_gdquot == NULL) || \
+	 (XFS_IS_PQUOTA_ON(mp) && (ip)->i_pdquot == NULL))
 
 #define XFS_QM_NEED_QUOTACHECK(mp) \
 	((XFS_IS_UQUOTA_ON(mp) && \
@@ -330,17 +330,18 @@ extern int xfs_trans_reserve_quota_nblks(struct xfs_trans *,
 		struct xfs_inode *, long, long, uint);
 extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *,
 		struct xfs_mount *, struct xfs_dquot *,
-		struct xfs_dquot *, long, long, uint);
+		struct xfs_dquot *, struct xfs_dquot *, long, long, uint);
 
 extern int xfs_qm_vop_dqalloc(struct xfs_inode *, uid_t, gid_t, prid_t, uint,
-		struct xfs_dquot **, struct xfs_dquot **);
+		struct xfs_dquot **, struct xfs_dquot **, struct xfs_dquot **);
 extern void xfs_qm_vop_create_dqattach(struct xfs_trans *, struct xfs_inode *,
-		struct xfs_dquot *, struct xfs_dquot *);
+		struct xfs_dquot *, struct xfs_dquot *, struct xfs_dquot *);
 extern int xfs_qm_vop_rename_dqattach(struct xfs_inode **);
 extern struct xfs_dquot *xfs_qm_vop_chown(struct xfs_trans *,
 		struct xfs_inode *, struct xfs_dquot **, struct xfs_dquot *);
 extern int xfs_qm_vop_chown_reserve(struct xfs_trans *, struct xfs_inode *,
-		struct xfs_dquot *, struct xfs_dquot *, uint);
+		struct xfs_dquot *, struct xfs_dquot *,
+		struct xfs_dquot *, uint);
 extern int xfs_qm_dqattach(struct xfs_inode *, uint);
 extern int xfs_qm_dqattach_locked(struct xfs_inode *, uint);
 extern void xfs_qm_dqdetach(struct xfs_inode *);
@@ -354,10 +355,12 @@ extern void xfs_qm_unmount_quotas(struct xfs_mount *);
 #else
 static inline int
 xfs_qm_vop_dqalloc(struct xfs_inode *ip, uid_t uid, gid_t gid, prid_t prid,
-		uint flags, struct xfs_dquot **udqp, struct xfs_dquot **gdqp)
+		uint flags, struct xfs_dquot **udqp, struct xfs_dquot **gdqp,
+		struct xfs_dquot **pdqp)
 {
 	*udqp = NULL;
 	*gdqp = NULL;
+	*pdqp = NULL;
 	return 0;
 }
 #define xfs_trans_dup_dqinfo(tp, tp2)
@@ -372,14 +375,15 @@ static inline int xfs_trans_reserve_quota_nblks(struct xfs_trans *tp,
 }
 static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp,
 		struct xfs_mount *mp, struct xfs_dquot *udqp,
-		struct xfs_dquot *gdqp, long nblks, long nions, uint flags)
+		struct xfs_dquot *gdqp, struct xfs_dquot *pdqp,
+		long nblks, long nions, uint flags)
 {
 	return 0;
 }
-#define xfs_qm_vop_create_dqattach(tp, ip, u, g)
+#define xfs_qm_vop_create_dqattach(tp, ip, u, g, p)
 #define xfs_qm_vop_rename_dqattach(it)					(0)
 #define xfs_qm_vop_chown(tp, ip, old, new)				(NULL)
-#define xfs_qm_vop_chown_reserve(tp, ip, u, g, fl)			(0)
+#define xfs_qm_vop_chown_reserve(tp, ip, u, g, p, fl)			(0)
 #define xfs_qm_dqattach(ip, fl)						(0)
 #define xfs_qm_dqattach_locked(ip, fl)					(0)
 #define xfs_qm_dqdetach(ip)
@@ -393,8 +397,8 @@ static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp,
 
 #define xfs_trans_unreserve_quota_nblks(tp, ip, nblks, ninos, flags) \
 	xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), -(ninos), flags)
-#define xfs_trans_reserve_quota(tp, mp, ud, gd, nb, ni, f) \
-	xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, nb, ni, \
+#define xfs_trans_reserve_quota(tp, mp, ud, gd, pd, nb, ni, f) \
+	xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, pd, nb, ni, \
 				f | XFS_QMOPT_RES_REGBLKS)
 
 extern int xfs_qm_dqcheck(struct xfs_mount *, xfs_disk_dquot_t *,
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 873fa5a..5feac04 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -560,14 +560,13 @@ xfs_showargs(
 	else if (mp->m_qflags & XFS_UQUOTA_ACCT)
 		seq_puts(m, "," MNTOPT_UQUOTANOENF);
 
-	/* Either project or group quotas can be active, not both */
-
 	if (mp->m_qflags & XFS_PQUOTA_ACCT) {
 		if (mp->m_qflags & XFS_PQUOTA_ENFD)
 			seq_puts(m, "," MNTOPT_PRJQUOTA);
 		else
 			seq_puts(m, "," MNTOPT_PQUOTANOENF);
-	} else if (mp->m_qflags & XFS_GQUOTA_ACCT) {
+	}
+	if (mp->m_qflags & XFS_GQUOTA_ACCT) {
 		if (mp->m_qflags & XFS_GQUOTA_ENFD)
 			seq_puts(m, "," MNTOPT_GRPQUOTA);
 		else
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index 5f23438..d69e50a 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -365,7 +365,9 @@ xfs_symlink(
 	int			n;
 	xfs_buf_t		*bp;
 	prid_t			prid;
-	struct xfs_dquot	*udqp, *gdqp;
+	struct xfs_dquot	*udqp = NULL;
+	struct xfs_dquot	*gdqp = NULL;
+	struct xfs_dquot	*pdqp = NULL;
 	uint			resblks;
 
 	*ipp = NULL;
@@ -392,7 +394,7 @@ xfs_symlink(
 	 * Make sure that we have allocated dquot(s) on disk.
 	 */
 	error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
-			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
+		XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp);
 	if (error)
 		goto std_return;
 
@@ -433,7 +435,8 @@ xfs_symlink(
 	/*
 	 * Reserve disk quota : blocks and inode.
 	 */
-	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
+	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
+						pdqp, resblks, 1, 0);
 	if (error)
 		goto error_return;
 
@@ -471,7 +474,7 @@ xfs_symlink(
 	/*
 	 * Also attach the dquot(s) to it, if applicable.
 	 */
-	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
+	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
 
 	if (resblks)
 		resblks -= XFS_IALLOC_SPACE_RES(mp);
@@ -570,6 +573,7 @@ xfs_symlink(
 	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 	xfs_qm_dqrele(udqp);
 	xfs_qm_dqrele(gdqp);
+	xfs_qm_dqrele(pdqp);
 
 	*ipp = ip;
 	return 0;
@@ -583,6 +587,7 @@ xfs_symlink(
 	xfs_trans_cancel(tp, cancel_flags);
 	xfs_qm_dqrele(udqp);
 	xfs_qm_dqrele(gdqp);
+	xfs_qm_dqrele(pdqp);
 
 	if (unlock_dp_on_error)
 		xfs_iunlock(dp, XFS_ILOCK_EXCL);
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index 8cdbd62..2bbad13 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -103,8 +103,6 @@ xfs_trans_dup_dqinfo(
 		return;
 
 	xfs_trans_alloc_dqinfo(ntp);
-	oqa = otp->t_dqinfo->dqa_usrdquots;
-	nqa = ntp->t_dqinfo->dqa_usrdquots;
 
 	/*
 	 * Because the quota blk reservation is carried forward,
@@ -113,7 +111,10 @@ xfs_trans_dup_dqinfo(
 	if(otp->t_flags & XFS_TRANS_DQ_DIRTY)
 		ntp->t_flags |= XFS_TRANS_DQ_DIRTY;
 
-	for (j = 0; j < 2; j++) {
+	for (j = 0; j < XFS_QM_TRANS_DQTYPES; j++) {
+		oqa = otp->t_dqinfo->dqs[j];
+		nqa = ntp->t_dqinfo->dqs[j];
+
 		for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
 			if (oqa[i].qt_dquot == NULL)
 				break;
@@ -138,8 +139,6 @@ xfs_trans_dup_dqinfo(
 			oq->qt_ino_res = oq->qt_ino_res_used;
 
 		}
-		oqa = otp->t_dqinfo->dqa_grpdquots;
-		nqa = ntp->t_dqinfo->dqa_grpdquots;
 	}
 }
 
@@ -166,8 +165,10 @@ xfs_trans_mod_dquot_byino(
 
 	if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot)
 		(void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta);
-	if (XFS_IS_OQUOTA_ON(mp) && ip->i_gdquot)
+	if (XFS_IS_GQUOTA_ON(mp) && ip->i_gdquot)
 		(void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta);
+	if (XFS_IS_PQUOTA_ON(mp) && ip->i_pdquot)
+		(void) xfs_trans_mod_dquot(tp, ip->i_pdquot, field, delta);
 }
 
 STATIC xfs_dqtrx_t *
@@ -178,15 +179,20 @@ xfs_trans_get_dqtrx(
 	int		i;
 	xfs_dqtrx_t	*qa;
 
-	qa = XFS_QM_ISUDQ(dqp) ?
-		tp->t_dqinfo->dqa_usrdquots : tp->t_dqinfo->dqa_grpdquots;
+	if (XFS_QM_ISUDQ(dqp))
+		qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_USR];
+	else if (XFS_QM_ISGDQ(dqp))
+		qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_GRP];
+	else if (XFS_QM_ISPDQ(dqp))
+		qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_PROJ];
+	else
+		return NULL;
 
 	for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
 		if (qa[i].qt_dquot == NULL ||
 		    qa[i].qt_dquot == dqp)
 			return &qa[i];
 	}
-
 	return NULL;
 }
 
@@ -339,12 +345,10 @@ xfs_trans_apply_dquot_deltas(
 		return;
 
 	ASSERT(tp->t_dqinfo);
-	qa = tp->t_dqinfo->dqa_usrdquots;
-	for (j = 0; j < 2; j++) {
-		if (qa[0].qt_dquot == NULL) {
-			qa = tp->t_dqinfo->dqa_grpdquots;
+	for (j = 0; j < XFS_QM_TRANS_DQTYPES; j++) {
+		qa = tp->t_dqinfo->dqs[j];
+		if (qa[0].qt_dquot == NULL)
 			continue;
-		}
 
 		/*
 		 * Lock all of the dquots and join them to the transaction.
@@ -495,10 +499,6 @@ xfs_trans_apply_dquot_deltas(
 			ASSERT(dqp->q_res_rtbcount >=
 				be64_to_cpu(dqp->q_core.d_rtbcount));
 		}
-		/*
-		 * Do the group quotas next
-		 */
-		qa = tp->t_dqinfo->dqa_grpdquots;
 	}
 }
 
@@ -521,9 +521,10 @@ xfs_trans_unreserve_and_mod_dquots(
 	if (!tp->t_dqinfo || !(tp->t_flags & XFS_TRANS_DQ_DIRTY))
 		return;
 
-	qa = tp->t_dqinfo->dqa_usrdquots;
 
-	for (j = 0; j < 2; j++) {
+	for (j = 0; j < XFS_QM_TRANS_DQTYPES; j++) {
+		qa = tp->t_dqinfo->dqs[j];
+
 		for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
 			qtrx = &qa[i];
 			/*
@@ -565,7 +566,6 @@ xfs_trans_unreserve_and_mod_dquots(
 				xfs_dqunlock(dqp);
 
 		}
-		qa = tp->t_dqinfo->dqa_grpdquots;
 	}
 }
 
@@ -736,8 +736,8 @@ error_return:
 
 /*
  * 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/prj quotas is important, because this follows a both-or-nothing
+ * The fact that this does the reservation against user, group and
+ * project quotas is important, because this follows a all-or-nothing
  * approach.
  *
  * flags = XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
@@ -748,15 +748,16 @@ error_return:
  */
 int
 xfs_trans_reserve_quota_bydquots(
-	xfs_trans_t	*tp,
-	xfs_mount_t	*mp,
-	xfs_dquot_t	*udqp,
-	xfs_dquot_t	*gdqp,
-	long		nblks,
-	long		ninos,
-	uint		flags)
+	struct xfs_trans	*tp,
+	struct xfs_mount	*mp,
+	struct xfs_dquot	*udqp,
+	struct xfs_dquot	*gdqp,
+	struct xfs_dquot	*pdqp,
+	long			nblks,
+	long			ninos,
+	uint			flags)
 {
-	int		resvd = 0, error;
+	int	error;
 
 	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
 		return 0;
@@ -771,28 +772,34 @@ xfs_trans_reserve_quota_bydquots(
 					(flags & ~XFS_QMOPT_ENOSPC));
 		if (error)
 			return error;
-		resvd = 1;
 	}
 
 	if (gdqp) {
 		error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags);
-		if (error) {
-			/*
-			 * can't do it, so backout previous reservation
-			 */
-			if (resvd) {
-				flags |= XFS_QMOPT_FORCE_RES;
-				xfs_trans_dqresv(tp, mp, udqp,
-						 -nblks, -ninos, flags);
-			}
-			return error;
-		}
+		if (error)
+			goto unwind_usr;
+	}
+
+	if (pdqp) {
+		error = xfs_trans_dqresv(tp, mp, pdqp, nblks, ninos, flags);
+		if (error)
+			goto unwind_grp;
 	}
 
 	/*
 	 * Didn't change anything critical, so, no need to log
 	 */
 	return 0;
+
+unwind_grp:
+	flags |= XFS_QMOPT_FORCE_RES;
+	if (gdqp)
+		xfs_trans_dqresv(tp, mp, gdqp, -nblks, -ninos, flags);
+unwind_usr:
+	flags |= XFS_QMOPT_FORCE_RES;
+	if (udqp)
+		xfs_trans_dqresv(tp, mp, udqp, -nblks, -ninos, flags);
+	return error;
 }
 
 
@@ -830,6 +837,7 @@ xfs_trans_reserve_quota_nblks(
 	 */
 	return xfs_trans_reserve_quota_bydquots(tp, mp,
 						ip->i_udquot, ip->i_gdquot,
+						ip->i_pdquot,
 						nblks, ninos, flags);
 }
 
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 1501f4f..cd0d133 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -498,6 +498,7 @@ xfs_create(
 	prid_t			prid;
 	struct xfs_dquot	*udqp = NULL;
 	struct xfs_dquot	*gdqp = NULL;
+	struct xfs_dquot	*pdqp = NULL;
 	uint			resblks;
 	uint			log_res;
 	uint			log_count;
@@ -516,7 +517,7 @@ xfs_create(
 	 * Make sure that we have allocated dquot(s) on disk.
 	 */
 	error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
-			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
+		XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp);
 	if (error)
 		return error;
 
@@ -568,7 +569,8 @@ xfs_create(
 	/*
 	 * Reserve disk quota and the inode.
 	 */
-	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
+	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
+						pdqp, resblks, 1, 0);
 	if (error)
 		goto out_trans_cancel;
 
@@ -632,7 +634,7 @@ xfs_create(
 	 * These ids of the inode couldn't have changed since the new
 	 * inode has been locked ever since it was created.
 	 */
-	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
+	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
 
 	error = xfs_bmap_finish(&tp, &free_list, &committed);
 	if (error)
@@ -644,6 +646,7 @@ xfs_create(
 
 	xfs_qm_dqrele(udqp);
 	xfs_qm_dqrele(gdqp);
+	xfs_qm_dqrele(pdqp);
 
 	*ipp = ip;
 	return 0;
@@ -665,6 +668,7 @@ xfs_create(
 
 	xfs_qm_dqrele(udqp);
 	xfs_qm_dqrele(gdqp);
+	xfs_qm_dqrele(pdqp);
 
 	if (unlock_dp_on_error)
 		xfs_iunlock(dp, XFS_ILOCK_EXCL);
@@ -1577,7 +1581,7 @@ xfs_free_file_space(
 		}
 		xfs_ilock(ip, XFS_ILOCK_EXCL);
 		error = xfs_trans_reserve_quota(tp, mp,
-				ip->i_udquot, ip->i_gdquot,
+				ip->i_udquot, ip->i_gdquot, ip->i_pdquot,
 				resblks, 0, XFS_QMOPT_RES_REGBLKS);
 		if (error)
 			goto error1;
-- 
1.7.1

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v8 3/5] xfs: Start using pquotaino from the superblock
  2013-05-10 21:21 [PATCH v8 0/5] xfs: Allow pquota and gquota to be used together Chandra Seetharaman
  2013-05-10 21:21 ` [PATCH v8 1/5] xfs: Remove incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD Chandra Seetharaman
  2013-05-10 21:21 ` [PATCH v8 2/5] xfs: Add pquota fields where gquota is used Chandra Seetharaman
@ 2013-05-10 21:21 ` Chandra Seetharaman
  2013-05-13  4:24   ` Jeff Liu
  2013-05-17  4:46   ` Dave Chinner
  2013-05-10 21:21 ` [PATCH v8 4/5] xfs: Add proper versioning support to fs_quota_stat Chandra Seetharaman
  2013-05-10 21:21 ` [PATCH v8 5/5] xfs: Use new qs_pquota field in fs_quota_stat for Q_XGETQSTAT Chandra Seetharaman
  4 siblings, 2 replies; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-10 21:21 UTC (permalink / raw)
  To: xfs; +Cc: Chandra Seetharaman

Define a macro to check if the superblock has pquotino.

Keep backward compatibilty by alowing mount of older superblock
with no separate pquota inode.
---
 fs/xfs/xfs_itable.c            |    3 +-
 fs/xfs/xfs_mount.c             |  117 ++++++++++++++++++++++++++++++----------
 fs/xfs/xfs_qm.c                |   29 +++++-----
 fs/xfs/xfs_qm_syscalls.c       |   32 +++++++++---
 fs/xfs/xfs_quota.h             |    8 ---
 fs/xfs/xfs_sb.h                |    5 ++
 fs/xfs/xfs_super.c             |   14 +++--
 fs/xfs/xfs_trans_dquot.c       |    4 +-
 include/uapi/linux/dqblk_xfs.h |    1 +
 9 files changed, 148 insertions(+), 65 deletions(-)

diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 2ea7d40..d80d58c 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -43,7 +43,8 @@ xfs_internal_inum(
 {
 	return (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
 		(xfs_sb_version_hasquota(&mp->m_sb) &&
-		 (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino)));
+		 (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino ||
+		  ino == mp->m_sb.sb_pquotino)));
 }
 
 /*
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 1b79906..233f88e 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -601,21 +601,6 @@ xfs_sb_from_disk(
 	to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
 	to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
 	to->sb_qflags = be16_to_cpu(from->sb_qflags);
-	if ((to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) &&
-			(to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
-				XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))) {
-		xfs_notice(NULL, "Super block has XFS_OQUOTA bits along with "
-		    "XFS_PQUOTA and/or XFS_GQUOTA bits. Quota check forced.\n");
-		force_quota_check = true;
-	}
-	if (to->sb_qflags & XFS_OQUOTA_ENFD)
-		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
-					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
-	if (to->sb_qflags & XFS_OQUOTA_CHKD)
-		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
-					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
-	to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
-
 	to->sb_flags = from->sb_flags;
 	to->sb_shared_vn = from->sb_shared_vn;
 	to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
@@ -636,6 +621,44 @@ xfs_sb_from_disk(
 	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
 	to->sb_lsn = be64_to_cpu(from->sb_lsn);
 
+	if (xfs_sb_version_has_pquota(to)) {
+		if (to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) {
+			xfs_notice(NULL, "Super block has XFS_OQUOTA bits "
+			"with version PQUOTINO. Quota check forced.\n");
+			to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
+			force_quota_check = true;
+		}
+		to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
+	} else {
+		if (to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
+					XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) {
+			xfs_notice(NULL, "Super block has XFS_[G|P]UOTA "
+				"bits in version older than PQUOTINO. "
+				"Quota check forced.\n");
+
+			to->sb_qflags &= ~(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
+					XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD);
+			force_quota_check = true;
+		}
+
+		/*
+		 * On disk superblock qflags uses XFS_OQUOTA.* to support
+		 * either PQUOTA or GQUOTA. But, in memory qflags uses
+		 * XFS_PQUOTA.* or XFS_GQUOTA.* depending on which quota
+		 * is used.
+		 * Following block translates XFS_OQUOTA.* to either
+		 * GQUOTA or PQUOTA.
+		 */
+		if (to->sb_qflags & XFS_OQUOTA_ENFD)
+			to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
+					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
+		if (to->sb_qflags & XFS_OQUOTA_CHKD)
+			to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
+					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
+		to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
+
+	}
+
 	if (force_quota_check)
 		to->sb_qflags &= ~(XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD);
 }
@@ -657,27 +680,51 @@ xfs_sb_to_disk(
 	int		first;
 	int		size;
 	__uint16_t	qflags = from->sb_qflags;
+	xfs_ino_t	gquotino = from->sb_gquotino;
 
 	ASSERT(fields);
 	if (!fields)
 		return;
 
-	if (fields & XFS_SB_QFLAGS) {
+	if (!xfs_sb_version_has_pquota(from)) {
+		if (fields & XFS_SB_QFLAGS) {
+			/*
+			 * The in-core version of sb_qflags do not have
+			 * XFS_OQUOTA_* flags, whereas the on-disk version
+			 * does.  So, convert incore XFS_{PG}QUOTA_* flags
+			 * to on-disk XFS_OQUOTA_* flags.
+			 */
+			qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
+					XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
+
+			if (from->sb_qflags &
+					(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
+				qflags |= XFS_OQUOTA_ENFD;
+			if (from->sb_qflags &
+					(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
+				qflags |= XFS_OQUOTA_CHKD;
+		}
+
 		/*
-		 * The in-core version of sb_qflags do not have
-		 * XFS_OQUOTA_* flags, whereas the on-disk version
-		 * does.  So, convert incore XFS_{PG}QUOTA_* flags 
-		 * to on-disk XFS_OQUOTA_* flags.
+		 * On-disk version earlier than pquota doesn't have
+		 * sb_pquotino. so, we need to copy the value to gquotino.
 		 */
-		qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
-				XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
+		if (fields & XFS_SB_PQUOTINO) {
+			fields &= (__int64_t)~XFS_SB_PQUOTINO;
+			fields |= (__int64_t)XFS_SB_GQUOTINO;
+			gquotino = from->sb_pquotino;
+		}
 
-		if (from->sb_qflags &
-				(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
-			qflags |= XFS_OQUOTA_ENFD;
-		if (from->sb_qflags &
-				(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
-			qflags |= XFS_OQUOTA_CHKD;
+		/* If any quota inodes are written, write all quota inodes */
+		if (fields & (XFS_SB_UQUOTINO|XFS_SB_GQUOTINO))
+			fields |= (XFS_SB_UQUOTINO|XFS_SB_GQUOTINO);
+
+	} else {
+		/* If any quota inodes are written, write all quota inodes */
+		if (fields & (XFS_SB_UQUOTINO | XFS_SB_GQUOTINO
+							| XFS_SB_PQUOTINO))
+			fields |= (XFS_SB_UQUOTINO | XFS_SB_GQUOTINO
+							| XFS_SB_PQUOTINO);
 	}
 
 	while (fields) {
@@ -691,6 +738,8 @@ xfs_sb_to_disk(
 			memcpy(to_ptr + first, from_ptr + first, size);
 		} else if (f == XFS_SBS_QFLAGS) {
 			*(__be16 *)(to_ptr + first) = cpu_to_be16(qflags);
+		} else if (f == XFS_SBS_GQUOTINO) {
+			*(__be64 *)(to_ptr + first) = cpu_to_be64(gquotino);
 		} else {
 			switch (size) {
 			case 2:
@@ -872,6 +921,18 @@ reread:
 	 */
 	xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
 
+	if (!xfs_sb_version_has_pquota(&mp->m_sb) && XFS_IS_PQUOTA_ON(mp)) {
+		/*
+		 * On disk superblock only has sb_gquotino, and in memory
+		 * superblock has both sb_gquotino and sb_pquotino. But,
+		 * only one them is supported at any point of time.
+		 * So, if PQUOTA is set in disk superblock, copy over
+		 * sb_gquotino to sb_pquotino.
+		 */
+		mp->m_sb.sb_pquotino = mp->m_sb.sb_gquotino;
+		mp->m_sb.sb_gquotino = NULLFSINO;
+	}
+
 	/*
 	 * We must be able to do sector-sized and sector-aligned IO.
 	 */
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 97912cb..41ccc3c 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -516,7 +516,8 @@ xfs_qm_need_dqattach(
 	if (!XFS_NOT_DQATTACHED(mp, ip))
 		return false;
 	if (ip->i_ino == mp->m_sb.sb_uquotino ||
-	    ip->i_ino == mp->m_sb.sb_gquotino)
+	    ip->i_ino == mp->m_sb.sb_gquotino ||
+	    ip->i_ino == mp->m_sb.sb_pquotino)
 		return false;
 	return true;
 }
@@ -651,6 +652,7 @@ xfs_qm_dqdetach(
 
 	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino);
 	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino);
+	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_pquotino);
 	if (ip->i_udquot) {
 		xfs_qm_dqrele(ip->i_udquot);
 		ip->i_udquot = NULL;
@@ -858,22 +860,21 @@ xfs_qm_qino_alloc(
 	spin_lock(&mp->m_sb_lock);
 	if (flags & XFS_QMOPT_SBVERSION) {
 		ASSERT(!xfs_sb_version_hasquota(&mp->m_sb));
-		ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-				   XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) ==
-		       (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-			XFS_SB_GQUOTINO | XFS_SB_QFLAGS));
 
 		xfs_sb_version_addquota(&mp->m_sb);
 		mp->m_sb.sb_uquotino = NULLFSINO;
 		mp->m_sb.sb_gquotino = NULLFSINO;
+		mp->m_sb.sb_pquotino = NULLFSINO;
 
 		/* qflags will get updated _after_ quotacheck */
 		mp->m_sb.sb_qflags = 0;
 	}
 	if (flags & XFS_QMOPT_UQUOTA)
 		mp->m_sb.sb_uquotino = (*ip)->i_ino;
-	else
+	else if (flags & XFS_QMOPT_GQUOTA)
 		mp->m_sb.sb_gquotino = (*ip)->i_ino;
+	else
+		mp->m_sb.sb_pquotino = (*ip)->i_ino;
 	spin_unlock(&mp->m_sb_lock);
 	xfs_mod_sb(tp, sbfields);
 
@@ -1185,7 +1186,9 @@ xfs_qm_dqusage_adjust(
 	 * rootino must have its resources accounted for, not so with the quota
 	 * inodes.
 	 */
-	if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
+	if (ino == mp->m_sb.sb_uquotino ||
+	    ino == mp->m_sb.sb_gquotino ||
+	    ino == mp->m_sb.sb_pquotino) {
 		*res = BULKSTAT_RV_NOTHING;
 		return XFS_ERROR(EINVAL);
 	}
@@ -1466,19 +1469,17 @@ xfs_qm_init_quotainos(
 			if (error)
 				goto error_rele;
 		}
-		/* Use sb_gquotino for now */
 		if (XFS_IS_PQUOTA_ON(mp) &&
-		    mp->m_sb.sb_gquotino != NULLFSINO) {
-			ASSERT(mp->m_sb.sb_gquotino > 0);
-			error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+		    mp->m_sb.sb_pquotino != NULLFSINO) {
+			ASSERT(mp->m_sb.sb_pquotino > 0);
+			error = xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
 					     0, 0, &pip);
 			if (error)
 				goto error_rele;
 		}
 	} else {
 		flags |= XFS_QMOPT_SBVERSION;
-		sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-			    XFS_SB_GQUOTINO | XFS_SB_QFLAGS);
+		sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_QFLAGS);
 	}
 
 	/*
@@ -1505,7 +1506,7 @@ xfs_qm_init_quotainos(
 	}
 	if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
 		error = xfs_qm_qino_alloc(mp, &pip,
-					     sbflags | XFS_SB_GQUOTINO,
+					     sbflags | XFS_SB_PQUOTINO,
 					     flags | XFS_QMOPT_PQUOTA);
 		if (error)
 			goto error_rele;
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 9bec772..65c0a7d 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -201,8 +201,7 @@ xfs_qm_scall_quotaoff(
 	/*
 	 * If quotas is completely disabled, close shop.
 	 */
-	if (((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET1) ||
-	    ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET2)) {
+	if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) {
 		mutex_unlock(&q->qi_quotaofflock);
 		xfs_qm_destroy_quotainfo(mp);
 		return (0);
@@ -297,8 +296,10 @@ xfs_qm_scall_trunc_qfiles(
 
 	if (flags & XFS_DQ_USER)
 		error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_uquotino);
-	if (flags & (XFS_DQ_GROUP|XFS_DQ_PROJ))
+	if (flags & XFS_DQ_GROUP)
 		error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_gquotino);
+	if (flags & XFS_DQ_PROJ)
+		error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_pquotino);
 
 	return error ? error : error2;
 }
@@ -412,17 +413,20 @@ xfs_qm_scall_getqstat(
 	struct fs_quota_stat	*out)
 {
 	struct xfs_quotainfo	*q = mp->m_quotainfo;
-	struct xfs_inode	*uip, *gip;
-	bool                    tempuqip, tempgqip;
+	struct xfs_inode	*uip = NULL;
+	struct xfs_inode	*gip = NULL;
+	struct xfs_inode	*pip = NULL;
+	bool                    tempuqip = false;
+	bool                    tempgqip = false;
+	bool                    temppqip = false;
 
-	uip = gip = NULL;
-	tempuqip = tempgqip = false;
 	memset(out, 0, sizeof(fs_quota_stat_t));
 
 	out->qs_version = FS_QSTAT_VERSION;
 	if (!xfs_sb_version_hasquota(&mp->m_sb)) {
 		out->qs_uquota.qfs_ino = NULLFSINO;
 		out->qs_gquota.qfs_ino = NULLFSINO;
+		out->qs_pquota.qfs_ino = NULLFSINO;
 		return (0);
 	}
 	out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
@@ -431,10 +435,13 @@ xfs_qm_scall_getqstat(
 	out->qs_pad = 0;
 	out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
 	out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
+	if (&out->qs_gquota != &out->qs_pquota)
+		out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino;
 
 	if (q) {
 		uip = q->qi_uquotaip;
 		gip = q->qi_gquotaip;
+		pip = q->qi_pquotaip;
 	}
 	if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
 		if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
@@ -446,6 +453,11 @@ xfs_qm_scall_getqstat(
 					0, 0, &gip) == 0)
 			tempgqip = true;
 	}
+	if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) {
+		if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
+					0, 0, &pip) == 0)
+			temppqip = true;
+	}
 	if (uip) {
 		out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
 		out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
@@ -458,6 +470,12 @@ xfs_qm_scall_getqstat(
 		if (tempgqip)
 			IRELE(gip);
 	}
+	if (pip) {
+		out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks;
+		out->qs_pquota.qfs_nextents = pip->i_d.di_nextents;
+		if (temppqip)
+			IRELE(pip);
+	}
 	if (q) {
 		out->qs_incoredqs = q->qi_dquots;
 		out->qs_btimelimit = q->qi_btimelimit;
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index fe46c0c..be51581 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -285,14 +285,6 @@ typedef struct xfs_qoff_logformat {
 	 (XFS_IS_PQUOTA_ON(mp) && \
 		(mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD) == 0))
 
-#define XFS_MOUNT_QUOTA_SET1	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
-				 XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
-				 XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD)
-
-#define XFS_MOUNT_QUOTA_SET2	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
-				 XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
-				 XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD)
-
 #define XFS_MOUNT_QUOTA_ALL	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
 				 XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
 				 XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD|\
diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h
index 2de58a8..3745b73 100644
--- a/fs/xfs/xfs_sb.h
+++ b/fs/xfs/xfs_sb.h
@@ -618,6 +618,11 @@ xfs_sb_has_incompat_log_feature(
 	return (sbp->sb_features_log_incompat & feature) != 0;
 }
 
+static inline int xfs_sb_version_has_pquota(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
+}
+
 /*
  * end of superblock version macros
  */
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 5feac04..01019d9 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -420,12 +420,6 @@ xfs_parseargs(
 	}
 #endif
 
-	if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
-	    (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE))) {
-		xfs_warn(mp, "cannot mount with both project and group quota");
-		return EINVAL;
-	}
-
 	if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
 		xfs_warn(mp, "sunit and swidth must be specified together");
 		return EINVAL;
@@ -1388,6 +1382,14 @@ xfs_finish_flags(
 		return XFS_ERROR(EROFS);
 	}
 
+	if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
+	    (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE)) &&
+	    !xfs_sb_version_has_pquota(&mp->m_sb)) {
+		xfs_warn(mp, "Super block does not support "
+				 "project and group quota together");
+		return XFS_ERROR(EINVAL);
+	}
+
 	return 0;
 }
 
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index 2bbad13..fee905b 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -157,7 +157,8 @@ xfs_trans_mod_dquot_byino(
 	if (!XFS_IS_QUOTA_RUNNING(mp) ||
 	    !XFS_IS_QUOTA_ON(mp) ||
 	    ip->i_ino == mp->m_sb.sb_uquotino ||
-	    ip->i_ino == mp->m_sb.sb_gquotino)
+	    ip->i_ino == mp->m_sb.sb_gquotino ||
+	    ip->i_ino == mp->m_sb.sb_pquotino)
 		return;
 
 	if (tp->t_dqinfo == NULL)
@@ -825,6 +826,7 @@ xfs_trans_reserve_quota_nblks(
 
 	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_pquotino);
 
 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 	ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
diff --git a/include/uapi/linux/dqblk_xfs.h b/include/uapi/linux/dqblk_xfs.h
index 8655280..f17e3bb 100644
--- a/include/uapi/linux/dqblk_xfs.h
+++ b/include/uapi/linux/dqblk_xfs.h
@@ -155,6 +155,7 @@ typedef struct fs_quota_stat {
 	__s8		qs_pad;		/* unused */
 	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
 	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
+#define qs_pquota	qs_gquota
 	__u32		qs_incoredqs;	/* number of dquots incore */
 	__s32		qs_btimelimit;  /* limit for blks timer */	
 	__s32		qs_itimelimit;  /* limit for inodes timer */	
-- 
1.7.1

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v8 4/5] xfs: Add proper versioning support to fs_quota_stat
  2013-05-10 21:21 [PATCH v8 0/5] xfs: Allow pquota and gquota to be used together Chandra Seetharaman
                   ` (2 preceding siblings ...)
  2013-05-10 21:21 ` [PATCH v8 3/5] xfs: Start using pquotaino from the superblock Chandra Seetharaman
@ 2013-05-10 21:21 ` Chandra Seetharaman
  2013-05-13  4:29   ` Jeff Liu
  2013-05-17  5:10   ` Dave Chinner
  2013-05-10 21:21 ` [PATCH v8 5/5] xfs: Use new qs_pquota field in fs_quota_stat for Q_XGETQSTAT Chandra Seetharaman
  4 siblings, 2 replies; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-10 21:21 UTC (permalink / raw)
  To: xfs; +Cc: Chandra Seetharaman

Added appropriate pads and code for backward compatibility.

Copied over the old version as it is different from the newer padded
version.

New callers of the system call have to just set the version of the data
structure being passed, and kernel will fill as much data as requested.

Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
---
 fs/gfs2/quota.c                |    3 ---
 fs/quota/quota.c               |   40 ++++++++++++++++++++++++++++++++++++++--
 fs/xfs/xfs_qm_syscalls.c       |    4 ----
 include/uapi/linux/dqblk_xfs.h |   38 ++++++++++++++++++++++++++++++++++++--
 4 files changed, 74 insertions(+), 11 deletions(-)

diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index c7c840e..ca0dccd 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -1443,9 +1443,6 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
 {
 	struct gfs2_sbd *sdp = sb->s_fs_info;
 
-	memset(fqs, 0, sizeof(struct fs_quota_stat));
-	fqs->qs_version = FS_QSTAT_VERSION;
-
 	switch (sdp->sd_args.ar_quota) {
 	case GFS2_QUOTA_ON:
 		fqs->qs_flags |= (FS_QUOTA_UDQ_ENFD | FS_QUOTA_GDQ_ENFD);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index c7314f1..510464e 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -207,12 +207,48 @@ static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
 static int quota_getxstate(struct super_block *sb, void __user *addr)
 {
 	struct fs_quota_stat fqs;
-	int ret;
+	struct fs_quota_stat_v1 fqs_v1;
+	int ret, size;
+	void *cp = &fqs;
 
 	if (!sb->s_qcop->get_xstate)
 		return -ENOSYS;
+
+	memset(&fqs, 0, sizeof(struct fs_quota_stat));
+	if (copy_from_user(&fqs, addr, 1)) /* just get the version */
+		return -EFAULT;
+
+	switch (fqs.qs_version) {
+	case FS_QSTAT_VERSION_2:
+		size = FS_QSTAT_V2_SIZE;
+		break;
+	default:
+		fqs.qs_version = FS_QSTAT_VERSION;
+		/* fallthrough */
+	case FS_QSTAT_VERSION:
+		size = FS_QSTAT_V1_SIZE;
+		cp = &fqs_v1;
+	}
+
 	ret = sb->s_qcop->get_xstate(sb, &fqs);
-	if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
+	if (ret)
+		return ret;
+
+	if (fqs.qs_version == FS_QSTAT_VERSION) {
+		fqs_v1.qs_version = fqs.qs_version;
+		fqs_v1.qs_flags = fqs.qs_flags;
+		fqs_v1.qs_pad = 0;
+		fqs_v1.qs_uquota = fqs.qs_uquota;
+		fqs_v1.qs_gquota = fqs.qs_gquota;
+		fqs_v1.qs_incoredqs = fqs.qs_incoredqs;
+		fqs_v1.qs_btimelimit = fqs.qs_btimelimit;
+		fqs_v1.qs_itimelimit = fqs.qs_itimelimit;
+		fqs_v1.qs_rtbtimelimit = fqs.qs_rtbtimelimit;
+		fqs_v1.qs_bwarnlimit = fqs.qs_bwarnlimit;
+		fqs_v1.qs_iwarnlimit = fqs.qs_iwarnlimit;
+	}
+
+	if (copy_to_user(addr, &cp, size))
 		return -EFAULT;
 	return ret;
 }
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 65c0a7d..c27b0e4 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -420,9 +420,6 @@ xfs_qm_scall_getqstat(
 	bool                    tempgqip = false;
 	bool                    temppqip = false;
 
-	memset(out, 0, sizeof(fs_quota_stat_t));
-
-	out->qs_version = FS_QSTAT_VERSION;
 	if (!xfs_sb_version_hasquota(&mp->m_sb)) {
 		out->qs_uquota.qfs_ino = NULLFSINO;
 		out->qs_gquota.qfs_ino = NULLFSINO;
@@ -432,7 +429,6 @@ xfs_qm_scall_getqstat(
 	out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
 							(XFS_ALL_QUOTA_ACCT|
 							 XFS_ALL_QUOTA_ENFD));
-	out->qs_pad = 0;
 	out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
 	out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
 	if (&out->qs_gquota != &out->qs_pquota)
diff --git a/include/uapi/linux/dqblk_xfs.h b/include/uapi/linux/dqblk_xfs.h
index f17e3bb..d9629c1 100644
--- a/include/uapi/linux/dqblk_xfs.h
+++ b/include/uapi/linux/dqblk_xfs.h
@@ -18,6 +18,7 @@
 #define _LINUX_DQBLK_XFS_H
 
 #include <linux/types.h>
+#include <linux/stddef.h>
 
 /*
  * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM).
@@ -137,8 +138,12 @@ typedef struct fs_disk_quota {
  * Provides a centralized way to get meta information about the quota subsystem.
  * eg. space taken up for user and group quotas, number of dquots currently
  * incore.
+ * User space caller should set qs_version to the appropriate version
+ * of the fs_quota_stat data structure they are providing. Not providing
+ * a version will be treated as FS_QSTAT_VERSION.
  */
 #define FS_QSTAT_VERSION	1	/* fs_quota_stat.qs_version */
+#define FS_QSTAT_VERSION_2	2	/* new field qs_pquota */
 
 /*
  * Some basic information about 'quota files'.
@@ -149,19 +154,48 @@ typedef struct fs_qfilestat {
 	__u32		qfs_nextents;	/* number of extents */
 } fs_qfilestat_t;
 
+typedef struct fs_quota_stat_v1 {
+	__s8		qs_version;	/* version number for future changes */
+	__u16		qs_flags;	/* FS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
+	__u8		qs_pad;		/* unused */
+	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
+	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
+	__u32		qs_incoredqs;	/* number of dquots incore */
+	__s32		qs_btimelimit;  /* limit for blks timer */	
+	__s32		qs_itimelimit;  /* limit for inodes timer */	
+	__s32		qs_rtbtimelimit;/* limit for rt blks timer */	
+	__u16		qs_bwarnlimit;	/* limit for num warnings */
+	__u16		qs_iwarnlimit;	/* limit for num warnings */
+} fs_quota_stat_v1_t;
+
 typedef struct fs_quota_stat {
 	__s8		qs_version;	/* version number for future changes */
+	__u8		qs_pad1;	/* unused */
 	__u16		qs_flags;	/* FS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
-	__s8		qs_pad;		/* unused */
+	__u8		qs_pad2[4];	/* unused */
 	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
 	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
-#define qs_pquota	qs_gquota
 	__u32		qs_incoredqs;	/* number of dquots incore */
 	__s32		qs_btimelimit;  /* limit for blks timer */	
 	__s32		qs_itimelimit;  /* limit for inodes timer */	
 	__s32		qs_rtbtimelimit;/* limit for rt blks timer */	
 	__u16		qs_bwarnlimit;	/* limit for num warnings */
 	__u16		qs_iwarnlimit;	/* limit for num warnings */
+	__u8		qs_pad3[4];	/* unused */
+	fs_qfilestat_t	qs_pquota;	/* project quota storage information */
+	/* End of Data structure for FS_QSTAT_VERSION_2 */
 } fs_quota_stat_t;
 
+/*
+ * Since Version 1 did not have padding at appropriate places,
+ * a new data structure has been defined for the older version to
+ * provide backward compatibility.
+ * Future extentions of this data structure won't require new
+ * data structure definitions as the current one can be extended
+ * with the logic and padding in place now.
+ */
+#define FS_QSTAT_V1_SIZE	(sizeof(struct fs_quota_stat_v1))
+#define FS_QSTAT_V2_SIZE	(offsetof(struct fs_quota_stat, qs_pquota) + \
+					sizeof(fs_qfilestat_t))
+
 #endif	/* _LINUX_DQBLK_XFS_H */
-- 
1.7.1

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v8 5/5] xfs: Use new qs_pquota field in fs_quota_stat for Q_XGETQSTAT
  2013-05-10 21:21 [PATCH v8 0/5] xfs: Allow pquota and gquota to be used together Chandra Seetharaman
                   ` (3 preceding siblings ...)
  2013-05-10 21:21 ` [PATCH v8 4/5] xfs: Add proper versioning support to fs_quota_stat Chandra Seetharaman
@ 2013-05-10 21:21 ` Chandra Seetharaman
  2013-05-17  5:14   ` Dave Chinner
  4 siblings, 1 reply; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-10 21:21 UTC (permalink / raw)
  To: xfs; +Cc: Chandra Seetharaman

For the Q_XGETQSTAT quota command, if the new version of fs_quota_stat
data structure is used, fill the project quota information.

Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
---
 fs/xfs/xfs_qm_syscalls.c |   39 +++++++++++++++++++++++++--------------
 1 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index c27b0e4..7c5876b 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -420,20 +420,14 @@ xfs_qm_scall_getqstat(
 	bool                    tempgqip = false;
 	bool                    temppqip = false;
 
-	if (!xfs_sb_version_hasquota(&mp->m_sb)) {
-		out->qs_uquota.qfs_ino = NULLFSINO;
-		out->qs_gquota.qfs_ino = NULLFSINO;
-		out->qs_pquota.qfs_ino = NULLFSINO;
+	out->qs_uquota.qfs_ino = NULLFSINO;
+	out->qs_gquota.qfs_ino = NULLFSINO;
+	out->qs_pquota.qfs_ino = NULLFSINO;
+
+	if (!xfs_sb_version_hasquota(&mp->m_sb))
 		return (0);
-	}
 	out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
-							(XFS_ALL_QUOTA_ACCT|
-							 XFS_ALL_QUOTA_ENFD));
-	out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
-	out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
-	if (&out->qs_gquota != &out->qs_pquota)
-		out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino;
-
+				(XFS_ALL_QUOTA_ACCT| XFS_ALL_QUOTA_ENFD));
 	if (q) {
 		uip = q->qi_uquotaip;
 		gip = q->qi_gquotaip;
@@ -454,21 +448,38 @@ xfs_qm_scall_getqstat(
 					0, 0, &pip) == 0)
 			temppqip = true;
 	}
+
 	if (uip) {
+		out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
 		out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
 		out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
 		if (tempuqip)
 			IRELE(uip);
 	}
 	if (gip) {
+		out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
 		out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
 		out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
 		if (tempgqip)
 			IRELE(gip);
 	}
 	if (pip) {
-		out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks;
-		out->qs_pquota.qfs_nextents = pip->i_d.di_nextents;
+		if (out->qs_version >= FS_QSTAT_VERSION_2) {
+			out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino;
+			out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks;
+			out->qs_pquota.qfs_nextents = pip->i_d.di_nextents;
+		} else {
+			/*
+			 * In FS_QSTAT_VERSION version, there is no
+			 * qs_pquota, and there is no combined support
+			 * for gquota/pquota. qs_gquota is shared for
+			 * providing the pquota/gquota information to
+			 * the user space.
+			 */
+			out->qs_gquota.qfs_ino = mp->m_sb.sb_pquotino;
+			out->qs_gquota.qfs_nblks = pip->i_d.di_nblocks;
+			out->qs_gquota.qfs_nextents = pip->i_d.di_nextents;
+		}
 		if (temppqip)
 			IRELE(pip);
 	}
-- 
1.7.1

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 1/5] xfs: Remove incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD
  2013-05-10 21:21 ` [PATCH v8 1/5] xfs: Remove incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD Chandra Seetharaman
@ 2013-05-13  3:15   ` Jeff Liu
  2013-05-14 22:19     ` Chandra Seetharaman
  2013-05-17  2:55   ` Dave Chinner
  1 sibling, 1 reply; 29+ messages in thread
From: Jeff Liu @ 2013-05-13  3:15 UTC (permalink / raw)
  To: Chandra Seetharaman; +Cc: xfs

Hi Chandra,

On 05/11/2013 05:21 AM, Chandra Seetharaman wrote:
> Remove all incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD. Instead,
> start using XFS_GQUOTA_.* XFS_PQUOTA_.* counterparts for GQUOTA and
> PQUOTA respectively.
> 
> On-disk copy still uses XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD.
> 
> Read and write of the superblock does the conversion from *OQUOTA*
> to *[PG]QUOTA*.
> 
> Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
> Reviewed-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/xfs_mount.c       |   41 +++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/xfs_qm.c          |    9 ++++++---
>  fs/xfs/xfs_qm_syscalls.c |   39 +++++++++++++++++++++------------------
>  fs/xfs/xfs_quota.h       |   42 ++++++++++++++++++++++++++++--------------
>  fs/xfs/xfs_quotaops.c    |    6 ++++--
>  fs/xfs/xfs_super.c       |   16 ++++++++--------
>  fs/xfs/xfs_trans_dquot.c |    4 ++--
>  7 files changed, 110 insertions(+), 47 deletions(-)
> 
> diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> index f6bfbd7..1b79906 100644
> --- a/fs/xfs/xfs_mount.c
> +++ b/fs/xfs/xfs_mount.c
> @@ -564,6 +564,8 @@ xfs_sb_from_disk(
>  	struct xfs_sb	*to,
>  	xfs_dsb_t	*from)
>  {
> +	bool force_quota_check = false;
> +
>  	to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
>  	to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
>  	to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
> @@ -599,6 +601,21 @@ xfs_sb_from_disk(
>  	to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
>  	to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
>  	to->sb_qflags = be16_to_cpu(from->sb_qflags);
> +	if ((to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) &&
> +			(to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> +				XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))) {
> +		xfs_notice(NULL, "Super block has XFS_OQUOTA bits along with "
> +		    "XFS_PQUOTA and/or XFS_GQUOTA bits. Quota check forced.\n");
> +		force_quota_check = true;
> +	}
> +	if (to->sb_qflags & XFS_OQUOTA_ENFD)
> +		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> +					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
> +	if (to->sb_qflags & XFS_OQUOTA_CHKD)
> +		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> +					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
> +	to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> +
>  	to->sb_flags = from->sb_flags;
>  	to->sb_shared_vn = from->sb_shared_vn;
>  	to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
> @@ -618,6 +635,9 @@ xfs_sb_from_disk(
>  	to->sb_pad = 0;
>  	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
>  	to->sb_lsn = be64_to_cpu(from->sb_lsn);
> +
> +	if (force_quota_check)
> +		to->sb_qflags &= ~(XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD);
>  }
>  
>  /*
> @@ -636,11 +656,30 @@ xfs_sb_to_disk(
>  	xfs_sb_field_t	f;
>  	int		first;
>  	int		size;
> +	__uint16_t	qflags = from->sb_qflags;
>  
>  	ASSERT(fields);
>  	if (!fields)
>  		return;
>  
> +	if (fields & XFS_SB_QFLAGS) {
> +		/*
> +		 * The in-core version of sb_qflags do not have
> +		 * XFS_OQUOTA_* flags, whereas the on-disk version
> +		 * does.  So, convert incore XFS_{PG}QUOTA_* flags  
A minor issue, above line end up with trailing whitespace.

Thanks,
-Jeff
> +		 * to on-disk XFS_OQUOTA_* flags.
> +		 */
> +		qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
> +				XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
> +
> +		if (from->sb_qflags &
> +				(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
> +			qflags |= XFS_OQUOTA_ENFD;
> +		if (from->sb_qflags &
> +				(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
> +			qflags |= XFS_OQUOTA_CHKD;
> +	}
> +
>  	while (fields) {
>  		f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
>  		first = xfs_sb_info[f].offset;
> @@ -650,6 +689,8 @@ xfs_sb_to_disk(
>  
>  		if (size == 1 || xfs_sb_info[f].type == 1) {
>  			memcpy(to_ptr + first, from_ptr + first, size);
> +		} else if (f == XFS_SBS_QFLAGS) {
> +			*(__be16 *)(to_ptr + first) = cpu_to_be16(qflags);
>  		} else {
>  			switch (size) {
>  			case 2:
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index f41702b..fe4c743 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -298,8 +298,10 @@ xfs_qm_mount_quotas(
>  	 */
>  	if (!XFS_IS_UQUOTA_ON(mp))
>  		mp->m_qflags &= ~XFS_UQUOTA_CHKD;
> -	if (!(XFS_IS_GQUOTA_ON(mp) || XFS_IS_PQUOTA_ON(mp)))
> -		mp->m_qflags &= ~XFS_OQUOTA_CHKD;
> +	if (!XFS_IS_GQUOTA_ON(mp))
> +		mp->m_qflags &= ~XFS_GQUOTA_CHKD;
> +	if (!XFS_IS_PQUOTA_ON(mp))
> +		mp->m_qflags &= ~XFS_PQUOTA_CHKD;
>  
>   write_changes:
>  	/*
> @@ -1280,7 +1282,8 @@ xfs_qm_quotacheck(
>  					 &buffer_list);
>  		if (error)
>  			goto error_return;
> -		flags |= XFS_OQUOTA_CHKD;
> +		flags |= XFS_IS_GQUOTA_ON(mp) ?
> +					XFS_GQUOTA_CHKD : XFS_PQUOTA_CHKD;
>  	}
>  
>  	do {
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index c41190c..f005f1d 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -117,11 +117,11 @@ xfs_qm_scall_quotaoff(
>  	}
>  	if (flags & XFS_GQUOTA_ACCT) {
>  		dqtype |= XFS_QMOPT_GQUOTA;
> -		flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
> +		flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
>  		inactivate_flags |= XFS_GQUOTA_ACTIVE;
>  	} else if (flags & XFS_PQUOTA_ACCT) {
>  		dqtype |= XFS_QMOPT_PQUOTA;
> -		flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
> +		flags |= (XFS_PQUOTA_CHKD | XFS_PQUOTA_ENFD);
>  		inactivate_flags |= XFS_PQUOTA_ACTIVE;
>  	}
>  
> @@ -335,14 +335,14 @@ xfs_qm_scall_quotaon(
>  	 * quota acct on ondisk without m_qflags' knowing.
>  	 */
>  	if (((flags & XFS_UQUOTA_ACCT) == 0 &&
> -	    (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
> -	    (flags & XFS_UQUOTA_ENFD))
> -	    ||
> +	     (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
> +	     (flags & XFS_UQUOTA_ENFD)) ||
>  	    ((flags & XFS_PQUOTA_ACCT) == 0 &&
> -	    (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
> -	    (flags & XFS_GQUOTA_ACCT) == 0 &&
> -	    (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
> -	    (flags & XFS_OQUOTA_ENFD))) {
> +	     (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
> +	     (flags & XFS_PQUOTA_ENFD)) ||
> +	    ((flags & XFS_GQUOTA_ACCT) == 0 &&
> +	     (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
> +	     (flags & XFS_GQUOTA_ENFD))) {
>  		xfs_debug(mp,
>  			"%s: Can't enforce without acct, flags=%x sbflags=%x\n",
>  			__func__, flags, mp->m_sb.sb_qflags);
> @@ -770,9 +770,12 @@ xfs_qm_scall_getquota(
>  	 * gets turned off. No need to confuse the user level code,
>  	 * so return zeroes in that case.
>  	 */
> -	if ((!XFS_IS_UQUOTA_ENFORCED(mp) && dqp->q_core.d_flags == XFS_DQ_USER) ||
> -	    (!XFS_IS_OQUOTA_ENFORCED(mp) &&
> -			(dqp->q_core.d_flags & (XFS_DQ_PROJ | XFS_DQ_GROUP)))) {
> +	if ((!XFS_IS_UQUOTA_ENFORCED(mp) &&
> +	     dqp->q_core.d_flags == XFS_DQ_USER) ||
> +	    (!XFS_IS_PQUOTA_ENFORCED(mp) &&
> +	     dqp->q_core.d_flags == XFS_DQ_PROJ) ||
> +	    (!XFS_IS_GQUOTA_ENFORCED(mp) &&
> +	     dqp->q_core.d_flags == XFS_DQ_GROUP)) {
>  		dst->d_btimer = 0;
>  		dst->d_itimer = 0;
>  		dst->d_rtbtimer = 0;
> @@ -780,8 +783,8 @@ xfs_qm_scall_getquota(
>  
>  #ifdef DEBUG
>  	if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == FS_USER_QUOTA) ||
> -	     (XFS_IS_OQUOTA_ENFORCED(mp) &&
> -			(dst->d_flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)))) &&
> +	     (XFS_IS_PQUOTA_ENFORCED(mp) && dst->d_flags == FS_PROJ_QUOTA) ||
> +	     (XFS_IS_GQUOTA_ENFORCED(mp) && dst->d_flags == FS_GROUP_QUOTA)) &&
>  	    dst->d_id != 0) {
>  		if ((dst->d_bcount > dst->d_blk_softlimit) &&
>  		    (dst->d_blk_softlimit > 0)) {
> @@ -833,10 +836,10 @@ xfs_qm_export_flags(
>  		uflags |= FS_QUOTA_GDQ_ACCT;
>  	if (flags & XFS_UQUOTA_ENFD)
>  		uflags |= FS_QUOTA_UDQ_ENFD;
> -	if (flags & (XFS_OQUOTA_ENFD)) {
> -		uflags |= (flags & XFS_GQUOTA_ACCT) ?
> -			FS_QUOTA_GDQ_ENFD : FS_QUOTA_PDQ_ENFD;
> -	}
> +	if (flags & XFS_PQUOTA_ENFD)
> +		uflags |= FS_QUOTA_PDQ_ENFD;
> +	if (flags & XFS_GQUOTA_ENFD)
> +		uflags |= FS_QUOTA_GDQ_ENFD;
>  	return (uflags);
>  }
>  
> diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
> index c61e31c..ccff1a6 100644
> --- a/fs/xfs/xfs_quota.h
> +++ b/fs/xfs/xfs_quota.h
> @@ -159,28 +159,43 @@ typedef struct xfs_qoff_logformat {
>  #define XFS_GQUOTA_ACCT	0x0040  /* group quota accounting ON */
>  
>  /*
> + * Start differentiating group quota and project quota in-core
> + * using distinct flags, instead of using the combined OQUOTA flags.
> + *
> + * Conversion to and from the combined OQUOTA flag (if necessary)
> + * is done only in xfs_sb_{to,from}_disk()
> + */
> +#define XFS_GQUOTA_ENFD	0x0080  /* group quota limits enforced */
> +#define XFS_GQUOTA_CHKD	0x0100  /* quotacheck run on group quotas */
> +#define XFS_PQUOTA_ENFD	0x0200  /* project quota limits enforced */
> +#define XFS_PQUOTA_CHKD	0x0400  /* quotacheck run on project quotas */
> +
> +/*
>   * Quota Accounting/Enforcement flags
>   */
>  #define XFS_ALL_QUOTA_ACCT	\
>  		(XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT)
> -#define XFS_ALL_QUOTA_ENFD	(XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD)
> -#define XFS_ALL_QUOTA_CHKD	(XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD)
> +#define XFS_ALL_QUOTA_ENFD	\
> +		(XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD | XFS_PQUOTA_ENFD)
> +#define XFS_ALL_QUOTA_CHKD	\
> +		(XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD)
>  
>  #define XFS_IS_QUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
>  #define XFS_IS_UQUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_UQUOTA_ACCT)
>  #define XFS_IS_PQUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_PQUOTA_ACCT)
>  #define XFS_IS_GQUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_GQUOTA_ACCT)
>  #define XFS_IS_UQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_UQUOTA_ENFD)
> -#define XFS_IS_OQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_OQUOTA_ENFD)
> +#define XFS_IS_PQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_PQUOTA_ENFD)
> +#define XFS_IS_GQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_GQUOTA_ENFD)
>  
>  /*
>   * Incore only flags for quotaoff - these bits get cleared when quota(s)
>   * are in the process of getting turned off. These flags are in m_qflags but
>   * never in sb_qflags.
>   */
> -#define XFS_UQUOTA_ACTIVE	0x0100  /* uquotas are being turned off */
> -#define XFS_PQUOTA_ACTIVE	0x0200  /* pquotas are being turned off */
> -#define XFS_GQUOTA_ACTIVE	0x0400  /* gquotas are being turned off */
> +#define XFS_UQUOTA_ACTIVE	0x1000  /* uquotas are being turned off */
> +#define XFS_PQUOTA_ACTIVE	0x2000  /* pquotas are being turned off */
> +#define XFS_GQUOTA_ACTIVE	0x4000  /* gquotas are being turned off */
>  #define XFS_ALL_QUOTA_ACTIVE	\
>  	(XFS_UQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE)
>  
> @@ -266,24 +281,23 @@ typedef struct xfs_qoff_logformat {
>  	((XFS_IS_UQUOTA_ON(mp) && \
>  		(mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD) == 0) || \
>  	 (XFS_IS_GQUOTA_ON(mp) && \
> -		((mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD) == 0 || \
> -		 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT))) || \
> +		(mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD) == 0) || \
>  	 (XFS_IS_PQUOTA_ON(mp) && \
> -		((mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD) == 0 || \
> -		 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT))))
> +		(mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD) == 0))
>  
>  #define XFS_MOUNT_QUOTA_SET1	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
>  				 XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
> -				 XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD)
> +				 XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD)
>  
>  #define XFS_MOUNT_QUOTA_SET2	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
>  				 XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
> -				 XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD)
> +				 XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD)
>  
>  #define XFS_MOUNT_QUOTA_ALL	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
>  				 XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
> -				 XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD|\
> -				 XFS_GQUOTA_ACCT)
> +				 XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD|\
> +				 XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD|\
> +				 XFS_GQUOTA_CHKD)
>  
>  
>  /*
> diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
> index 71926d6..056d62e 100644
> --- a/fs/xfs/xfs_quotaops.c
> +++ b/fs/xfs/xfs_quotaops.c
> @@ -75,8 +75,10 @@ xfs_fs_set_xstate(
>  		flags |= XFS_GQUOTA_ACCT;
>  	if (uflags & FS_QUOTA_UDQ_ENFD)
>  		flags |= XFS_UQUOTA_ENFD;
> -	if (uflags & (FS_QUOTA_PDQ_ENFD|FS_QUOTA_GDQ_ENFD))
> -		flags |= XFS_OQUOTA_ENFD;
> +	if (uflags & FS_QUOTA_PDQ_ENFD)
> +		flags |= XFS_PQUOTA_ENFD;
> +	if (uflags & FS_QUOTA_GDQ_ENFD)
> +		flags |= XFS_GQUOTA_ENFD;
>  
>  	switch (op) {
>  	case Q_XQUOTAON:
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index ea341ce..873fa5a 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -359,17 +359,17 @@ xfs_parseargs(
>  		} else if (!strcmp(this_char, MNTOPT_PQUOTA) ||
>  			   !strcmp(this_char, MNTOPT_PRJQUOTA)) {
>  			mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE |
> -					 XFS_OQUOTA_ENFD);
> +					 XFS_PQUOTA_ENFD);
>  		} else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) {
>  			mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE);
> -			mp->m_qflags &= ~XFS_OQUOTA_ENFD;
> +			mp->m_qflags &= ~XFS_PQUOTA_ENFD;
>  		} else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
>  			   !strcmp(this_char, MNTOPT_GRPQUOTA)) {
>  			mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE |
> -					 XFS_OQUOTA_ENFD);
> +					 XFS_GQUOTA_ENFD);
>  		} else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
>  			mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
> -			mp->m_qflags &= ~XFS_OQUOTA_ENFD;
> +			mp->m_qflags &= ~XFS_GQUOTA_ENFD;
>  		} else if (!strcmp(this_char, MNTOPT_DELAYLOG)) {
>  			xfs_warn(mp,
>  	"delaylog is the default now, option is deprecated.");
> @@ -563,12 +563,12 @@ xfs_showargs(
>  	/* Either project or group quotas can be active, not both */
>  
>  	if (mp->m_qflags & XFS_PQUOTA_ACCT) {
> -		if (mp->m_qflags & XFS_OQUOTA_ENFD)
> +		if (mp->m_qflags & XFS_PQUOTA_ENFD)
>  			seq_puts(m, "," MNTOPT_PRJQUOTA);
>  		else
>  			seq_puts(m, "," MNTOPT_PQUOTANOENF);
>  	} else if (mp->m_qflags & XFS_GQUOTA_ACCT) {
> -		if (mp->m_qflags & XFS_OQUOTA_ENFD)
> +		if (mp->m_qflags & XFS_GQUOTA_ENFD)
>  			seq_puts(m, "," MNTOPT_GRPQUOTA);
>  		else
>  			seq_puts(m, "," MNTOPT_GQUOTANOENF);
> @@ -1136,8 +1136,8 @@ xfs_fs_statfs(
>  	spin_unlock(&mp->m_sb_lock);
>  
>  	if ((ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
> -	    ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))) ==
> -			      (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))
> +	    ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))) ==
> +			      (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))
>  		xfs_qm_statvfs(ip, statp);
>  	return 0;
>  }
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index fec75d0..8cdbd62 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -640,8 +640,8 @@ xfs_trans_dqresv(
>  	if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
>  	    dqp->q_core.d_id &&
>  	    ((XFS_IS_UQUOTA_ENFORCED(dqp->q_mount) && XFS_QM_ISUDQ(dqp)) ||
> -	     (XFS_IS_OQUOTA_ENFORCED(dqp->q_mount) &&
> -	      (XFS_QM_ISPDQ(dqp) || XFS_QM_ISGDQ(dqp))))) {
> +	     (XFS_IS_PQUOTA_ENFORCED(dqp->q_mount) && XFS_QM_ISPDQ(dqp)) ||
> +	     (XFS_IS_GQUOTA_ENFORCED(dqp->q_mount) && XFS_QM_ISGDQ(dqp)))) {
>  		if (nblks > 0) {
>  			/*
>  			 * dquot is locked already. See if we'd go over the
> 

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 2/5] xfs: Add pquota fields where gquota is used.
  2013-05-10 21:21 ` [PATCH v8 2/5] xfs: Add pquota fields where gquota is used Chandra Seetharaman
@ 2013-05-13  3:59   ` Jeff Liu
  2013-05-17  3:01     ` Dave Chinner
  2013-05-17 21:15     ` Chandra Seetharaman
  2013-05-17  4:23   ` Dave Chinner
  1 sibling, 2 replies; 29+ messages in thread
From: Jeff Liu @ 2013-05-13  3:59 UTC (permalink / raw)
  To: Chandra Seetharaman; +Cc: xfs

Hi,

On 05/11/2013 05:21 AM, Chandra Seetharaman wrote:
> Add project quota changes to all the places where group quota field
> is used:
>    * add separate project quota members into various structures
>    * split project quota and group quotas so that instead of overriding
>      the group quota members incore, the new project quota members are
>      used instead
>    * get rid of usage of the OQUOTA flag incore, in favor of separate
>    * group
>      and project quota flags.
>    * add a project dquot argument to various functions.
> 
> No externally visible interfaces changed.
> 
> Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
> ---
>  fs/xfs/xfs_dquot.c       |   33 ++++-
>  fs/xfs/xfs_dquot.h       |   13 +-
>  fs/xfs/xfs_icache.c      |    4 +-
>  fs/xfs/xfs_inode.h       |    1 +
>  fs/xfs/xfs_ioctl.c       |   14 +-
>  fs/xfs/xfs_iops.c        |    4 +-
>  fs/xfs/xfs_qm.c          |  355 ++++++++++++++++++++++++++++++----------------
>  fs/xfs/xfs_qm.h          |   53 +++++---
>  fs/xfs/xfs_qm_bhv.c      |    2 +-
>  fs/xfs/xfs_qm_syscalls.c |   19 ++-
>  fs/xfs/xfs_quota.h       |   32 +++--
>  fs/xfs/xfs_super.c       |    5 +-
>  fs/xfs/xfs_symlink.c     |   13 ++-
>  fs/xfs/xfs_trans_dquot.c |   94 +++++++------
>  fs/xfs/xfs_vnodeops.c    |   12 +-
>  15 files changed, 416 insertions(+), 238 deletions(-)
> 
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index a41f8bf..a25ba5d 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -68,8 +68,7 @@ static struct lock_class_key xfs_dquot_other_class;
>   * This is called to free all the memory associated with a dquot
>   */
>  void
> -xfs_qm_dqdestroy(
> -	xfs_dquot_t	*dqp)
> +xfs_qm_dqdestroy(xfs_dquot_t	*dqp)
>  {
>  	ASSERT(list_empty(&dqp->q_lru));
>  
> @@ -568,6 +567,17 @@ xfs_qm_dqrepair(
>  	return 0;
>  }
>  
> +struct xfs_inode *
> +xfs_dq_to_quota_inode(struct xfs_dquot *dqp)
> +{
> +	if (XFS_QM_ISUDQ(dqp))
> +		return dqp->q_mount->m_quotainfo->qi_uquotaip;
> +	if (XFS_QM_ISGDQ(dqp))
> +		return dqp->q_mount->m_quotainfo->qi_gquotaip;
> +	ASSERT(XFS_QM_ISPDQ(dqp));
> +	return dqp->q_mount->m_quotainfo->qi_pquotaip;
> +}
Is it better to replace above conditional judgment with 'switch...case'?
i.e.
static inline struct xfs_inode *
xfs_dq_to_qip(struct xfs_dquot *dqp)
{
	switch (dqp->dq_flags) {
	case XFS_DQ_USER:
		return dqp->q_mount->m_quotainfo->qi_uquotaip;
	case XFS_DQ_GROUP:
		return dqp->q_mount->m_quotainfo->qi_gqoutaip;
	case XFS_DQ_PROJ:
		return dqp->q_mount->m_quotainfo->qi_pquotaip;
	}

	ASSERT(0);
	return NULL;
}
> +
>  /*
>   * Maps a dquot to the buffer containing its on-disk version.
>   * This returns a ptr to the buffer containing the on-disk dquot
> @@ -584,7 +594,7 @@ xfs_qm_dqtobp(
>  	xfs_bmbt_irec_t map;
>  	int		nmaps = 1, error;
>  	xfs_buf_t	*bp;
> -	xfs_inode_t	*quotip = XFS_DQ_TO_QIP(dqp);
> +	xfs_inode_t	*quotip = xfs_dq_to_quota_inode(dqp);
>  	xfs_mount_t	*mp = dqp->q_mount;
>  	xfs_dqid_t	id = be32_to_cpu(dqp->q_core.d_id);
>  	xfs_trans_t	*tp = (tpp ? *tpp : NULL);
> @@ -815,7 +825,7 @@ xfs_qm_dqget(
>  	xfs_dquot_t	**O_dqpp) /* OUT : locked incore dquot */
>  {
>  	struct xfs_quotainfo	*qi = mp->m_quotainfo;
> -	struct radix_tree_root *tree = XFS_DQUOT_TREE(qi, type);
> +	struct radix_tree_root *tree = xfs_dquot_tree(qi, type);
>  	struct xfs_dquot	*dqp;
>  	int			error;
>  
> @@ -947,6 +957,7 @@ xfs_qm_dqput_final(
>  {
>  	struct xfs_quotainfo	*qi = dqp->q_mount->m_quotainfo;
>  	struct xfs_dquot	*gdqp;
> +	struct xfs_dquot	*pdqp;
>  
>  	trace_xfs_dqput_free(dqp);
>  
> @@ -960,21 +971,29 @@ xfs_qm_dqput_final(
>  
>  	/*
>  	 * If we just added a udquot to the freelist, then we want to release
> -	 * the gdquot reference that it (probably) has. Otherwise it'll keep
> -	 * the gdquot from getting reclaimed.
> +	 * the gdquot/pdquot reference that it (probably) has. Otherwise it'll
> +	 * keep the gdquot/pdquot from getting reclaimed.
>  	 */
>  	gdqp = dqp->q_gdquot;
>  	if (gdqp) {
>  		xfs_dqlock(gdqp);
>  		dqp->q_gdquot = NULL;
>  	}
> +
> +	pdqp = dqp->q_pdquot;
> +	if (pdqp) {
> +		xfs_dqlock(pdqp);
> +		dqp->q_pdquot = NULL;
> +	}
>  	xfs_dqunlock(dqp);
>  
>  	/*
> -	 * If we had a group quota hint, release it now.
> +	 * If we had a group/project quota hint, release it now.
>  	 */
>  	if (gdqp)
>  		xfs_qm_dqput(gdqp);
> +	if (pdqp)
> +		xfs_qm_dqput(pdqp);
>  }
>  
>  /*
> diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
> index 4f0ebfc..00ccbf1 100644
> --- a/fs/xfs/xfs_dquot.h
> +++ b/fs/xfs/xfs_dquot.h
> @@ -29,7 +29,6 @@
>   * when quotas are off.
>   */
>  
> -struct xfs_mount;
>  struct xfs_trans;
>  
>  enum {
> @@ -52,7 +51,8 @@ typedef struct xfs_dquot {
>  	int		 q_bufoffset;	/* off of dq in buffer (# dquots) */
>  	xfs_fileoff_t	 q_fileoffset;	/* offset in quotas file */
>  
> -	struct xfs_dquot*q_gdquot;	/* group dquot, hint only */
> +	struct xfs_dquot *q_gdquot;	/* group dquot, hint only */
> +	struct xfs_dquot *q_pdquot;	/* project dquot, hint only */
>  	xfs_disk_dquot_t q_core;	/* actual usage & quotas */
>  	xfs_dq_logitem_t q_logitem;	/* dquot log item */
>  	xfs_qcnt_t	 q_res_bcount;	/* total regular nblks used+reserved */
> @@ -118,8 +118,9 @@ static inline int xfs_this_quota_on(struct xfs_mount *mp, int type)
>  	case XFS_DQ_USER:
>  		return XFS_IS_UQUOTA_ON(mp);
>  	case XFS_DQ_GROUP:
> +		return XFS_IS_GQUOTA_ON(mp);
>  	case XFS_DQ_PROJ:
> -		return XFS_IS_OQUOTA_ON(mp);
> +		return XFS_IS_PQUOTA_ON(mp);
>  	default:
>  		return 0;
>  	}
> @@ -131,8 +132,9 @@ static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
>  	case XFS_DQ_USER:
>  		return ip->i_udquot;
>  	case XFS_DQ_GROUP:
> -	case XFS_DQ_PROJ:
>  		return ip->i_gdquot;
> +	case XFS_DQ_PROJ:
> +		return ip->i_pdquot;
>  	default:
>  		return NULL;
>  	}
> @@ -144,9 +146,6 @@ static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
>  #define XFS_QM_ISPDQ(dqp)	((dqp)->dq_flags & XFS_DQ_PROJ)
>  #define XFS_QM_ISGDQ(dqp)	((dqp)->dq_flags & XFS_DQ_GROUP)
>  #define XFS_DQ_TO_QINF(dqp)	((dqp)->q_mount->m_quotainfo)
For now, XFS_DQ_TO_QINF() is used by XFS_DQ_TO_QIP() only.
Maybe we can remove it in this patch as well, if we don't want to make
use of it in any other places to simplify the input...
> -#define XFS_DQ_TO_QIP(dqp)	(XFS_QM_ISUDQ(dqp) ? \
> -				 XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \
> -				 XFS_DQ_TO_QINF(dqp)->qi_gquotaip)
>  
>  extern int		xfs_qm_dqread(struct xfs_mount *, xfs_dqid_t, uint,
>  					uint, struct xfs_dquot	**);
> diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
> index 96e344e..3f90e1c 100644
> --- a/fs/xfs/xfs_icache.c
> +++ b/fs/xfs/xfs_icache.c
> @@ -335,7 +335,9 @@ xfs_iget_cache_miss(
>  	iflags = XFS_INEW;
>  	if (flags & XFS_IGET_DONTCACHE)
>  		iflags |= XFS_IDONTCACHE;
> -	ip->i_udquot = ip->i_gdquot = NULL;
> +	ip->i_udquot = NULL;
> +	ip->i_gdquot = NULL;
> +	ip->i_pdquot = NULL;
>  	xfs_iflags_set(ip, iflags);
>  
>  	/* insert the new inode */
> diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
> index 9112979..b55fd34 100644
> --- a/fs/xfs/xfs_inode.h
> +++ b/fs/xfs/xfs_inode.h
> @@ -250,6 +250,7 @@ typedef struct xfs_inode {
>  	struct xfs_mount	*i_mount;	/* fs mount struct ptr */
>  	struct xfs_dquot	*i_udquot;	/* user dquot */
>  	struct xfs_dquot	*i_gdquot;	/* group dquot */
> +	struct xfs_dquot	*i_pdquot;	/* project dquot */
>  
>  	/* Inode location stuff */
>  	xfs_ino_t		i_ino;		/* inode number (agno/agino)*/
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 5e99968..71a8bc5 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -928,7 +928,7 @@ xfs_ioctl_setattr(
>  	struct xfs_trans	*tp;
>  	unsigned int		lock_flags = 0;
>  	struct xfs_dquot	*udqp = NULL;
> -	struct xfs_dquot	*gdqp = NULL;
> +	struct xfs_dquot	*pdqp = NULL;
>  	struct xfs_dquot	*olddquot = NULL;
>  	int			code;
>  
> @@ -957,7 +957,7 @@ xfs_ioctl_setattr(
>  	if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
>  		code = xfs_qm_vop_dqalloc(ip, ip->i_d.di_uid,
>  					 ip->i_d.di_gid, fa->fsx_projid,
> -					 XFS_QMOPT_PQUOTA, &udqp, &gdqp);
> +					 XFS_QMOPT_PQUOTA, &udqp, NULL, &pdqp);
>  		if (code)
>  			return code;
>  	}
> @@ -994,8 +994,8 @@ xfs_ioctl_setattr(
>  		    XFS_IS_PQUOTA_ON(mp) &&
>  		    xfs_get_projid(ip) != fa->fsx_projid) {
>  			ASSERT(tp);
> -			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
> -						capable(CAP_FOWNER) ?
> +			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL,
> +						pdqp, capable(CAP_FOWNER) ?
>  						XFS_QMOPT_FORCE_RES : 0);
>  			if (code)	/* out of quota */
>  				goto error_return;
> @@ -1113,7 +1113,7 @@ xfs_ioctl_setattr(
>  		if (xfs_get_projid(ip) != fa->fsx_projid) {
>  			if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
>  				olddquot = xfs_qm_vop_chown(tp, ip,
> -							&ip->i_gdquot, gdqp);
> +							&ip->i_pdquot, pdqp);
>  			}
>  			xfs_set_projid(ip, fa->fsx_projid);
>  
> @@ -1160,13 +1160,13 @@ xfs_ioctl_setattr(
>  	 */
>  	xfs_qm_dqrele(olddquot);
>  	xfs_qm_dqrele(udqp);
> -	xfs_qm_dqrele(gdqp);
> +	xfs_qm_dqrele(pdqp);
>  
>  	return code;
>  
>   error_return:
>  	xfs_qm_dqrele(udqp);
> -	xfs_qm_dqrele(gdqp);
> +	xfs_qm_dqrele(pdqp);
>  	xfs_trans_cancel(tp, 0);
>  	if (lock_flags)
>  		xfs_iunlock(ip, lock_flags);
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index d82efaa..7c54ea4 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -517,7 +517,7 @@ xfs_setattr_nonsize(
>  		ASSERT(udqp == NULL);
>  		ASSERT(gdqp == NULL);
>  		error = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip),
> -					 qflags, &udqp, &gdqp);
> +					 qflags, &udqp, &gdqp, NULL);
>  		if (error)
>  			return error;
>  	}
> @@ -553,7 +553,7 @@ xfs_setattr_nonsize(
>  		     (XFS_IS_GQUOTA_ON(mp) && igid != gid))) {
>  			ASSERT(tp);
>  			error = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
> -						capable(CAP_FOWNER) ?
> +						NULL, capable(CAP_FOWNER) ?
>  						XFS_QMOPT_FORCE_RES : 0);
>  			if (error)	/* out of quota */
>  				goto out_trans_cancel;
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index fe4c743..97912cb 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -69,7 +69,7 @@ xfs_qm_dquot_walk(
>  	void			*data)
>  {
>  	struct xfs_quotainfo	*qi = mp->m_quotainfo;
> -	struct radix_tree_root	*tree = XFS_DQUOT_TREE(qi, type);
> +	struct radix_tree_root	*tree = xfs_dquot_tree(qi, type);
>  	uint32_t		next_index;
>  	int			last_error = 0;
>  	int			skipped;
> @@ -136,6 +136,7 @@ xfs_qm_dqpurge(
>  	struct xfs_mount	*mp = dqp->q_mount;
>  	struct xfs_quotainfo	*qi = mp->m_quotainfo;
>  	struct xfs_dquot	*gdqp = NULL;
> +	struct xfs_dquot	*pdqp = NULL;
>  
>  	xfs_dqlock(dqp);
>  	if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) {
> @@ -144,8 +145,7 @@ xfs_qm_dqpurge(
>  	}
>  
>  	/*
> -	 * If this quota has a group hint attached, prepare for releasing it
> -	 * now.
> +	 * If this quota has a hint attached, prepare for releasing it now.
>  	 */
>  	gdqp = dqp->q_gdquot;
>  	if (gdqp) {
> @@ -153,6 +153,12 @@ xfs_qm_dqpurge(
>  		dqp->q_gdquot = NULL;
>  	}
>  
> +	pdqp = dqp->q_pdquot;
> +	if (pdqp) {
> +		xfs_dqlock(pdqp);
> +		dqp->q_pdquot = NULL;
> +	}
> +
>  	dqp->dq_flags |= XFS_DQ_FREEING;
>  
>  	xfs_dqflock(dqp);
> @@ -188,7 +194,7 @@ xfs_qm_dqpurge(
>  	xfs_dqfunlock(dqp);
>  	xfs_dqunlock(dqp);
>  
> -	radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags),
> +	radix_tree_delete(xfs_dquot_tree(qi, dqp->q_core.d_flags),
>  			  be32_to_cpu(dqp->q_core.d_id));
>  	qi->qi_dquots--;
>  
> @@ -207,6 +213,8 @@ xfs_qm_dqpurge(
>  
>  	if (gdqp)
>  		xfs_qm_dqput(gdqp);
> +	if (pdqp)
> +		xfs_qm_dqput(pdqp);
>  	return 0;
>  }
>  
> @@ -363,6 +371,10 @@ xfs_qm_unmount_quotas(
>  			IRELE(mp->m_quotainfo->qi_gquotaip);
>  			mp->m_quotainfo->qi_gquotaip = NULL;
>  		}
> +		if (mp->m_quotainfo->qi_pquotaip) {
> +			IRELE(mp->m_quotainfo->qi_pquotaip);
> +			mp->m_quotainfo->qi_pquotaip = NULL;
> +		}
>  	}
>  }
>  
> @@ -409,7 +421,10 @@ xfs_qm_dqattach_one(
>  		 * be reclaimed as long as we have a ref from inode and we
>  		 * hold the ilock.
>  		 */
> -		dqp = udqhint->q_gdquot;
> +		if (type == XFS_DQ_GROUP)
> +			dqp = udqhint->q_gdquot;
> +		else
> +			dqp = udqhint->q_pdquot;
Maybe it's better to:
dqp = "type == XFS_DQ_GROUP" ? udqhint->q_gdquot :
			       udqhint->q_pdquot;

>  		if (dqp && be32_to_cpu(dqp->q_core.d_id) == id) {
>  			ASSERT(*IO_idqpp == NULL);
>  
> @@ -452,28 +467,38 @@ xfs_qm_dqattach_one(
>  
>  
>  /*
> - * Given a udquot and gdquot, attach a ptr to the group dquot in the
> + * Given a udquot and gdquot, attach a ptr to the group/project dquot in the
>   * udquot as a hint for future lookups.
>   */
>  STATIC void
> -xfs_qm_dqattach_grouphint(
> -	xfs_dquot_t	*udq,
> -	xfs_dquot_t	*gdq)
> +xfs_qm_dqattach_grouphint(xfs_inode_t *ip, int type)
>  {
> -	xfs_dquot_t	*tmp;
> +	struct xfs_dquot **dqhint;
> +	struct xfs_dquot *gpdq;
> +	struct xfs_dquot *udq = ip->i_udquot;
>  
>  	xfs_dqlock(udq);
>  
> -	tmp = udq->q_gdquot;
> -	if (tmp) {
> -		if (tmp == gdq)
> +	if (type == XFS_DQ_GROUP) {
> +		gpdq = ip->i_gdquot;
> +		dqhint = &udq->q_gdquot;
> +	} else {
> +		gpdq = ip->i_pdquot;
> +		dqhint = &udq->q_pdquot;
> +	}
> +
> +	if (*dqhint) {
> +		struct xfs_dquot *tmp;
> +
> +		if (*dqhint == gpdq)
>  			goto done;
>  
> -		udq->q_gdquot = NULL;
> +		tmp = *dqhint;
> +		*dqhint = NULL;
>  		xfs_qm_dqrele(tmp);
>  	}
>  
> -	udq->q_gdquot = xfs_qm_dqhold(gdq);
> +	*dqhint = xfs_qm_dqhold(gpdq);
>  done:
>  	xfs_dqunlock(udq);
>  }
> @@ -527,12 +552,8 @@ xfs_qm_dqattach_locked(
>  	}
>  
>  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
> -	if (XFS_IS_OQUOTA_ON(mp)) {
> -		error = XFS_IS_GQUOTA_ON(mp) ?
> -			xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
> -						flags & XFS_QMOPT_DQALLOC,
> -						ip->i_udquot, &ip->i_gdquot) :
> -			xfs_qm_dqattach_one(ip, xfs_get_projid(ip), XFS_DQ_PROJ,
> +	if (XFS_IS_GQUOTA_ON(mp)) {
> +		error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
>  						flags & XFS_QMOPT_DQALLOC,
>  						ip->i_udquot, &ip->i_gdquot);
>  		/*
> @@ -544,14 +565,28 @@ xfs_qm_dqattach_locked(
>  		nquotas++;
>  	}
>  
> +	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
> +	if (XFS_IS_PQUOTA_ON(mp)) {
> +		error = xfs_qm_dqattach_one(ip, xfs_get_projid(ip), XFS_DQ_PROJ,
> +						flags & XFS_QMOPT_DQALLOC,
> +						ip->i_udquot, &ip->i_pdquot);
> +		/*
> +		 * Don't worry about the udquot that we may have
> +		 * attached above. It'll get detached, if not already.
> +		 */
> +		if (error)
> +			goto done;
> +		nquotas++;
> +	}
> +
>  	/*
> -	 * Attach this group quota to the user quota as a hint.
> +	 * Attach this group/project quota to the user quota as a hint.
>  	 * This WON'T, in general, result in a thrash.
>  	 */
> -	if (nquotas == 2) {
> +	if (nquotas > 1 && ip->i_udquot) {
>  		ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
> -		ASSERT(ip->i_udquot);
> -		ASSERT(ip->i_gdquot);
> +		ASSERT(ip->i_gdquot || !XFS_IS_GQUOTA_ON(mp));
> +		ASSERT(ip->i_pdquot || !XFS_IS_PQUOTA_ON(mp));
>  
>  		/*
>  		 * We do not have i_udquot locked at this point, but this check
> @@ -559,8 +594,13 @@ xfs_qm_dqattach_locked(
>  		 * 100% all the time. It is just a hint, and this will
>  		 * succeed in general.
>  		 */
> -		if (ip->i_udquot->q_gdquot != ip->i_gdquot)
> -			xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot);
> +		if (XFS_IS_GQUOTA_ON(mp) &&
> +				ip->i_udquot->q_gdquot != ip->i_gdquot)
> +			xfs_qm_dqattach_grouphint(ip, XFS_DQ_GROUP);
> +
> +		if (XFS_IS_PQUOTA_ON(mp) &&
> +				ip->i_udquot->q_pdquot != ip->i_pdquot)
> +			xfs_qm_dqattach_grouphint(ip, XFS_DQ_PROJ);
>  	}
>  
>   done:
> @@ -568,8 +608,10 @@ xfs_qm_dqattach_locked(
>  	if (!error) {
>  		if (XFS_IS_UQUOTA_ON(mp))
>  			ASSERT(ip->i_udquot);
> -		if (XFS_IS_OQUOTA_ON(mp))
> +		if (XFS_IS_GQUOTA_ON(mp))
>  			ASSERT(ip->i_gdquot);
> +		if (XFS_IS_PQUOTA_ON(mp))
> +			ASSERT(ip->i_pdquot);
>  	}
>  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
>  #endif
> @@ -602,7 +644,7 @@ void
>  xfs_qm_dqdetach(
>  	xfs_inode_t	*ip)
>  {
> -	if (!(ip->i_udquot || ip->i_gdquot))
> +	if (!(ip->i_udquot || ip->i_gdquot || ip->i_pdquot))
>  		return;
>  
>  	trace_xfs_dquot_dqdetach(ip);
> @@ -617,6 +659,10 @@ xfs_qm_dqdetach(
>  		xfs_qm_dqrele(ip->i_gdquot);
>  		ip->i_gdquot = NULL;
>  	}
> +	if (ip->i_pdquot) {
> +		xfs_qm_dqrele(ip->i_pdquot);
> +		ip->i_pdquot = NULL;
> +	}
>  }
>  
>  int
> @@ -661,6 +707,7 @@ xfs_qm_init_quotainfo(
>  
>  	INIT_RADIX_TREE(&qinf->qi_uquota_tree, GFP_NOFS);
>  	INIT_RADIX_TREE(&qinf->qi_gquota_tree, GFP_NOFS);
> +	INIT_RADIX_TREE(&qinf->qi_pquota_tree, GFP_NOFS);
>  	mutex_init(&qinf->qi_tree_lock);
>  
>  	INIT_LIST_HEAD(&qinf->qi_lru_list);
> @@ -762,6 +809,10 @@ xfs_qm_destroy_quotainfo(
>  		IRELE(qi->qi_gquotaip);
>  		qi->qi_gquotaip = NULL;
>  	}
> +	if (qi->qi_pquotaip) {
> +		IRELE(qi->qi_pquotaip);
> +		qi->qi_pquotaip = NULL;
> +	}
>  	mutex_destroy(&qi->qi_quotaofflock);
>  	kmem_free(qi);
>  	mp->m_quotainfo = NULL;
> @@ -1247,16 +1298,18 @@ xfs_qm_quotacheck(
>  	int		done, count, error, error2;
>  	xfs_ino_t	lastino;
>  	size_t		structsz;
> -	xfs_inode_t	*uip, *gip;
>  	uint		flags;
>  	LIST_HEAD	(buffer_list);
> +	struct xfs_inode	*uip = mp->m_quotainfo->qi_uquotaip;
> +	struct xfs_inode	*gip = mp->m_quotainfo->qi_gquotaip;
> +	struct xfs_inode	*pip = mp->m_quotainfo->qi_pquotaip;
>  
>  	count = INT_MAX;
>  	structsz = 1;
>  	lastino = 0;
>  	flags = 0;
>  
> -	ASSERT(mp->m_quotainfo->qi_uquotaip || mp->m_quotainfo->qi_gquotaip);
> +	ASSERT(uip || gip || pip);
>  	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
>  
>  	xfs_notice(mp, "Quotacheck needed: Please wait.");
> @@ -1266,7 +1319,6 @@ xfs_qm_quotacheck(
>  	 * their counters to zero. We need a clean slate.
>  	 * We don't log our changes till later.
>  	 */
> -	uip = mp->m_quotainfo->qi_uquotaip;
>  	if (uip) {
>  		error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA,
>  					 &buffer_list);
> @@ -1275,15 +1327,20 @@ xfs_qm_quotacheck(
>  		flags |= XFS_UQUOTA_CHKD;
>  	}
>  
> -	gip = mp->m_quotainfo->qi_gquotaip;
>  	if (gip) {
> -		error = xfs_qm_dqiterate(mp, gip, XFS_IS_GQUOTA_ON(mp) ?
> -					 XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA,
> +		error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA,
> +					 &buffer_list);
> +		if (error)
> +			goto error_return;
> +		flags |= XFS_GQUOTA_CHKD;
> +	}
> +
> +	if (pip) {
> +		error = xfs_qm_dqiterate(mp, pip, XFS_QMOPT_PQUOTA,
>  					 &buffer_list);
>  		if (error)
>  			goto error_return;
> -		flags |= XFS_IS_GQUOTA_ON(mp) ?
> -					XFS_GQUOTA_CHKD : XFS_PQUOTA_CHKD;
> +		flags |= XFS_PQUOTA_CHKD;
>  	}
>  
>  	do {
> @@ -1378,13 +1435,14 @@ STATIC int
>  xfs_qm_init_quotainos(
>  	xfs_mount_t	*mp)
>  {
> -	xfs_inode_t	*uip, *gip;
> +	struct xfs_inode	*uip = NULL;
> +	struct xfs_inode	*gip = NULL;
> +	struct xfs_inode	*pip = NULL;
>  	int		error;
>  	__int64_t	sbflags;
>  	uint		flags;
>  
>  	ASSERT(mp->m_quotainfo);
> -	uip = gip = NULL;
>  	sbflags = 0;
>  	flags = 0;
>  
> @@ -1395,19 +1453,27 @@ xfs_qm_init_quotainos(
>  		if (XFS_IS_UQUOTA_ON(mp) &&
>  		    mp->m_sb.sb_uquotino != NULLFSINO) {
>  			ASSERT(mp->m_sb.sb_uquotino > 0);
> -			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
> -					     0, 0, &uip)))
> +			error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
> +					     0, 0, &uip);
> +			if (error)
>  				return XFS_ERROR(error);
>  		}
> -		if (XFS_IS_OQUOTA_ON(mp) &&
> +		if (XFS_IS_GQUOTA_ON(mp) &&
>  		    mp->m_sb.sb_gquotino != NULLFSINO) {
>  			ASSERT(mp->m_sb.sb_gquotino > 0);
> -			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
> -					     0, 0, &gip))) {
> -				if (uip)
> -					IRELE(uip);
> -				return XFS_ERROR(error);
> -			}
> +			error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
> +					     0, 0, &gip);
> +			if (error)
> +				goto error_rele;
> +		}
> +		/* Use sb_gquotino for now */
> +		if (XFS_IS_PQUOTA_ON(mp) &&
> +		    mp->m_sb.sb_gquotino != NULLFSINO) {
> +			ASSERT(mp->m_sb.sb_gquotino > 0);
> +			error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
> +					     0, 0, &pip);
> +			if (error)
> +				goto error_rele;
>  		}
>  	} else {
>  		flags |= XFS_QMOPT_SBVERSION;
> @@ -1416,36 +1482,50 @@ xfs_qm_init_quotainos(
>  	}
>  
>  	/*
> -	 * Create the two inodes, if they don't exist already. The changes
> +	 * Create the three inodes, if they don't exist already. The changes
>  	 * made above will get added to a transaction and logged in one of
>  	 * the qino_alloc calls below.  If the device is readonly,
>  	 * temporarily switch to read-write to do this.
>  	 */
>  	if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) {
> -		if ((error = xfs_qm_qino_alloc(mp, &uip,
> +		error = xfs_qm_qino_alloc(mp, &uip,
>  					      sbflags | XFS_SB_UQUOTINO,
> -					      flags | XFS_QMOPT_UQUOTA)))
> +					      flags | XFS_QMOPT_UQUOTA);
> +		if (error)
>  			return XFS_ERROR(error);
>  
>  		flags &= ~XFS_QMOPT_SBVERSION;
>  	}
> -	if (XFS_IS_OQUOTA_ON(mp) && gip == NULL) {
> -		flags |= (XFS_IS_GQUOTA_ON(mp) ?
> -				XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA);
> +	if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
>  		error = xfs_qm_qino_alloc(mp, &gip,
> -					  sbflags | XFS_SB_GQUOTINO, flags);
> -		if (error) {
> -			if (uip)
> -				IRELE(uip);
> -
> -			return XFS_ERROR(error);
> -		}
> +					     sbflags | XFS_SB_GQUOTINO,
> +					     flags | XFS_QMOPT_GQUOTA);
> +		if (error)
> +			goto error_rele;
> +	}
> +	if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
> +		error = xfs_qm_qino_alloc(mp, &pip,
> +					     sbflags | XFS_SB_GQUOTINO,
> +					     flags | XFS_QMOPT_PQUOTA);
> +		if (error)
> +			goto error_rele;
>  	}
>  
>  	mp->m_quotainfo->qi_uquotaip = uip;
>  	mp->m_quotainfo->qi_gquotaip = gip;
> +	mp->m_quotainfo->qi_pquotaip = pip;
>  
>  	return 0;
> +
> +error_rele:
> +	if (uip)
> +		IRELE(uip);
> +	if (gip)
> +		IRELE(gip);
> +	if (pip)
> +		IRELE(pip);
> +	return XFS_ERROR(error);
> +
>  }
>  
>  STATIC void
> @@ -1456,7 +1536,7 @@ xfs_qm_dqfree_one(
>  	struct xfs_quotainfo	*qi = mp->m_quotainfo;
>  
>  	mutex_lock(&qi->qi_tree_lock);
> -	radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags),
> +	radix_tree_delete(xfs_dquot_tree(qi, dqp->q_core.d_flags),
>  			  be32_to_cpu(dqp->q_core.d_id));
>  
>  	qi->qi_dquots--;
> @@ -1639,10 +1719,13 @@ xfs_qm_vop_dqalloc(
>  	prid_t			prid,
>  	uint			flags,
>  	struct xfs_dquot	**O_udqpp,
> -	struct xfs_dquot	**O_gdqpp)
> +	struct xfs_dquot	**O_gdqpp,
> +	struct xfs_dquot	**O_pdqpp)
>  {
>  	struct xfs_mount	*mp = ip->i_mount;
> -	struct xfs_dquot	*uq, *gq;
> +	struct xfs_dquot	*uq = NULL;
> +	struct xfs_dquot	*gq = NULL;
> +	struct xfs_dquot	*pq = NULL;
>  	int			error;
>  	uint			lockflags;
>  
> @@ -1667,7 +1750,6 @@ xfs_qm_vop_dqalloc(
>  		}
>  	}
>  
> -	uq = gq = NULL;
>  	if ((flags & XFS_QMOPT_UQUOTA) && XFS_IS_UQUOTA_ON(mp)) {
>  		if (ip->i_d.di_uid != uid) {
>  			/*
> @@ -1680,14 +1762,14 @@ xfs_qm_vop_dqalloc(
>  			 * holding ilock.
>  			 */
>  			xfs_iunlock(ip, lockflags);
> -			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid,
> +			error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid,
>  						 XFS_DQ_USER,
>  						 XFS_QMOPT_DQALLOC |
>  						 XFS_QMOPT_DOWARN,
> -						 &uq))) {
> -				ASSERT(error != ENOENT);
> +						 &uq);
> +			ASSERT(error != ENOENT);
> +			if (error)
>  				return error;
> -			}
>  			/*
>  			 * Get the ilock in the right order.
>  			 */
> @@ -1706,16 +1788,15 @@ xfs_qm_vop_dqalloc(
>  	if ((flags & XFS_QMOPT_GQUOTA) && XFS_IS_GQUOTA_ON(mp)) {
>  		if (ip->i_d.di_gid != gid) {
>  			xfs_iunlock(ip, lockflags);
> -			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,
> +			error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,
>  						 XFS_DQ_GROUP,
>  						 XFS_QMOPT_DQALLOC |
>  						 XFS_QMOPT_DOWARN,
> -						 &gq))) {
> -				if (uq)
> -					xfs_qm_dqrele(uq);
> -				ASSERT(error != ENOENT);
> -				return error;
> -			}
> +						 &gq);
> +			ASSERT(error != ENOENT);
> +			if (error)
> +				goto error_rele;
> +
>  			xfs_dqunlock(gq);
>  			lockflags = XFS_ILOCK_SHARED;
>  			xfs_ilock(ip, lockflags);
> @@ -1723,25 +1804,25 @@ xfs_qm_vop_dqalloc(
>  			ASSERT(ip->i_gdquot);
>  			gq = xfs_qm_dqhold(ip->i_gdquot);
>  		}
> -	} else if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) {
> +	}
> +	if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) {
>  		if (xfs_get_projid(ip) != prid) {
>  			xfs_iunlock(ip, lockflags);
> -			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid,
> +			error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid,
>  						 XFS_DQ_PROJ,
>  						 XFS_QMOPT_DQALLOC |
>  						 XFS_QMOPT_DOWARN,
> -						 &gq))) {
> -				if (uq)
> -					xfs_qm_dqrele(uq);
> -				ASSERT(error != ENOENT);
> -				return (error);
> -			}
> -			xfs_dqunlock(gq);
> +						 &pq);
> +			ASSERT(error != ENOENT);
> +			if (error)
> +				goto error_rele;
> +
> +			xfs_dqunlock(pq);
>  			lockflags = XFS_ILOCK_SHARED;
>  			xfs_ilock(ip, lockflags);
>  		} else {
> -			ASSERT(ip->i_gdquot);
> -			gq = xfs_qm_dqhold(ip->i_gdquot);
> +			ASSERT(ip->i_pdquot);
> +			pq = xfs_qm_dqhold(ip->i_pdquot);
>  		}
>  	}
>  	if (uq)
> @@ -1756,7 +1837,18 @@ xfs_qm_vop_dqalloc(
>  		*O_gdqpp = gq;
>  	else if (gq)
>  		xfs_qm_dqrele(gq);
> +	if (O_pdqpp)
> +		*O_pdqpp = pq;
> +	else if (pq)
> +		xfs_qm_dqrele(pq);
>  	return 0;
> +
> +error_rele:
> +	if (uq)
> +		xfs_qm_dqrele(uq);
> +	if (gq)
> +		xfs_qm_dqrele(gq);
> +	return error;
>  }
>  
>  /*
> @@ -1804,15 +1896,21 @@ xfs_qm_vop_chown(
>   */
>  int
>  xfs_qm_vop_chown_reserve(
> -	xfs_trans_t	*tp,
> -	xfs_inode_t	*ip,
> -	xfs_dquot_t	*udqp,
> -	xfs_dquot_t	*gdqp,
> -	uint		flags)
> +	xfs_trans_t		*tp,
> +	xfs_inode_t		*ip,
> +	struct xfs_dquot	*udqp,
> +	struct xfs_dquot	*gdqp,
> +	struct xfs_dquot	*pdqp,
> +	uint			flags)
>  {
>  	xfs_mount_t	*mp = ip->i_mount;
>  	uint		delblks, blkflags, prjflags = 0;
> -	xfs_dquot_t	*unresudq, *unresgdq, *delblksudq, *delblksgdq;
> +	struct xfs_dquot	*unresudq = NULL;
> +	struct xfs_dquot	*unresgdq = NULL;
> +	struct xfs_dquot	*unrespdq = NULL;
> +	struct xfs_dquot	*delblksudq = NULL;
> +	struct xfs_dquot	*delblksgdq = NULL;
> +	struct xfs_dquot	*delblkspdq = NULL;
>  	int		error;
>  
>  
> @@ -1820,7 +1918,6 @@ xfs_qm_vop_chown_reserve(
>  	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
>  
>  	delblks = ip->i_delayed_blks;
> -	delblksudq = delblksgdq = unresudq = unresgdq = NULL;
>  	blkflags = XFS_IS_REALTIME_INODE(ip) ?
>  			XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS;
>  
> @@ -1837,25 +1934,29 @@ xfs_qm_vop_chown_reserve(
>  			unresudq = ip->i_udquot;
>  		}
>  	}
> -	if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) {
> -		if (XFS_IS_PQUOTA_ON(ip->i_mount) &&
> -		     xfs_get_projid(ip) != 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);
> -				unresgdq = ip->i_gdquot;
> -			}
> +	if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp &&
> +	    ip->i_d.di_gid != be32_to_cpu(gdqp->q_core.d_id)) {
> +		delblksgdq = gdqp;
> +		if (delblks) {
> +			ASSERT(ip->i_gdquot);
> +			unresgdq = ip->i_gdquot;
> +		}
> +	}
> +
> +	if (XFS_IS_PQUOTA_ON(ip->i_mount) && pdqp &&
> +	    xfs_get_projid(ip) != be32_to_cpu(pdqp->q_core.d_id)) {
> +		prjflags = XFS_QMOPT_ENOSPC;
> +		delblkspdq = pdqp;
> +		if (delblks) {
> +			ASSERT(ip->i_pdquot);
> +			unrespdq = ip->i_pdquot;
>  		}
>  	}
>  
> -	if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
> -				delblksudq, delblksgdq, ip->i_d.di_nblocks, 1,
> -				flags | blkflags | prjflags)))
> +	error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
> +			delblksudq, delblksgdq, delblkspdq, ip->i_d.di_nblocks,
> +			1, flags | blkflags | prjflags);
> +	if (error)
>  		return (error);
>  
>  	/*
> @@ -1868,15 +1969,17 @@ xfs_qm_vop_chown_reserve(
>  		/*
>  		 * Do the reservations first. Unreservation can't fail.
>  		 */
> -		ASSERT(delblksudq || delblksgdq);
> -		ASSERT(unresudq || unresgdq);
> -		if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
> -				delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0,
> -				flags | blkflags | prjflags)))
> +		ASSERT(delblksudq || delblksgdq || delblkspdq);
> +		ASSERT(unresudq || unresgdq || unrespdq);
> +		error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
> +				delblksudq, delblksgdq, delblkspdq,
> +				(xfs_qcnt_t)delblks, 0,
> +				flags | blkflags | prjflags);
> +		if (error)
>  			return (error);
>  		xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
> -				unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0,
> -				blkflags);
> +				unresudq, unresgdq, unrespdq,
> +				-((xfs_qcnt_t)delblks), 0, blkflags);
>  	}
>  
>  	return (0);
> @@ -1915,7 +2018,8 @@ xfs_qm_vop_create_dqattach(
>  	struct xfs_trans	*tp,
>  	struct xfs_inode	*ip,
>  	struct xfs_dquot	*udqp,
> -	struct xfs_dquot	*gdqp)
> +	struct xfs_dquot	*gdqp,
> +	struct xfs_dquot	*pdqp)
>  {
>  	struct xfs_mount	*mp = tp->t_mountp;
>  
> @@ -1935,13 +2039,18 @@ xfs_qm_vop_create_dqattach(
>  	}
>  	if (gdqp) {
>  		ASSERT(ip->i_gdquot == NULL);
> -		ASSERT(XFS_IS_OQUOTA_ON(mp));
> -		ASSERT((XFS_IS_GQUOTA_ON(mp) ?
> -			ip->i_d.di_gid : xfs_get_projid(ip)) ==
> -				be32_to_cpu(gdqp->q_core.d_id));
> -
> +		ASSERT(XFS_IS_GQUOTA_ON(mp));
> +		ASSERT(ip->i_d.di_gid == be32_to_cpu(gdqp->q_core.d_id));
>  		ip->i_gdquot = xfs_qm_dqhold(gdqp);
>  		xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
>  	}
> +	if (pdqp) {
> +		ASSERT(ip->i_pdquot == NULL);
> +		ASSERT(XFS_IS_PQUOTA_ON(mp));
> +		ASSERT(xfs_get_projid(ip) == be32_to_cpu(pdqp->q_core.d_id));
> +
> +		ip->i_pdquot = xfs_qm_dqhold(pdqp);
> +		xfs_trans_mod_dquot(tp, pdqp, XFS_TRANS_DQ_ICOUNT, 1);
> +	}
>  }
>  
> diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
> index 5d16a6e..f23b06b 100644
> --- a/fs/xfs/xfs_qm.h
> +++ b/fs/xfs/xfs_qm.h
> @@ -44,9 +44,11 @@ extern struct kmem_zone	*xfs_qm_dqtrxzone;
>  typedef struct xfs_quotainfo {
>  	struct radix_tree_root qi_uquota_tree;
>  	struct radix_tree_root qi_gquota_tree;
> +	struct radix_tree_root qi_pquota_tree;
>  	struct mutex qi_tree_lock;
> -	xfs_inode_t	*qi_uquotaip;	 /* user quota inode */
> -	xfs_inode_t	*qi_gquotaip;	 /* group quota inode */
> +	struct xfs_inode *qi_uquotaip;	 /* user quota inode */
> +	struct xfs_inode *qi_gquotaip;	 /* group quota inode */
> +	struct xfs_inode *qi_pquotaip;	 /* project quota inode */
>  	struct list_head qi_lru_list;
>  	struct mutex	 qi_lru_lock;
>  	int		 qi_lru_count;
> @@ -69,30 +71,45 @@ typedef struct xfs_quotainfo {
>  	struct shrinker  qi_shrinker;
>  } xfs_quotainfo_t;
>  
> -#define XFS_DQUOT_TREE(qi, type) \
> -	((type & XFS_DQ_USER) ? \
> -	 &((qi)->qi_uquota_tree) : \
> -	 &((qi)->qi_gquota_tree))
> -
> +static inline struct radix_tree_root *
> +xfs_dquot_tree(
> +	struct xfs_quotainfo	*qi,
> +	int			type)
> +{
> +	switch (type) {
> +	case XFS_DQ_USER:
> +		return &qi->qi_uquota_tree;
> +	case XFS_DQ_GROUP:
> +		return &qi->qi_gquota_tree;
> +	case XFS_DQ_PROJ:
> +		return &qi->qi_pquota_tree;
> +	default:
> +		ASSERT(0);
> +	}
> +	return NULL;
> +}
>  
>  extern int	xfs_qm_calc_dquots_per_chunk(struct xfs_mount *mp,
>  					     unsigned int nbblks);
> -extern void	xfs_trans_mod_dquot(xfs_trans_t *, xfs_dquot_t *, uint, long);
> -extern int	xfs_trans_reserve_quota_bydquots(xfs_trans_t *, xfs_mount_t *,
> -			xfs_dquot_t *, xfs_dquot_t *, long, long, uint);
> -extern void	xfs_trans_dqjoin(xfs_trans_t *, xfs_dquot_t *);
> -extern void	xfs_trans_log_dquot(xfs_trans_t *, xfs_dquot_t *);
> +extern void	xfs_trans_mod_dquot(xfs_trans_t *, struct xfs_dquot *, uint, long);
> +extern void	xfs_trans_dqjoin(xfs_trans_t *, struct xfs_dquot *);
> +extern void	xfs_trans_log_dquot(xfs_trans_t *, struct xfs_dquot *);
>  
>  /*
> - * We keep the usr and grp dquots separately so that locking will be easier
> - * to do at commit time. All transactions that we know of at this point
> + * We keep the usr, grp, and prj dquots separately so that locking will be
> + * easier to do at commit time. All transactions that we know of at this point
>   * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value.
>   */
> +enum {
> +	XFS_QM_TRANS_USR = 0,
> +	XFS_QM_TRANS_GRP,
> +	XFS_QM_TRANS_PROJ,
> +	XFS_QM_TRANS_DQTYPES
> +};
>  #define XFS_QM_TRANS_MAXDQS		2
> -typedef struct xfs_dquot_acct {
> -	xfs_dqtrx_t	dqa_usrdquots[XFS_QM_TRANS_MAXDQS];
> -	xfs_dqtrx_t	dqa_grpdquots[XFS_QM_TRANS_MAXDQS];
> -} xfs_dquot_acct_t;
> +struct xfs_dquot_acct {
> +	struct xfs_dqtrx dqs[XFS_QM_TRANS_DQTYPES][XFS_QM_TRANS_MAXDQS];
> +};
>  
>  /*
>   * Users are allowed to have a usage exceeding their softlimit for
> diff --git a/fs/xfs/xfs_qm_bhv.c b/fs/xfs/xfs_qm_bhv.c
> index 2d02eac..72a4fdd 100644
> --- a/fs/xfs/xfs_qm_bhv.c
> +++ b/fs/xfs/xfs_qm_bhv.c
> @@ -115,7 +115,7 @@ xfs_qm_newmount(
>  	     (pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
>  	    (!pquotaondisk &&  XFS_IS_PQUOTA_ON(mp)) ||
>  	     (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
> -	    (!gquotaondisk &&  XFS_IS_OQUOTA_ON(mp)))  &&
> +	    (!gquotaondisk &&  XFS_IS_GQUOTA_ON(mp)))  &&
>  	    xfs_dev_is_read_only(mp, "changing quota state")) {
>  		xfs_warn(mp, "please mount with%s%s%s%s.",
>  			(!quotaondisk ? "out quota" : ""),
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index f005f1d..9bec772 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -119,7 +119,8 @@ xfs_qm_scall_quotaoff(
>  		dqtype |= XFS_QMOPT_GQUOTA;
>  		flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
>  		inactivate_flags |= XFS_GQUOTA_ACTIVE;
> -	} else if (flags & XFS_PQUOTA_ACCT) {
> +	}
> +	if (flags & XFS_PQUOTA_ACCT) {
>  		dqtype |= XFS_QMOPT_PQUOTA;
>  		flags |= (XFS_PQUOTA_CHKD | XFS_PQUOTA_ENFD);
>  		inactivate_flags |= XFS_PQUOTA_ACTIVE;
> @@ -214,10 +215,14 @@ xfs_qm_scall_quotaoff(
>  		IRELE(q->qi_uquotaip);
>  		q->qi_uquotaip = NULL;
>  	}
> -	if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && q->qi_gquotaip) {
> +	if ((dqtype & XFS_QMOPT_GQUOTA) && q->qi_gquotaip) {
>  		IRELE(q->qi_gquotaip);
>  		q->qi_gquotaip = NULL;
>  	}
> +	if ((dqtype & XFS_QMOPT_PQUOTA) && q->qi_pquotaip) {
> +		IRELE(q->qi_pquotaip);
> +		q->qi_pquotaip = NULL;
> +	}
>  
>  out_unlock:
>  	mutex_unlock(&q->qi_quotaofflock);
> @@ -853,9 +858,11 @@ xfs_dqrele_inode(
>  {
>  	/* skip quota inodes */
>  	if (ip == ip->i_mount->m_quotainfo->qi_uquotaip ||
> -	    ip == ip->i_mount->m_quotainfo->qi_gquotaip) {
> +	    ip == ip->i_mount->m_quotainfo->qi_gquotaip ||
> +	    ip == ip->i_mount->m_quotainfo->qi_pquotaip) {
>  		ASSERT(ip->i_udquot == NULL);
>  		ASSERT(ip->i_gdquot == NULL);
> +		ASSERT(ip->i_pdquot == NULL);
>  		return 0;
>  	}
>  
> @@ -864,10 +871,14 @@ xfs_dqrele_inode(
>  		xfs_qm_dqrele(ip->i_udquot);
>  		ip->i_udquot = NULL;
>  	}
> -	if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) && ip->i_gdquot) {
> +	if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) {
>  		xfs_qm_dqrele(ip->i_gdquot);
>  		ip->i_gdquot = NULL;
>  	}
> +	if ((flags & XFS_PQUOTA_ACCT) && ip->i_pdquot) {
> +		xfs_qm_dqrele(ip->i_pdquot);
> +		ip->i_pdquot = NULL;
> +	}
>  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
>  	return 0;
>  }
> diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
> index ccff1a6..fe46c0c 100644
> --- a/fs/xfs/xfs_quota.h
> +++ b/fs/xfs/xfs_quota.h
> @@ -272,10 +272,10 @@ typedef struct xfs_qoff_logformat {
>   * we didn't have the inode locked, the appropriate dquot(s) will be
>   * attached atomically.
>   */
> -#define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\
> -				     (ip)->i_udquot == NULL) || \
> -				    (XFS_IS_OQUOTA_ON(mp) && \
> -				     (ip)->i_gdquot == NULL))
> +#define XFS_NOT_DQATTACHED(mp, ip) \
> +	((XFS_IS_UQUOTA_ON(mp) && (ip)->i_udquot == NULL) || \
> +	 (XFS_IS_GQUOTA_ON(mp) && (ip)->i_gdquot == NULL) || \
> +	 (XFS_IS_PQUOTA_ON(mp) && (ip)->i_pdquot == NULL))
>  
>  #define XFS_QM_NEED_QUOTACHECK(mp) \
>  	((XFS_IS_UQUOTA_ON(mp) && \
> @@ -330,17 +330,18 @@ extern int xfs_trans_reserve_quota_nblks(struct xfs_trans *,
>  		struct xfs_inode *, long, long, uint);
>  extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *,
>  		struct xfs_mount *, struct xfs_dquot *,
> -		struct xfs_dquot *, long, long, uint);
> +		struct xfs_dquot *, struct xfs_dquot *, long, long, uint);
>  
>  extern int xfs_qm_vop_dqalloc(struct xfs_inode *, uid_t, gid_t, prid_t, uint,
> -		struct xfs_dquot **, struct xfs_dquot **);
> +		struct xfs_dquot **, struct xfs_dquot **, struct xfs_dquot **);
>  extern void xfs_qm_vop_create_dqattach(struct xfs_trans *, struct xfs_inode *,
> -		struct xfs_dquot *, struct xfs_dquot *);
> +		struct xfs_dquot *, struct xfs_dquot *, struct xfs_dquot *);
>  extern int xfs_qm_vop_rename_dqattach(struct xfs_inode **);
>  extern struct xfs_dquot *xfs_qm_vop_chown(struct xfs_trans *,
>  		struct xfs_inode *, struct xfs_dquot **, struct xfs_dquot *);
>  extern int xfs_qm_vop_chown_reserve(struct xfs_trans *, struct xfs_inode *,
> -		struct xfs_dquot *, struct xfs_dquot *, uint);
> +		struct xfs_dquot *, struct xfs_dquot *,
> +		struct xfs_dquot *, uint);
>  extern int xfs_qm_dqattach(struct xfs_inode *, uint);
>  extern int xfs_qm_dqattach_locked(struct xfs_inode *, uint);
>  extern void xfs_qm_dqdetach(struct xfs_inode *);
> @@ -354,10 +355,12 @@ extern void xfs_qm_unmount_quotas(struct xfs_mount *);
>  #else
>  static inline int
>  xfs_qm_vop_dqalloc(struct xfs_inode *ip, uid_t uid, gid_t gid, prid_t prid,
> -		uint flags, struct xfs_dquot **udqp, struct xfs_dquot **gdqp)
> +		uint flags, struct xfs_dquot **udqp, struct xfs_dquot **gdqp,
> +		struct xfs_dquot **pdqp)
>  {
>  	*udqp = NULL;
>  	*gdqp = NULL;
> +	*pdqp = NULL;
>  	return 0;
>  }
>  #define xfs_trans_dup_dqinfo(tp, tp2)
> @@ -372,14 +375,15 @@ static inline int xfs_trans_reserve_quota_nblks(struct xfs_trans *tp,
>  }
>  static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp,
>  		struct xfs_mount *mp, struct xfs_dquot *udqp,
> -		struct xfs_dquot *gdqp, long nblks, long nions, uint flags)
> +		struct xfs_dquot *gdqp, struct xfs_dquot *pdqp,
> +		long nblks, long nions, uint flags)
>  {
>  	return 0;
>  }
> -#define xfs_qm_vop_create_dqattach(tp, ip, u, g)
> +#define xfs_qm_vop_create_dqattach(tp, ip, u, g, p)
>  #define xfs_qm_vop_rename_dqattach(it)					(0)
>  #define xfs_qm_vop_chown(tp, ip, old, new)				(NULL)
> -#define xfs_qm_vop_chown_reserve(tp, ip, u, g, fl)			(0)
> +#define xfs_qm_vop_chown_reserve(tp, ip, u, g, p, fl)			(0)
>  #define xfs_qm_dqattach(ip, fl)						(0)
>  #define xfs_qm_dqattach_locked(ip, fl)					(0)
>  #define xfs_qm_dqdetach(ip)
> @@ -393,8 +397,8 @@ static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp,
>  
>  #define xfs_trans_unreserve_quota_nblks(tp, ip, nblks, ninos, flags) \
>  	xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), -(ninos), flags)
> -#define xfs_trans_reserve_quota(tp, mp, ud, gd, nb, ni, f) \
> -	xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, nb, ni, \
> +#define xfs_trans_reserve_quota(tp, mp, ud, gd, pd, nb, ni, f) \
> +	xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, pd, nb, ni, \
>  				f | XFS_QMOPT_RES_REGBLKS)
>  
>  extern int xfs_qm_dqcheck(struct xfs_mount *, xfs_disk_dquot_t *,
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index 873fa5a..5feac04 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -560,14 +560,13 @@ xfs_showargs(
>  	else if (mp->m_qflags & XFS_UQUOTA_ACCT)
>  		seq_puts(m, "," MNTOPT_UQUOTANOENF);
>  
> -	/* Either project or group quotas can be active, not both */
> -
>  	if (mp->m_qflags & XFS_PQUOTA_ACCT) {
>  		if (mp->m_qflags & XFS_PQUOTA_ENFD)
>  			seq_puts(m, "," MNTOPT_PRJQUOTA);
>  		else
>  			seq_puts(m, "," MNTOPT_PQUOTANOENF);
> -	} else if (mp->m_qflags & XFS_GQUOTA_ACCT) {
> +	}
> +	if (mp->m_qflags & XFS_GQUOTA_ACCT) {
>  		if (mp->m_qflags & XFS_GQUOTA_ENFD)
>  			seq_puts(m, "," MNTOPT_GRPQUOTA);
>  		else
> diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
> index 5f23438..d69e50a 100644
> --- a/fs/xfs/xfs_symlink.c
> +++ b/fs/xfs/xfs_symlink.c
> @@ -365,7 +365,9 @@ xfs_symlink(
>  	int			n;
>  	xfs_buf_t		*bp;
>  	prid_t			prid;
> -	struct xfs_dquot	*udqp, *gdqp;
> +	struct xfs_dquot	*udqp = NULL;
> +	struct xfs_dquot	*gdqp = NULL;
> +	struct xfs_dquot	*pdqp = NULL;
>  	uint			resblks;
>  
>  	*ipp = NULL;
> @@ -392,7 +394,7 @@ xfs_symlink(
>  	 * Make sure that we have allocated dquot(s) on disk.
>  	 */
>  	error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
> -			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
> +		XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp);
>  	if (error)
>  		goto std_return;
>  
> @@ -433,7 +435,8 @@ xfs_symlink(
>  	/*
>  	 * Reserve disk quota : blocks and inode.
>  	 */
> -	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
> +	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
> +						pdqp, resblks, 1, 0);
>  	if (error)
>  		goto error_return;
>  
> @@ -471,7 +474,7 @@ xfs_symlink(
>  	/*
>  	 * Also attach the dquot(s) to it, if applicable.
>  	 */
> -	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
> +	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
>  
>  	if (resblks)
>  		resblks -= XFS_IALLOC_SPACE_RES(mp);
> @@ -570,6 +573,7 @@ xfs_symlink(
>  	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
>  	xfs_qm_dqrele(udqp);
>  	xfs_qm_dqrele(gdqp);
> +	xfs_qm_dqrele(pdqp);
>  
>  	*ipp = ip;
>  	return 0;
> @@ -583,6 +587,7 @@ xfs_symlink(
>  	xfs_trans_cancel(tp, cancel_flags);
>  	xfs_qm_dqrele(udqp);
>  	xfs_qm_dqrele(gdqp);
> +	xfs_qm_dqrele(pdqp);
>  
>  	if (unlock_dp_on_error)
>  		xfs_iunlock(dp, XFS_ILOCK_EXCL);
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index 8cdbd62..2bbad13 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -103,8 +103,6 @@ xfs_trans_dup_dqinfo(
>  		return;
>  
>  	xfs_trans_alloc_dqinfo(ntp);
> -	oqa = otp->t_dqinfo->dqa_usrdquots;
> -	nqa = ntp->t_dqinfo->dqa_usrdquots;
>  
>  	/*
>  	 * Because the quota blk reservation is carried forward,
> @@ -113,7 +111,10 @@ xfs_trans_dup_dqinfo(
>  	if(otp->t_flags & XFS_TRANS_DQ_DIRTY)
>  		ntp->t_flags |= XFS_TRANS_DQ_DIRTY;
>  
> -	for (j = 0; j < 2; j++) {
> +	for (j = 0; j < XFS_QM_TRANS_DQTYPES; j++) {
> +		oqa = otp->t_dqinfo->dqs[j];
> +		nqa = ntp->t_dqinfo->dqs[j];
> +
>  		for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
>  			if (oqa[i].qt_dquot == NULL)
>  				break;
> @@ -138,8 +139,6 @@ xfs_trans_dup_dqinfo(
>  			oq->qt_ino_res = oq->qt_ino_res_used;
>  
>  		}
> -		oqa = otp->t_dqinfo->dqa_grpdquots;
> -		nqa = ntp->t_dqinfo->dqa_grpdquots;
>  	}
>  }
>  
> @@ -166,8 +165,10 @@ xfs_trans_mod_dquot_byino(
>  
>  	if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot)
>  		(void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta);
> -	if (XFS_IS_OQUOTA_ON(mp) && ip->i_gdquot)
> +	if (XFS_IS_GQUOTA_ON(mp) && ip->i_gdquot)
>  		(void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta);
> +	if (XFS_IS_PQUOTA_ON(mp) && ip->i_pdquot)
> +		(void) xfs_trans_mod_dquot(tp, ip->i_pdquot, field, delta);
>  }
>  
>  STATIC xfs_dqtrx_t *
> @@ -178,15 +179,20 @@ xfs_trans_get_dqtrx(
>  	int		i;
>  	xfs_dqtrx_t	*qa;
>  
> -	qa = XFS_QM_ISUDQ(dqp) ?
> -		tp->t_dqinfo->dqa_usrdquots : tp->t_dqinfo->dqa_grpdquots;
> +	if (XFS_QM_ISUDQ(dqp))
> +		qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_USR];
> +	else if (XFS_QM_ISGDQ(dqp))
> +		qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_GRP];
> +	else if (XFS_QM_ISPDQ(dqp))
> +		qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_PROJ];
> +	else
> +		return NULL;
>  
>  	for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
>  		if (qa[i].qt_dquot == NULL ||
>  		    qa[i].qt_dquot == dqp)
>  			return &qa[i];
>  	}
> -
>  	return NULL;
>  }
>  
> @@ -339,12 +345,10 @@ xfs_trans_apply_dquot_deltas(
>  		return;
>  
>  	ASSERT(tp->t_dqinfo);
> -	qa = tp->t_dqinfo->dqa_usrdquots;
> -	for (j = 0; j < 2; j++) {
> -		if (qa[0].qt_dquot == NULL) {
> -			qa = tp->t_dqinfo->dqa_grpdquots;
> +	for (j = 0; j < XFS_QM_TRANS_DQTYPES; j++) {
> +		qa = tp->t_dqinfo->dqs[j];
> +		if (qa[0].qt_dquot == NULL)
>  			continue;
> -		}
>  
>  		/*
>  		 * Lock all of the dquots and join them to the transaction.
> @@ -495,10 +499,6 @@ xfs_trans_apply_dquot_deltas(
>  			ASSERT(dqp->q_res_rtbcount >=
>  				be64_to_cpu(dqp->q_core.d_rtbcount));
>  		}
> -		/*
> -		 * Do the group quotas next
> -		 */
> -		qa = tp->t_dqinfo->dqa_grpdquots;
>  	}
>  }
>  
> @@ -521,9 +521,10 @@ xfs_trans_unreserve_and_mod_dquots(
>  	if (!tp->t_dqinfo || !(tp->t_flags & XFS_TRANS_DQ_DIRTY))
>  		return;
>  
> -	qa = tp->t_dqinfo->dqa_usrdquots;
>  
> -	for (j = 0; j < 2; j++) {
> +	for (j = 0; j < XFS_QM_TRANS_DQTYPES; j++) {
> +		qa = tp->t_dqinfo->dqs[j];
> +
>  		for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
>  			qtrx = &qa[i];
>  			/*
> @@ -565,7 +566,6 @@ xfs_trans_unreserve_and_mod_dquots(
>  				xfs_dqunlock(dqp);
>  
>  		}
> -		qa = tp->t_dqinfo->dqa_grpdquots;
>  	}
>  }
>  
> @@ -736,8 +736,8 @@ error_return:
>  
>  /*
>   * 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/prj quotas is important, because this follows a both-or-nothing
> + * The fact that this does the reservation against user, group and
> + * project quotas is important, because this follows a all-or-nothing
>   * approach.
>   *
>   * flags = XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
> @@ -748,15 +748,16 @@ error_return:
>   */
>  int
>  xfs_trans_reserve_quota_bydquots(
> -	xfs_trans_t	*tp,
> -	xfs_mount_t	*mp,
> -	xfs_dquot_t	*udqp,
> -	xfs_dquot_t	*gdqp,
> -	long		nblks,
> -	long		ninos,
> -	uint		flags)
> +	struct xfs_trans	*tp,
> +	struct xfs_mount	*mp,
> +	struct xfs_dquot	*udqp,
> +	struct xfs_dquot	*gdqp,
> +	struct xfs_dquot	*pdqp,
> +	long			nblks,
> +	long			ninos,
> +	uint			flags)
>  {
> -	int		resvd = 0, error;
> +	int	error;
>  
>  	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
>  		return 0;
> @@ -771,28 +772,34 @@ xfs_trans_reserve_quota_bydquots(
>  					(flags & ~XFS_QMOPT_ENOSPC));
>  		if (error)
>  			return error;
> -		resvd = 1;
>  	}
>  
>  	if (gdqp) {
>  		error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags);
> -		if (error) {
> -			/*
> -			 * can't do it, so backout previous reservation
> -			 */
> -			if (resvd) {
> -				flags |= XFS_QMOPT_FORCE_RES;
> -				xfs_trans_dqresv(tp, mp, udqp,
> -						 -nblks, -ninos, flags);
> -			}
> -			return error;
> -		}
> +		if (error)
> +			goto unwind_usr;
> +	}
> +
> +	if (pdqp) {
> +		error = xfs_trans_dqresv(tp, mp, pdqp, nblks, ninos, flags);
> +		if (error)
> +			goto unwind_grp;
>  	}
>  
>  	/*
>  	 * Didn't change anything critical, so, no need to log
>  	 */
>  	return 0;
> +
> +unwind_grp:
> +	flags |= XFS_QMOPT_FORCE_RES;
> +	if (gdqp)
> +		xfs_trans_dqresv(tp, mp, gdqp, -nblks, -ninos, flags);
> +unwind_usr:
> +	flags |= XFS_QMOPT_FORCE_RES;
> +	if (udqp)
> +		xfs_trans_dqresv(tp, mp, udqp, -nblks, -ninos, flags);
> +	return error;
>  }
>  
>  
> @@ -830,6 +837,7 @@ xfs_trans_reserve_quota_nblks(
>  	 */
>  	return xfs_trans_reserve_quota_bydquots(tp, mp,
>  						ip->i_udquot, ip->i_gdquot,
> +						ip->i_pdquot,
>  						nblks, ninos, flags);
>  }
>  
> diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
> index 1501f4f..cd0d133 100644
> --- a/fs/xfs/xfs_vnodeops.c
> +++ b/fs/xfs/xfs_vnodeops.c
> @@ -498,6 +498,7 @@ xfs_create(
>  	prid_t			prid;
>  	struct xfs_dquot	*udqp = NULL;
>  	struct xfs_dquot	*gdqp = NULL;
> +	struct xfs_dquot	*pdqp = NULL;
>  	uint			resblks;
>  	uint			log_res;
>  	uint			log_count;
> @@ -516,7 +517,7 @@ xfs_create(
>  	 * Make sure that we have allocated dquot(s) on disk.
>  	 */
>  	error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
> -			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
> +		XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp);
>  	if (error)
>  		return error;
>  
> @@ -568,7 +569,8 @@ xfs_create(
>  	/*
>  	 * Reserve disk quota and the inode.
>  	 */
> -	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
> +	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
> +						pdqp, resblks, 1, 0);
>  	if (error)
>  		goto out_trans_cancel;
>  
> @@ -632,7 +634,7 @@ xfs_create(
>  	 * These ids of the inode couldn't have changed since the new
>  	 * inode has been locked ever since it was created.
>  	 */
> -	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
> +	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
>  
>  	error = xfs_bmap_finish(&tp, &free_list, &committed);
>  	if (error)
> @@ -644,6 +646,7 @@ xfs_create(
>  
>  	xfs_qm_dqrele(udqp);
>  	xfs_qm_dqrele(gdqp);
> +	xfs_qm_dqrele(pdqp);
>  
>  	*ipp = ip;
>  	return 0;
> @@ -665,6 +668,7 @@ xfs_create(
>  
>  	xfs_qm_dqrele(udqp);
>  	xfs_qm_dqrele(gdqp);
> +	xfs_qm_dqrele(pdqp);
>  
>  	if (unlock_dp_on_error)
>  		xfs_iunlock(dp, XFS_ILOCK_EXCL);
> @@ -1577,7 +1581,7 @@ xfs_free_file_space(
>  		}
>  		xfs_ilock(ip, XFS_ILOCK_EXCL);
>  		error = xfs_trans_reserve_quota(tp, mp,
> -				ip->i_udquot, ip->i_gdquot,
> +				ip->i_udquot, ip->i_gdquot, ip->i_pdquot,
>  				resblks, 0, XFS_QMOPT_RES_REGBLKS);
>  		if (error)
>  			goto error1;
> 
Thanks,
-Jeff

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 3/5] xfs: Start using pquotaino from the superblock
  2013-05-10 21:21 ` [PATCH v8 3/5] xfs: Start using pquotaino from the superblock Chandra Seetharaman
@ 2013-05-13  4:24   ` Jeff Liu
  2013-05-17  4:46   ` Dave Chinner
  1 sibling, 0 replies; 29+ messages in thread
From: Jeff Liu @ 2013-05-13  4:24 UTC (permalink / raw)
  To: Chandra Seetharaman; +Cc: xfs

On 05/11/2013 05:21 AM, Chandra Seetharaman wrote:
> Define a macro to check if the superblock has pquotino.
> 
> Keep backward compatibilty by alowing mount of older superblock
> with no separate pquota inode.
> ---
>  fs/xfs/xfs_itable.c            |    3 +-
>  fs/xfs/xfs_mount.c             |  117 ++++++++++++++++++++++++++++++----------
>  fs/xfs/xfs_qm.c                |   29 +++++-----
>  fs/xfs/xfs_qm_syscalls.c       |   32 +++++++++---
>  fs/xfs/xfs_quota.h             |    8 ---
>  fs/xfs/xfs_sb.h                |    5 ++
>  fs/xfs/xfs_super.c             |   14 +++--
>  fs/xfs/xfs_trans_dquot.c       |    4 +-
>  include/uapi/linux/dqblk_xfs.h |    1 +
>  9 files changed, 148 insertions(+), 65 deletions(-)
> 
> diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
> index 2ea7d40..d80d58c 100644
> --- a/fs/xfs/xfs_itable.c
> +++ b/fs/xfs/xfs_itable.c
> @@ -43,7 +43,8 @@ xfs_internal_inum(
>  {
>  	return (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
>  		(xfs_sb_version_hasquota(&mp->m_sb) &&
> -		 (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino)));
> +		 (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino ||
> +		  ino == mp->m_sb.sb_pquotino)));
>  }
>  
>  /*
> diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> index 1b79906..233f88e 100644
> --- a/fs/xfs/xfs_mount.c
> +++ b/fs/xfs/xfs_mount.c
> @@ -601,21 +601,6 @@ xfs_sb_from_disk(
>  	to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
>  	to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
>  	to->sb_qflags = be16_to_cpu(from->sb_qflags);
> -	if ((to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) &&
> -			(to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> -				XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))) {
> -		xfs_notice(NULL, "Super block has XFS_OQUOTA bits along with "
> -		    "XFS_PQUOTA and/or XFS_GQUOTA bits. Quota check forced.\n");
> -		force_quota_check = true;
> -	}
> -	if (to->sb_qflags & XFS_OQUOTA_ENFD)
> -		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> -					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
> -	if (to->sb_qflags & XFS_OQUOTA_CHKD)
> -		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> -					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
> -	to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> -
>  	to->sb_flags = from->sb_flags;
>  	to->sb_shared_vn = from->sb_shared_vn;
>  	to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
> @@ -636,6 +621,44 @@ xfs_sb_from_disk(
>  	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
>  	to->sb_lsn = be64_to_cpu(from->sb_lsn);
>  
> +	if (xfs_sb_version_has_pquota(to)) {
> +		if (to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) {
> +			xfs_notice(NULL, "Super block has XFS_OQUOTA bits "
> +			"with version PQUOTINO. Quota check forced.\n");
> +			to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> +			force_quota_check = true;
> +		}
> +		to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
> +	} else {
> +		if (to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> +					XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) {
> +			xfs_notice(NULL, "Super block has XFS_[G|P]UOTA "
> +				"bits in version older than PQUOTINO. "
> +				"Quota check forced.\n");
> +
> +			to->sb_qflags &= ~(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> +					XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD);
> +			force_quota_check = true;
> +		}
> +
> +		/*
> +		 * On disk superblock qflags uses XFS_OQUOTA.* to support
> +		 * either PQUOTA or GQUOTA. But, in memory qflags uses
> +		 * XFS_PQUOTA.* or XFS_GQUOTA.* depending on which quota
> +		 * is used.
> +		 * Following block translates XFS_OQUOTA.* to either
> +		 * GQUOTA or PQUOTA.
> +		 */
> +		if (to->sb_qflags & XFS_OQUOTA_ENFD)
> +			to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> +					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
> +		if (to->sb_qflags & XFS_OQUOTA_CHKD)
> +			to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> +					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
> +		to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> +
> +	}
> +
>  	if (force_quota_check)
>  		to->sb_qflags &= ~(XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD);
>  }
> @@ -657,27 +680,51 @@ xfs_sb_to_disk(
>  	int		first;
>  	int		size;
>  	__uint16_t	qflags = from->sb_qflags;
> +	xfs_ino_t	gquotino = from->sb_gquotino;
>  
>  	ASSERT(fields);
>  	if (!fields)
>  		return;
>  
> -	if (fields & XFS_SB_QFLAGS) {
> +	if (!xfs_sb_version_has_pquota(from)) {
> +		if (fields & XFS_SB_QFLAGS) {
> +			/*
> +			 * The in-core version of sb_qflags do not have
> +			 * XFS_OQUOTA_* flags, whereas the on-disk version
> +			 * does.  So, convert incore XFS_{PG}QUOTA_* flags
> +			 * to on-disk XFS_OQUOTA_* flags.
> +			 */
> +			qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
> +					XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
> +
> +			if (from->sb_qflags &
> +					(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
> +				qflags |= XFS_OQUOTA_ENFD;
> +			if (from->sb_qflags &
> +					(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
> +				qflags |= XFS_OQUOTA_CHKD;
> +		}
> +
>  		/*
> -		 * The in-core version of sb_qflags do not have
> -		 * XFS_OQUOTA_* flags, whereas the on-disk version
> -		 * does.  So, convert incore XFS_{PG}QUOTA_* flags 
> -		 * to on-disk XFS_OQUOTA_* flags.
> +		 * On-disk version earlier than pquota doesn't have
> +		 * sb_pquotino. so, we need to copy the value to gquotino.
>  		 */
> -		qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
> -				XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
> +		if (fields & XFS_SB_PQUOTINO) {
> +			fields &= (__int64_t)~XFS_SB_PQUOTINO;
> +			fields |= (__int64_t)XFS_SB_GQUOTINO;
> +			gquotino = from->sb_pquotino;
> +		}
>  
> -		if (from->sb_qflags &
> -				(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
> -			qflags |= XFS_OQUOTA_ENFD;
> -		if (from->sb_qflags &
> -				(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
> -			qflags |= XFS_OQUOTA_CHKD;
> +		/* If any quota inodes are written, write all quota inodes */
> +		if (fields & (XFS_SB_UQUOTINO|XFS_SB_GQUOTINO))
> +			fields |= (XFS_SB_UQUOTINO|XFS_SB_GQUOTINO);
> +
> +	} else {
> +		/* If any quota inodes are written, write all quota inodes */
> +		if (fields & (XFS_SB_UQUOTINO | XFS_SB_GQUOTINO
> +							| XFS_SB_PQUOTINO))
> +			fields |= (XFS_SB_UQUOTINO | XFS_SB_GQUOTINO
> +							| XFS_SB_PQUOTINO);
>  	}
>  
>  	while (fields) {
> @@ -691,6 +738,8 @@ xfs_sb_to_disk(
>  			memcpy(to_ptr + first, from_ptr + first, size);
>  		} else if (f == XFS_SBS_QFLAGS) {
>  			*(__be16 *)(to_ptr + first) = cpu_to_be16(qflags);
> +		} else if (f == XFS_SBS_GQUOTINO) {
> +			*(__be64 *)(to_ptr + first) = cpu_to_be64(gquotino);
>  		} else {
>  			switch (size) {
>  			case 2:
> @@ -872,6 +921,18 @@ reread:
>  	 */
>  	xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
>  
> +	if (!xfs_sb_version_has_pquota(&mp->m_sb) && XFS_IS_PQUOTA_ON(mp)) {
> +		/*
> +		 * On disk superblock only has sb_gquotino, and in memory
> +		 * superblock has both sb_gquotino and sb_pquotino. But,
> +		 * only one them is supported at any point of time.
> +		 * So, if PQUOTA is set in disk superblock, copy over
> +		 * sb_gquotino to sb_pquotino.
> +		 */
> +		mp->m_sb.sb_pquotino = mp->m_sb.sb_gquotino;
> +		mp->m_sb.sb_gquotino = NULLFSINO;
> +	}
> +
>  	/*
>  	 * We must be able to do sector-sized and sector-aligned IO.
>  	 */
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index 97912cb..41ccc3c 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -516,7 +516,8 @@ xfs_qm_need_dqattach(
>  	if (!XFS_NOT_DQATTACHED(mp, ip))
>  		return false;
>  	if (ip->i_ino == mp->m_sb.sb_uquotino ||
> -	    ip->i_ino == mp->m_sb.sb_gquotino)
> +	    ip->i_ino == mp->m_sb.sb_gquotino ||
> +	    ip->i_ino == mp->m_sb.sb_pquotino)
>  		return false;
>  	return true;
>  }
> @@ -651,6 +652,7 @@ xfs_qm_dqdetach(
>  
>  	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino);
>  	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino);
> +	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_pquotino);
>  	if (ip->i_udquot) {
>  		xfs_qm_dqrele(ip->i_udquot);
>  		ip->i_udquot = NULL;
> @@ -858,22 +860,21 @@ xfs_qm_qino_alloc(
>  	spin_lock(&mp->m_sb_lock);
>  	if (flags & XFS_QMOPT_SBVERSION) {
>  		ASSERT(!xfs_sb_version_hasquota(&mp->m_sb));
> -		ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
> -				   XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) ==
> -		       (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
> -			XFS_SB_GQUOTINO | XFS_SB_QFLAGS));
>  
>  		xfs_sb_version_addquota(&mp->m_sb);
>  		mp->m_sb.sb_uquotino = NULLFSINO;
>  		mp->m_sb.sb_gquotino = NULLFSINO;
> +		mp->m_sb.sb_pquotino = NULLFSINO;
>  
>  		/* qflags will get updated _after_ quotacheck */
>  		mp->m_sb.sb_qflags = 0;
>  	}
>  	if (flags & XFS_QMOPT_UQUOTA)
>  		mp->m_sb.sb_uquotino = (*ip)->i_ino;
> -	else
> +	else if (flags & XFS_QMOPT_GQUOTA)
>  		mp->m_sb.sb_gquotino = (*ip)->i_ino;
> +	else
> +		mp->m_sb.sb_pquotino = (*ip)->i_ino;
>  	spin_unlock(&mp->m_sb_lock);
>  	xfs_mod_sb(tp, sbfields);
>  
> @@ -1185,7 +1186,9 @@ xfs_qm_dqusage_adjust(
>  	 * rootino must have its resources accounted for, not so with the quota
>  	 * inodes.
>  	 */
> -	if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
> +	if (ino == mp->m_sb.sb_uquotino ||
> +	    ino == mp->m_sb.sb_gquotino ||
> +	    ino == mp->m_sb.sb_pquotino) {
>  		*res = BULKSTAT_RV_NOTHING;
>  		return XFS_ERROR(EINVAL);
>  	}
> @@ -1466,19 +1469,17 @@ xfs_qm_init_quotainos(
>  			if (error)
>  				goto error_rele;
>  		}
> -		/* Use sb_gquotino for now */
>  		if (XFS_IS_PQUOTA_ON(mp) &&
> -		    mp->m_sb.sb_gquotino != NULLFSINO) {
> -			ASSERT(mp->m_sb.sb_gquotino > 0);
> -			error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
> +		    mp->m_sb.sb_pquotino != NULLFSINO) {
> +			ASSERT(mp->m_sb.sb_pquotino > 0);
> +			error = xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
>  					     0, 0, &pip);
>  			if (error)
>  				goto error_rele;
>  		}
>  	} else {
>  		flags |= XFS_QMOPT_SBVERSION;
> -		sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
> -			    XFS_SB_GQUOTINO | XFS_SB_QFLAGS);
> +		sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_QFLAGS);
>  	}
>  
>  	/*
> @@ -1505,7 +1506,7 @@ xfs_qm_init_quotainos(
>  	}
>  	if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
>  		error = xfs_qm_qino_alloc(mp, &pip,
> -					     sbflags | XFS_SB_GQUOTINO,
> +					     sbflags | XFS_SB_PQUOTINO,
>  					     flags | XFS_QMOPT_PQUOTA);
>  		if (error)
>  			goto error_rele;
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index 9bec772..65c0a7d 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -201,8 +201,7 @@ xfs_qm_scall_quotaoff(
>  	/*
>  	 * If quotas is completely disabled, close shop.
>  	 */
> -	if (((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET1) ||
> -	    ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET2)) {
> +	if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) {
>  		mutex_unlock(&q->qi_quotaofflock);
>  		xfs_qm_destroy_quotainfo(mp);
>  		return (0);
> @@ -297,8 +296,10 @@ xfs_qm_scall_trunc_qfiles(
>  
>  	if (flags & XFS_DQ_USER)
>  		error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_uquotino);
> -	if (flags & (XFS_DQ_GROUP|XFS_DQ_PROJ))
> +	if (flags & XFS_DQ_GROUP)
>  		error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_gquotino);
> +	if (flags & XFS_DQ_PROJ)
> +		error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_pquotino);
If remove the space used by both group and project quota all failed, the first
error will be hidden.
Actually, I'm confused to compare the code logical between the kernel and the
user space even without this feature. i.e.  xfsprogs/quota/state.c->remove_extents():

        if (type & XFS_USER_QUOTA) {
                if (remove_qtype_extents(dir, XFS_USER_QUOTA) < 0)
                        return;
		       ^^^^^^^^ <-- So we will return and won't continue to deal with
	other quota types.  However, in kernel part, we deal with those types all at once.
        }
        if (type & XFS_GROUP_QUOTA) {
                if (remove_qtype_extents(dir, XFS_GROUP_QUOTA) < 0)
                        return;
        } else if (type & XFS_PROJ_QUOTA) {
                if (remove_qtype_extents(dir, XFS_PROJ_QUOTA) < 0)
                        return;
        }


>  
>  	return error ? error : error2;
>  }
> @@ -412,17 +413,20 @@ xfs_qm_scall_getqstat(
>  	struct fs_quota_stat	*out)
>  {
>  	struct xfs_quotainfo	*q = mp->m_quotainfo;
> -	struct xfs_inode	*uip, *gip;
> -	bool                    tempuqip, tempgqip;
> +	struct xfs_inode	*uip = NULL;
> +	struct xfs_inode	*gip = NULL;
> +	struct xfs_inode	*pip = NULL;
> +	bool                    tempuqip = false;
> +	bool                    tempgqip = false;
> +	bool                    temppqip = false;
>  
> -	uip = gip = NULL;
> -	tempuqip = tempgqip = false;
>  	memset(out, 0, sizeof(fs_quota_stat_t));
>  
>  	out->qs_version = FS_QSTAT_VERSION;
>  	if (!xfs_sb_version_hasquota(&mp->m_sb)) {
>  		out->qs_uquota.qfs_ino = NULLFSINO;
>  		out->qs_gquota.qfs_ino = NULLFSINO;
> +		out->qs_pquota.qfs_ino = NULLFSINO;
>  		return (0);
>  	}
>  	out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
> @@ -431,10 +435,13 @@ xfs_qm_scall_getqstat(
>  	out->qs_pad = 0;
>  	out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
>  	out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
> +	if (&out->qs_gquota != &out->qs_pquota)
> +		out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino;
>  
>  	if (q) {
>  		uip = q->qi_uquotaip;
>  		gip = q->qi_gquotaip;
> +		pip = q->qi_pquotaip;
>  	}
>  	if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
>  		if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
> @@ -446,6 +453,11 @@ xfs_qm_scall_getqstat(
>  					0, 0, &gip) == 0)
>  			tempgqip = true;
>  	}
> +	if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) {
> +		if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
> +					0, 0, &pip) == 0)
> +			temppqip = true;
> +	}
>  	if (uip) {
>  		out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
>  		out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
> @@ -458,6 +470,12 @@ xfs_qm_scall_getqstat(
>  		if (tempgqip)
>  			IRELE(gip);
>  	}
> +	if (pip) {
> +		out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks;
> +		out->qs_pquota.qfs_nextents = pip->i_d.di_nextents;
> +		if (temppqip)
> +			IRELE(pip);
> +	}
>  	if (q) {
>  		out->qs_incoredqs = q->qi_dquots;
>  		out->qs_btimelimit = q->qi_btimelimit;
> diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
> index fe46c0c..be51581 100644
> --- a/fs/xfs/xfs_quota.h
> +++ b/fs/xfs/xfs_quota.h
> @@ -285,14 +285,6 @@ typedef struct xfs_qoff_logformat {
>  	 (XFS_IS_PQUOTA_ON(mp) && \
>  		(mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD) == 0))
>  
> -#define XFS_MOUNT_QUOTA_SET1	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
> -				 XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
> -				 XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD)
> -
> -#define XFS_MOUNT_QUOTA_SET2	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
> -				 XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
> -				 XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD)
> -
>  #define XFS_MOUNT_QUOTA_ALL	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
>  				 XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
>  				 XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD|\
> diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h
> index 2de58a8..3745b73 100644
> --- a/fs/xfs/xfs_sb.h
> +++ b/fs/xfs/xfs_sb.h
> @@ -618,6 +618,11 @@ xfs_sb_has_incompat_log_feature(
>  	return (sbp->sb_features_log_incompat & feature) != 0;
>  }
>  
> +static inline int xfs_sb_version_has_pquota(xfs_sb_t *sbp)
> +{
> +	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
> +}
> +
>  /*
>   * end of superblock version macros
>   */
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index 5feac04..01019d9 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -420,12 +420,6 @@ xfs_parseargs(
>  	}
>  #endif
>  
> -	if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
> -	    (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE))) {
> -		xfs_warn(mp, "cannot mount with both project and group quota");
> -		return EINVAL;
> -	}
> -
>  	if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
>  		xfs_warn(mp, "sunit and swidth must be specified together");
>  		return EINVAL;
> @@ -1388,6 +1382,14 @@ xfs_finish_flags(
>  		return XFS_ERROR(EROFS);
>  	}
>  
> +	if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
> +	    (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE)) &&
> +	    !xfs_sb_version_has_pquota(&mp->m_sb)) {
> +		xfs_warn(mp, "Super block does not support "
> +				 "project and group quota together");
I have been teached by Dave Chinner in another patch recently that it's better
to adjust the warning message to one line if possible.
> +		return XFS_ERROR(EINVAL);
> +	}
> +
>  	return 0;
>  }
>  
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index 2bbad13..fee905b 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -157,7 +157,8 @@ xfs_trans_mod_dquot_byino(
>  	if (!XFS_IS_QUOTA_RUNNING(mp) ||
>  	    !XFS_IS_QUOTA_ON(mp) ||
>  	    ip->i_ino == mp->m_sb.sb_uquotino ||
> -	    ip->i_ino == mp->m_sb.sb_gquotino)
> +	    ip->i_ino == mp->m_sb.sb_gquotino ||
> +	    ip->i_ino == mp->m_sb.sb_pquotino)
>  		return;
>  
>  	if (tp->t_dqinfo == NULL)
> @@ -825,6 +826,7 @@ xfs_trans_reserve_quota_nblks(
>  
>  	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_pquotino);
>  
>  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
>  	ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
> diff --git a/include/uapi/linux/dqblk_xfs.h b/include/uapi/linux/dqblk_xfs.h
> index 8655280..f17e3bb 100644
> --- a/include/uapi/linux/dqblk_xfs.h
> +++ b/include/uapi/linux/dqblk_xfs.h
> @@ -155,6 +155,7 @@ typedef struct fs_quota_stat {
>  	__s8		qs_pad;		/* unused */
>  	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
>  	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
> +#define qs_pquota	qs_gquota
>  	__u32		qs_incoredqs;	/* number of dquots incore */
>  	__s32		qs_btimelimit;  /* limit for blks timer */	
>  	__s32		qs_itimelimit;  /* limit for inodes timer */	
> 
Thanks,
-Jeff

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 4/5] xfs: Add proper versioning support to fs_quota_stat
  2013-05-10 21:21 ` [PATCH v8 4/5] xfs: Add proper versioning support to fs_quota_stat Chandra Seetharaman
@ 2013-05-13  4:29   ` Jeff Liu
  2013-05-17  5:10   ` Dave Chinner
  1 sibling, 0 replies; 29+ messages in thread
From: Jeff Liu @ 2013-05-13  4:29 UTC (permalink / raw)
  To: Chandra Seetharaman; +Cc: xfs

On 05/11/2013 05:21 AM, Chandra Seetharaman wrote:
> Added appropriate pads and code for backward compatibility.
> 
> Copied over the old version as it is different from the newer padded
> version.
> 
> New callers of the system call have to just set the version of the data
> structure being passed, and kernel will fill as much data as requested.
> 
> Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
> ---
>  fs/gfs2/quota.c                |    3 ---
>  fs/quota/quota.c               |   40 ++++++++++++++++++++++++++++++++++++++--
>  fs/xfs/xfs_qm_syscalls.c       |    4 ----
>  include/uapi/linux/dqblk_xfs.h |   38 ++++++++++++++++++++++++++++++++++++--
>  4 files changed, 74 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
> index c7c840e..ca0dccd 100644
> --- a/fs/gfs2/quota.c
> +++ b/fs/gfs2/quota.c
> @@ -1443,9 +1443,6 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
>  {
>  	struct gfs2_sbd *sdp = sb->s_fs_info;
>  
> -	memset(fqs, 0, sizeof(struct fs_quota_stat));
> -	fqs->qs_version = FS_QSTAT_VERSION;
> -
>  	switch (sdp->sd_args.ar_quota) {
>  	case GFS2_QUOTA_ON:
>  		fqs->qs_flags |= (FS_QUOTA_UDQ_ENFD | FS_QUOTA_GDQ_ENFD);
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index c7314f1..510464e 100644
> --- a/fs/quota/quota.c
> +++ b/fs/quota/quota.c
> @@ -207,12 +207,48 @@ static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
>  static int quota_getxstate(struct super_block *sb, void __user *addr)
>  {
>  	struct fs_quota_stat fqs;
> -	int ret;
> +	struct fs_quota_stat_v1 fqs_v1;
> +	int ret, size;
> +	void *cp = &fqs;
>  
>  	if (!sb->s_qcop->get_xstate)
>  		return -ENOSYS;
> +
> +	memset(&fqs, 0, sizeof(struct fs_quota_stat));
> +	if (copy_from_user(&fqs, addr, 1)) /* just get the version */
> +		return -EFAULT;
> +
> +	switch (fqs.qs_version) {
> +	case FS_QSTAT_VERSION_2:
> +		size = FS_QSTAT_V2_SIZE;
> +		break;
> +	default:
> +		fqs.qs_version = FS_QSTAT_VERSION;
> +		/* fallthrough */
> +	case FS_QSTAT_VERSION:
> +		size = FS_QSTAT_V1_SIZE;
> +		cp = &fqs_v1;
> +	}
> +
>  	ret = sb->s_qcop->get_xstate(sb, &fqs);
> -	if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
> +	if (ret)
> +		return ret;
> +
> +	if (fqs.qs_version == FS_QSTAT_VERSION) {
> +		fqs_v1.qs_version = fqs.qs_version;
> +		fqs_v1.qs_flags = fqs.qs_flags;
> +		fqs_v1.qs_pad = 0;
> +		fqs_v1.qs_uquota = fqs.qs_uquota;
> +		fqs_v1.qs_gquota = fqs.qs_gquota;
> +		fqs_v1.qs_incoredqs = fqs.qs_incoredqs;
> +		fqs_v1.qs_btimelimit = fqs.qs_btimelimit;
> +		fqs_v1.qs_itimelimit = fqs.qs_itimelimit;
> +		fqs_v1.qs_rtbtimelimit = fqs.qs_rtbtimelimit;
> +		fqs_v1.qs_bwarnlimit = fqs.qs_bwarnlimit;
> +		fqs_v1.qs_iwarnlimit = fqs.qs_iwarnlimit;
> +	}
> +
> +	if (copy_to_user(addr, &cp, size))
>  		return -EFAULT;
>  	return ret;
>  }
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index 65c0a7d..c27b0e4 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -420,9 +420,6 @@ xfs_qm_scall_getqstat(
>  	bool                    tempgqip = false;
>  	bool                    temppqip = false;
>  
> -	memset(out, 0, sizeof(fs_quota_stat_t));
> -
> -	out->qs_version = FS_QSTAT_VERSION;
>  	if (!xfs_sb_version_hasquota(&mp->m_sb)) {
>  		out->qs_uquota.qfs_ino = NULLFSINO;
>  		out->qs_gquota.qfs_ino = NULLFSINO;
> @@ -432,7 +429,6 @@ xfs_qm_scall_getqstat(
>  	out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
>  							(XFS_ALL_QUOTA_ACCT|
>  							 XFS_ALL_QUOTA_ENFD));
> -	out->qs_pad = 0;
>  	out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
>  	out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
>  	if (&out->qs_gquota != &out->qs_pquota)
> diff --git a/include/uapi/linux/dqblk_xfs.h b/include/uapi/linux/dqblk_xfs.h
> index f17e3bb..d9629c1 100644
> --- a/include/uapi/linux/dqblk_xfs.h
> +++ b/include/uapi/linux/dqblk_xfs.h
> @@ -18,6 +18,7 @@
>  #define _LINUX_DQBLK_XFS_H
>  
>  #include <linux/types.h>
> +#include <linux/stddef.h>
>  
>  /*
>   * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM).
> @@ -137,8 +138,12 @@ typedef struct fs_disk_quota {
>   * Provides a centralized way to get meta information about the quota subsystem.
>   * eg. space taken up for user and group quotas, number of dquots currently
>   * incore.
> + * User space caller should set qs_version to the appropriate version
> + * of the fs_quota_stat data structure they are providing. Not providing
> + * a version will be treated as FS_QSTAT_VERSION.
>   */
>  #define FS_QSTAT_VERSION	1	/* fs_quota_stat.qs_version */
> +#define FS_QSTAT_VERSION_2	2	/* new field qs_pquota */
>  
>  /*
>   * Some basic information about 'quota files'.
> @@ -149,19 +154,48 @@ typedef struct fs_qfilestat {
>  	__u32		qfs_nextents;	/* number of extents */
>  } fs_qfilestat_t;
>  
> +typedef struct fs_quota_stat_v1 {
> +	__s8		qs_version;	/* version number for future changes */
> +	__u16		qs_flags;	/* FS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
> +	__u8		qs_pad;		/* unused */
> +	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
> +	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
> +	__u32		qs_incoredqs;	/* number of dquots incore */
> +	__s32		qs_btimelimit;  /* limit for blks timer */	
> +	__s32		qs_itimelimit;  /* limit for inodes timer */	
> +	__s32		qs_rtbtimelimit;/* limit for rt blks timer */	
> +	__u16		qs_bwarnlimit;	/* limit for num warnings */
> +	__u16		qs_iwarnlimit;	/* limit for num warnings */
> +} fs_quota_stat_v1_t;
Dave has mentioned that we should not introduce typedef again. :-P.
> +
>  typedef struct fs_quota_stat {
>  	__s8		qs_version;	/* version number for future changes */
> +	__u8		qs_pad1;	/* unused */
>  	__u16		qs_flags;	/* FS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
> -	__s8		qs_pad;		/* unused */
> +	__u8		qs_pad2[4];	/* unused */
>  	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
>  	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
> -#define qs_pquota	qs_gquota
>  	__u32		qs_incoredqs;	/* number of dquots incore */
...
>  	__s32		qs_btimelimit;  /* limit for blks timer */	
>  	__s32		qs_itimelimit;  /* limit for inodes timer */	
>  	__s32		qs_rtbtimelimit;/* limit for rt blks timer */	
Found trailing whitespace for above three lines when applying this patch.
>  	__u16		qs_bwarnlimit;	/* limit for num warnings */
>  	__u16		qs_iwarnlimit;	/* limit for num warnings */
> +	__u8		qs_pad3[4];	/* unused */
> +	fs_qfilestat_t	qs_pquota;	/* project quota storage information */
> +	/* End of Data structure for FS_QSTAT_VERSION_2 */
>  } fs_quota_stat_t;
>  
> +/*
> + * Since Version 1 did not have padding at appropriate places,
> + * a new data structure has been defined for the older version to
> + * provide backward compatibility.
> + * Future extentions of this data structure won't require new
> + * data structure definitions as the current one can be extended
> + * with the logic and padding in place now.
> + */
> +#define FS_QSTAT_V1_SIZE	(sizeof(struct fs_quota_stat_v1))
> +#define FS_QSTAT_V2_SIZE	(offsetof(struct fs_quota_stat, qs_pquota) + \
> +					sizeof(fs_qfilestat_t))
> +
>  #endif	/* _LINUX_DQBLK_XFS_H */
> 
Thanks,
-Jeff

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 1/5] xfs: Remove incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD
  2013-05-13  3:15   ` Jeff Liu
@ 2013-05-14 22:19     ` Chandra Seetharaman
  0 siblings, 0 replies; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-14 22:19 UTC (permalink / raw)
  To: Jeff Liu; +Cc: xfs

Hi Jeff,

Thanks for the review.

I will fix them in my next (hopefully final :) version.

Chandra
On Mon, 2013-05-13 at 11:15 +0800, Jeff Liu wrote:
> Hi Chandra,
> 
> On 05/11/2013 05:21 AM, Chandra Seetharaman wrote:
> > Remove all incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD. Instead,
> > start using XFS_GQUOTA_.* XFS_PQUOTA_.* counterparts for GQUOTA and
> > PQUOTA respectively.
> > 
> > On-disk copy still uses XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD.
> > 
> > Read and write of the superblock does the conversion from *OQUOTA*
> > to *[PG]QUOTA*.
> > 
> > Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
> > Reviewed-by: Dave Chinner <dchinner@redhat.com>
> > ---
> >  fs/xfs/xfs_mount.c       |   41 +++++++++++++++++++++++++++++++++++++++++
> >  fs/xfs/xfs_qm.c          |    9 ++++++---
> >  fs/xfs/xfs_qm_syscalls.c |   39 +++++++++++++++++++++------------------
> >  fs/xfs/xfs_quota.h       |   42 ++++++++++++++++++++++++++++--------------
> >  fs/xfs/xfs_quotaops.c    |    6 ++++--
> >  fs/xfs/xfs_super.c       |   16 ++++++++--------
> >  fs/xfs/xfs_trans_dquot.c |    4 ++--
> >  7 files changed, 110 insertions(+), 47 deletions(-)
> > 
> > diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> > index f6bfbd7..1b79906 100644
> > --- a/fs/xfs/xfs_mount.c
> > +++ b/fs/xfs/xfs_mount.c
> > @@ -564,6 +564,8 @@ xfs_sb_from_disk(
> >  	struct xfs_sb	*to,
> >  	xfs_dsb_t	*from)
> >  {
> > +	bool force_quota_check = false;
> > +
> >  	to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
> >  	to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
> >  	to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
> > @@ -599,6 +601,21 @@ xfs_sb_from_disk(
> >  	to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
> >  	to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
> >  	to->sb_qflags = be16_to_cpu(from->sb_qflags);
> > +	if ((to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) &&
> > +			(to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> > +				XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))) {
> > +		xfs_notice(NULL, "Super block has XFS_OQUOTA bits along with "
> > +		    "XFS_PQUOTA and/or XFS_GQUOTA bits. Quota check forced.\n");
> > +		force_quota_check = true;
> > +	}
> > +	if (to->sb_qflags & XFS_OQUOTA_ENFD)
> > +		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> > +					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
> > +	if (to->sb_qflags & XFS_OQUOTA_CHKD)
> > +		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> > +					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
> > +	to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> > +
> >  	to->sb_flags = from->sb_flags;
> >  	to->sb_shared_vn = from->sb_shared_vn;
> >  	to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
> > @@ -618,6 +635,9 @@ xfs_sb_from_disk(
> >  	to->sb_pad = 0;
> >  	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
> >  	to->sb_lsn = be64_to_cpu(from->sb_lsn);
> > +
> > +	if (force_quota_check)
> > +		to->sb_qflags &= ~(XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD);
> >  }
> >  
> >  /*
> > @@ -636,11 +656,30 @@ xfs_sb_to_disk(
> >  	xfs_sb_field_t	f;
> >  	int		first;
> >  	int		size;
> > +	__uint16_t	qflags = from->sb_qflags;
> >  
> >  	ASSERT(fields);
> >  	if (!fields)
> >  		return;
> >  
> > +	if (fields & XFS_SB_QFLAGS) {
> > +		/*
> > +		 * The in-core version of sb_qflags do not have
> > +		 * XFS_OQUOTA_* flags, whereas the on-disk version
> > +		 * does.  So, convert incore XFS_{PG}QUOTA_* flags  
> A minor issue, above line end up with trailing whitespace.
> 
> Thanks,
> -Jeff
> > +		 * to on-disk XFS_OQUOTA_* flags.
> > +		 */
> > +		qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
> > +				XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
> > +
> > +		if (from->sb_qflags &
> > +				(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
> > +			qflags |= XFS_OQUOTA_ENFD;
> > +		if (from->sb_qflags &
> > +				(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
> > +			qflags |= XFS_OQUOTA_CHKD;
> > +	}
> > +
> >  	while (fields) {
> >  		f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
> >  		first = xfs_sb_info[f].offset;
> > @@ -650,6 +689,8 @@ xfs_sb_to_disk(
> >  
> >  		if (size == 1 || xfs_sb_info[f].type == 1) {
> >  			memcpy(to_ptr + first, from_ptr + first, size);
> > +		} else if (f == XFS_SBS_QFLAGS) {
> > +			*(__be16 *)(to_ptr + first) = cpu_to_be16(qflags);
> >  		} else {
> >  			switch (size) {
> >  			case 2:
> > diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> > index f41702b..fe4c743 100644
> > --- a/fs/xfs/xfs_qm.c
> > +++ b/fs/xfs/xfs_qm.c
> > @@ -298,8 +298,10 @@ xfs_qm_mount_quotas(
> >  	 */
> >  	if (!XFS_IS_UQUOTA_ON(mp))
> >  		mp->m_qflags &= ~XFS_UQUOTA_CHKD;
> > -	if (!(XFS_IS_GQUOTA_ON(mp) || XFS_IS_PQUOTA_ON(mp)))
> > -		mp->m_qflags &= ~XFS_OQUOTA_CHKD;
> > +	if (!XFS_IS_GQUOTA_ON(mp))
> > +		mp->m_qflags &= ~XFS_GQUOTA_CHKD;
> > +	if (!XFS_IS_PQUOTA_ON(mp))
> > +		mp->m_qflags &= ~XFS_PQUOTA_CHKD;
> >  
> >   write_changes:
> >  	/*
> > @@ -1280,7 +1282,8 @@ xfs_qm_quotacheck(
> >  					 &buffer_list);
> >  		if (error)
> >  			goto error_return;
> > -		flags |= XFS_OQUOTA_CHKD;
> > +		flags |= XFS_IS_GQUOTA_ON(mp) ?
> > +					XFS_GQUOTA_CHKD : XFS_PQUOTA_CHKD;
> >  	}
> >  
> >  	do {
> > diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> > index c41190c..f005f1d 100644
> > --- a/fs/xfs/xfs_qm_syscalls.c
> > +++ b/fs/xfs/xfs_qm_syscalls.c
> > @@ -117,11 +117,11 @@ xfs_qm_scall_quotaoff(
> >  	}
> >  	if (flags & XFS_GQUOTA_ACCT) {
> >  		dqtype |= XFS_QMOPT_GQUOTA;
> > -		flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
> > +		flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
> >  		inactivate_flags |= XFS_GQUOTA_ACTIVE;
> >  	} else if (flags & XFS_PQUOTA_ACCT) {
> >  		dqtype |= XFS_QMOPT_PQUOTA;
> > -		flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
> > +		flags |= (XFS_PQUOTA_CHKD | XFS_PQUOTA_ENFD);
> >  		inactivate_flags |= XFS_PQUOTA_ACTIVE;
> >  	}
> >  
> > @@ -335,14 +335,14 @@ xfs_qm_scall_quotaon(
> >  	 * quota acct on ondisk without m_qflags' knowing.
> >  	 */
> >  	if (((flags & XFS_UQUOTA_ACCT) == 0 &&
> > -	    (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
> > -	    (flags & XFS_UQUOTA_ENFD))
> > -	    ||
> > +	     (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
> > +	     (flags & XFS_UQUOTA_ENFD)) ||
> >  	    ((flags & XFS_PQUOTA_ACCT) == 0 &&
> > -	    (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
> > -	    (flags & XFS_GQUOTA_ACCT) == 0 &&
> > -	    (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
> > -	    (flags & XFS_OQUOTA_ENFD))) {
> > +	     (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
> > +	     (flags & XFS_PQUOTA_ENFD)) ||
> > +	    ((flags & XFS_GQUOTA_ACCT) == 0 &&
> > +	     (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
> > +	     (flags & XFS_GQUOTA_ENFD))) {
> >  		xfs_debug(mp,
> >  			"%s: Can't enforce without acct, flags=%x sbflags=%x\n",
> >  			__func__, flags, mp->m_sb.sb_qflags);
> > @@ -770,9 +770,12 @@ xfs_qm_scall_getquota(
> >  	 * gets turned off. No need to confuse the user level code,
> >  	 * so return zeroes in that case.
> >  	 */
> > -	if ((!XFS_IS_UQUOTA_ENFORCED(mp) && dqp->q_core.d_flags == XFS_DQ_USER) ||
> > -	    (!XFS_IS_OQUOTA_ENFORCED(mp) &&
> > -			(dqp->q_core.d_flags & (XFS_DQ_PROJ | XFS_DQ_GROUP)))) {
> > +	if ((!XFS_IS_UQUOTA_ENFORCED(mp) &&
> > +	     dqp->q_core.d_flags == XFS_DQ_USER) ||
> > +	    (!XFS_IS_PQUOTA_ENFORCED(mp) &&
> > +	     dqp->q_core.d_flags == XFS_DQ_PROJ) ||
> > +	    (!XFS_IS_GQUOTA_ENFORCED(mp) &&
> > +	     dqp->q_core.d_flags == XFS_DQ_GROUP)) {
> >  		dst->d_btimer = 0;
> >  		dst->d_itimer = 0;
> >  		dst->d_rtbtimer = 0;
> > @@ -780,8 +783,8 @@ xfs_qm_scall_getquota(
> >  
> >  #ifdef DEBUG
> >  	if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == FS_USER_QUOTA) ||
> > -	     (XFS_IS_OQUOTA_ENFORCED(mp) &&
> > -			(dst->d_flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)))) &&
> > +	     (XFS_IS_PQUOTA_ENFORCED(mp) && dst->d_flags == FS_PROJ_QUOTA) ||
> > +	     (XFS_IS_GQUOTA_ENFORCED(mp) && dst->d_flags == FS_GROUP_QUOTA)) &&
> >  	    dst->d_id != 0) {
> >  		if ((dst->d_bcount > dst->d_blk_softlimit) &&
> >  		    (dst->d_blk_softlimit > 0)) {
> > @@ -833,10 +836,10 @@ xfs_qm_export_flags(
> >  		uflags |= FS_QUOTA_GDQ_ACCT;
> >  	if (flags & XFS_UQUOTA_ENFD)
> >  		uflags |= FS_QUOTA_UDQ_ENFD;
> > -	if (flags & (XFS_OQUOTA_ENFD)) {
> > -		uflags |= (flags & XFS_GQUOTA_ACCT) ?
> > -			FS_QUOTA_GDQ_ENFD : FS_QUOTA_PDQ_ENFD;
> > -	}
> > +	if (flags & XFS_PQUOTA_ENFD)
> > +		uflags |= FS_QUOTA_PDQ_ENFD;
> > +	if (flags & XFS_GQUOTA_ENFD)
> > +		uflags |= FS_QUOTA_GDQ_ENFD;
> >  	return (uflags);
> >  }
> >  
> > diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
> > index c61e31c..ccff1a6 100644
> > --- a/fs/xfs/xfs_quota.h
> > +++ b/fs/xfs/xfs_quota.h
> > @@ -159,28 +159,43 @@ typedef struct xfs_qoff_logformat {
> >  #define XFS_GQUOTA_ACCT	0x0040  /* group quota accounting ON */
> >  
> >  /*
> > + * Start differentiating group quota and project quota in-core
> > + * using distinct flags, instead of using the combined OQUOTA flags.
> > + *
> > + * Conversion to and from the combined OQUOTA flag (if necessary)
> > + * is done only in xfs_sb_{to,from}_disk()
> > + */
> > +#define XFS_GQUOTA_ENFD	0x0080  /* group quota limits enforced */
> > +#define XFS_GQUOTA_CHKD	0x0100  /* quotacheck run on group quotas */
> > +#define XFS_PQUOTA_ENFD	0x0200  /* project quota limits enforced */
> > +#define XFS_PQUOTA_CHKD	0x0400  /* quotacheck run on project quotas */
> > +
> > +/*
> >   * Quota Accounting/Enforcement flags
> >   */
> >  #define XFS_ALL_QUOTA_ACCT	\
> >  		(XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT)
> > -#define XFS_ALL_QUOTA_ENFD	(XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD)
> > -#define XFS_ALL_QUOTA_CHKD	(XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD)
> > +#define XFS_ALL_QUOTA_ENFD	\
> > +		(XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD | XFS_PQUOTA_ENFD)
> > +#define XFS_ALL_QUOTA_CHKD	\
> > +		(XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD)
> >  
> >  #define XFS_IS_QUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
> >  #define XFS_IS_UQUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_UQUOTA_ACCT)
> >  #define XFS_IS_PQUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_PQUOTA_ACCT)
> >  #define XFS_IS_GQUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_GQUOTA_ACCT)
> >  #define XFS_IS_UQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_UQUOTA_ENFD)
> > -#define XFS_IS_OQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_OQUOTA_ENFD)
> > +#define XFS_IS_PQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_PQUOTA_ENFD)
> > +#define XFS_IS_GQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_GQUOTA_ENFD)
> >  
> >  /*
> >   * Incore only flags for quotaoff - these bits get cleared when quota(s)
> >   * are in the process of getting turned off. These flags are in m_qflags but
> >   * never in sb_qflags.
> >   */
> > -#define XFS_UQUOTA_ACTIVE	0x0100  /* uquotas are being turned off */
> > -#define XFS_PQUOTA_ACTIVE	0x0200  /* pquotas are being turned off */
> > -#define XFS_GQUOTA_ACTIVE	0x0400  /* gquotas are being turned off */
> > +#define XFS_UQUOTA_ACTIVE	0x1000  /* uquotas are being turned off */
> > +#define XFS_PQUOTA_ACTIVE	0x2000  /* pquotas are being turned off */
> > +#define XFS_GQUOTA_ACTIVE	0x4000  /* gquotas are being turned off */
> >  #define XFS_ALL_QUOTA_ACTIVE	\
> >  	(XFS_UQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE)
> >  
> > @@ -266,24 +281,23 @@ typedef struct xfs_qoff_logformat {
> >  	((XFS_IS_UQUOTA_ON(mp) && \
> >  		(mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD) == 0) || \
> >  	 (XFS_IS_GQUOTA_ON(mp) && \
> > -		((mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD) == 0 || \
> > -		 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT))) || \
> > +		(mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD) == 0) || \
> >  	 (XFS_IS_PQUOTA_ON(mp) && \
> > -		((mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD) == 0 || \
> > -		 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT))))
> > +		(mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD) == 0))
> >  
> >  #define XFS_MOUNT_QUOTA_SET1	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
> >  				 XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
> > -				 XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD)
> > +				 XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD)
> >  
> >  #define XFS_MOUNT_QUOTA_SET2	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
> >  				 XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
> > -				 XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD)
> > +				 XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD)
> >  
> >  #define XFS_MOUNT_QUOTA_ALL	(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
> >  				 XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
> > -				 XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD|\
> > -				 XFS_GQUOTA_ACCT)
> > +				 XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD|\
> > +				 XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD|\
> > +				 XFS_GQUOTA_CHKD)
> >  
> >  
> >  /*
> > diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
> > index 71926d6..056d62e 100644
> > --- a/fs/xfs/xfs_quotaops.c
> > +++ b/fs/xfs/xfs_quotaops.c
> > @@ -75,8 +75,10 @@ xfs_fs_set_xstate(
> >  		flags |= XFS_GQUOTA_ACCT;
> >  	if (uflags & FS_QUOTA_UDQ_ENFD)
> >  		flags |= XFS_UQUOTA_ENFD;
> > -	if (uflags & (FS_QUOTA_PDQ_ENFD|FS_QUOTA_GDQ_ENFD))
> > -		flags |= XFS_OQUOTA_ENFD;
> > +	if (uflags & FS_QUOTA_PDQ_ENFD)
> > +		flags |= XFS_PQUOTA_ENFD;
> > +	if (uflags & FS_QUOTA_GDQ_ENFD)
> > +		flags |= XFS_GQUOTA_ENFD;
> >  
> >  	switch (op) {
> >  	case Q_XQUOTAON:
> > diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> > index ea341ce..873fa5a 100644
> > --- a/fs/xfs/xfs_super.c
> > +++ b/fs/xfs/xfs_super.c
> > @@ -359,17 +359,17 @@ xfs_parseargs(
> >  		} else if (!strcmp(this_char, MNTOPT_PQUOTA) ||
> >  			   !strcmp(this_char, MNTOPT_PRJQUOTA)) {
> >  			mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE |
> > -					 XFS_OQUOTA_ENFD);
> > +					 XFS_PQUOTA_ENFD);
> >  		} else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) {
> >  			mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE);
> > -			mp->m_qflags &= ~XFS_OQUOTA_ENFD;
> > +			mp->m_qflags &= ~XFS_PQUOTA_ENFD;
> >  		} else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
> >  			   !strcmp(this_char, MNTOPT_GRPQUOTA)) {
> >  			mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE |
> > -					 XFS_OQUOTA_ENFD);
> > +					 XFS_GQUOTA_ENFD);
> >  		} else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
> >  			mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
> > -			mp->m_qflags &= ~XFS_OQUOTA_ENFD;
> > +			mp->m_qflags &= ~XFS_GQUOTA_ENFD;
> >  		} else if (!strcmp(this_char, MNTOPT_DELAYLOG)) {
> >  			xfs_warn(mp,
> >  	"delaylog is the default now, option is deprecated.");
> > @@ -563,12 +563,12 @@ xfs_showargs(
> >  	/* Either project or group quotas can be active, not both */
> >  
> >  	if (mp->m_qflags & XFS_PQUOTA_ACCT) {
> > -		if (mp->m_qflags & XFS_OQUOTA_ENFD)
> > +		if (mp->m_qflags & XFS_PQUOTA_ENFD)
> >  			seq_puts(m, "," MNTOPT_PRJQUOTA);
> >  		else
> >  			seq_puts(m, "," MNTOPT_PQUOTANOENF);
> >  	} else if (mp->m_qflags & XFS_GQUOTA_ACCT) {
> > -		if (mp->m_qflags & XFS_OQUOTA_ENFD)
> > +		if (mp->m_qflags & XFS_GQUOTA_ENFD)
> >  			seq_puts(m, "," MNTOPT_GRPQUOTA);
> >  		else
> >  			seq_puts(m, "," MNTOPT_GQUOTANOENF);
> > @@ -1136,8 +1136,8 @@ xfs_fs_statfs(
> >  	spin_unlock(&mp->m_sb_lock);
> >  
> >  	if ((ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
> > -	    ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))) ==
> > -			      (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))
> > +	    ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))) ==
> > +			      (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))
> >  		xfs_qm_statvfs(ip, statp);
> >  	return 0;
> >  }
> > diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> > index fec75d0..8cdbd62 100644
> > --- a/fs/xfs/xfs_trans_dquot.c
> > +++ b/fs/xfs/xfs_trans_dquot.c
> > @@ -640,8 +640,8 @@ xfs_trans_dqresv(
> >  	if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
> >  	    dqp->q_core.d_id &&
> >  	    ((XFS_IS_UQUOTA_ENFORCED(dqp->q_mount) && XFS_QM_ISUDQ(dqp)) ||
> > -	     (XFS_IS_OQUOTA_ENFORCED(dqp->q_mount) &&
> > -	      (XFS_QM_ISPDQ(dqp) || XFS_QM_ISGDQ(dqp))))) {
> > +	     (XFS_IS_PQUOTA_ENFORCED(dqp->q_mount) && XFS_QM_ISPDQ(dqp)) ||
> > +	     (XFS_IS_GQUOTA_ENFORCED(dqp->q_mount) && XFS_QM_ISGDQ(dqp)))) {
> >  		if (nblks > 0) {
> >  			/*
> >  			 * dquot is locked already. See if we'd go over the
> > 
> 


_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 1/5] xfs: Remove incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD
  2013-05-10 21:21 ` [PATCH v8 1/5] xfs: Remove incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD Chandra Seetharaman
  2013-05-13  3:15   ` Jeff Liu
@ 2013-05-17  2:55   ` Dave Chinner
  2013-05-24 21:45     ` Chandra Seetharaman
  1 sibling, 1 reply; 29+ messages in thread
From: Dave Chinner @ 2013-05-17  2:55 UTC (permalink / raw)
  To: Chandra Seetharaman; +Cc: xfs

On Fri, May 10, 2013 at 04:21:25PM -0500, Chandra Seetharaman wrote:
> Remove all incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD. Instead,
> start using XFS_GQUOTA_.* XFS_PQUOTA_.* counterparts for GQUOTA and
> PQUOTA respectively.
> 
> On-disk copy still uses XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD.
> 
> Read and write of the superblock does the conversion from *OQUOTA*
> to *[PG]QUOTA*.
> 
> Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
> Reviewed-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/xfs_mount.c       |   41 +++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/xfs_qm.c          |    9 ++++++---
>  fs/xfs/xfs_qm_syscalls.c |   39 +++++++++++++++++++++------------------
>  fs/xfs/xfs_quota.h       |   42 ++++++++++++++++++++++++++++--------------
>  fs/xfs/xfs_quotaops.c    |    6 ++++--
>  fs/xfs/xfs_super.c       |   16 ++++++++--------
>  fs/xfs/xfs_trans_dquot.c |    4 ++--
>  7 files changed, 110 insertions(+), 47 deletions(-)
> 
> diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> index f6bfbd7..1b79906 100644
> --- a/fs/xfs/xfs_mount.c
> +++ b/fs/xfs/xfs_mount.c
> @@ -564,6 +564,8 @@ xfs_sb_from_disk(
>  	struct xfs_sb	*to,
>  	xfs_dsb_t	*from)
>  {
> +	bool force_quota_check = false;
> +
>  	to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
>  	to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
>  	to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
> @@ -599,6 +601,21 @@ xfs_sb_from_disk(
>  	to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
>  	to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
>  	to->sb_qflags = be16_to_cpu(from->sb_qflags);
> +	if ((to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) &&
> +			(to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> +				XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))) {
> +		xfs_notice(NULL, "Super block has XFS_OQUOTA bits along with "
> +		    "XFS_PQUOTA and/or XFS_GQUOTA bits. Quota check forced.\n");
> +		force_quota_check = true;
> +	}

We can't do these quota check manipulations to the superblock quota
flags during disk->incore translation anymore - there is more than
one place that converts the superblock from on-disk to incore format
(e.g.  the verification callbacks) and so emitting this message when
we are *writing* the superblock is not good.

Also, if the XFS_PQUOTA_CHKD/XFS_PQUOTA_ENFD flags are set and
the superblock is not a V5 superblock, then I think we should refuse
to mount the filesystem because that is an invalid state - those
flags should only be set now on a V5 superblock, and never at any
other time. Hence this specific check should probably be moved to
xfs_mount_validate_sb() and cause an EFSCORRUPTED return if it
fails. That will catch something setting the flags incorrectly (i.e.
at superblock write) as well as prevent mounting in this situation.

I know, this is different to what I've said in the past, but the
on-disk format checking is now a lot stricter and so I think that if
the filesystem is in some kind of wierd state we should just throw
an error and let the administrator work out how this problem
happened and how to resolve it.

> +	if (to->sb_qflags & XFS_OQUOTA_ENFD)
> +		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> +					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
> +	if (to->sb_qflags & XFS_OQUOTA_CHKD)
> +		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> +					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
> +	to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> +

This translation of the quota flags needs to be external to
this function, and then only called in the mount path where we are
initially setting up the in-core superblock (i.e. in xfs_readsb())
because that is the only place where the incore values are
permanently stored.

> @@ -636,11 +656,30 @@ xfs_sb_to_disk(
>  	xfs_sb_field_t	f;
>  	int		first;
>  	int		size;
> +	__uint16_t	qflags = from->sb_qflags;
>  
>  	ASSERT(fields);
>  	if (!fields)
>  		return;
>  
> +	if (fields & XFS_SB_QFLAGS) {
> +		/*
> +		 * The in-core version of sb_qflags do not have
> +		 * XFS_OQUOTA_* flags, whereas the on-disk version
> +		 * does.  So, convert incore XFS_{PG}QUOTA_* flags 
> +		 * to on-disk XFS_OQUOTA_* flags.
> +		 */
> +		qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
> +				XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
> +
> +		if (from->sb_qflags &
> +				(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
> +			qflags |= XFS_OQUOTA_ENFD;
> +		if (from->sb_qflags &
> +				(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
> +			qflags |= XFS_OQUOTA_CHKD;
> +	}

Given that we have a new superblock version, we can write the new
XFS_[PG]QUOTA_CHKD/XFS_[PG]QUOTA_ENFD flags directly into the
sb_qflags knowing that we can't get an older kernel to interpret
these new fields because they'll fail the superblck version test. So
that would mean we only need to do this translation for filesystems
for non-v5 superblock filesystems.

Ah, I see that in a later patch you introduce
xfs_sb_version_has_pquota() and modify this code path to do
something similar, and it becomes rather complex and nasty.

OK, I know this is a bit of work, but can you introduce
xfs_sb_version_has_pquota() in this patch (as we already have the
pquota inode defined in the on-disk format) as:

static inline int xfs_sb_version_haspquota(xfs_sb_t *sbp)
{
        return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
}

and make these OQUOTA flag translations dependent on this not being
set right from the start?

Also, given how nasty this manipulation ends up, can you push it out
into a function that is called from xfs_sb_to_disk(). That way
xfs_sb_to_disk() doesn't end up mostly being 70% quota field
manipulation code...


>  /*
> + * Start differentiating group quota and project quota in-core
> + * using distinct flags, instead of using the combined OQUOTA flags.
> + *
> + * Conversion to and from the combined OQUOTA flag (if necessary)
> + * is done only in xfs_sb_{to,from}_disk()
> + */
> +#define XFS_GQUOTA_ENFD	0x0080  /* group quota limits enforced */
> +#define XFS_GQUOTA_CHKD	0x0100  /* quotacheck run on group quotas */
> +#define XFS_PQUOTA_ENFD	0x0200  /* project quota limits enforced */
> +#define XFS_PQUOTA_CHKD	0x0400  /* quotacheck run on project quotas */

These become new on-disk fields for xfs_sb_version_haspquota()
filesystems, so they are not specifically in-core values.

Other than these to/from disk changes, the patch looks fine.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 2/5] xfs: Add pquota fields where gquota is used.
  2013-05-13  3:59   ` Jeff Liu
@ 2013-05-17  3:01     ` Dave Chinner
  2013-05-17  5:40       ` Jeff Liu
  2013-05-17 21:15     ` Chandra Seetharaman
  1 sibling, 1 reply; 29+ messages in thread
From: Dave Chinner @ 2013-05-17  3:01 UTC (permalink / raw)
  To: Jeff Liu; +Cc: Chandra Seetharaman, xfs

On Mon, May 13, 2013 at 11:59:36AM +0800, Jeff Liu wrote:
> Hi,
> 
> > +struct xfs_inode *
> > +xfs_dq_to_quota_inode(struct xfs_dquot *dqp)
> > +{
> > +	if (XFS_QM_ISUDQ(dqp))
> > +		return dqp->q_mount->m_quotainfo->qi_uquotaip;
> > +	if (XFS_QM_ISGDQ(dqp))
> > +		return dqp->q_mount->m_quotainfo->qi_gquotaip;
> > +	ASSERT(XFS_QM_ISPDQ(dqp));
> > +	return dqp->q_mount->m_quotainfo->qi_pquotaip;
> > +}
> Is it better to replace above conditional judgment with 'switch...case'?
> i.e.
> static inline struct xfs_inode *
> xfs_dq_to_qip(struct xfs_dquot *dqp)
> {
> 	switch (dqp->dq_flags) {
> 	case XFS_DQ_USER:
> 		return dqp->q_mount->m_quotainfo->qi_uquotaip;
> 	case XFS_DQ_GROUP:
> 		return dqp->q_mount->m_quotainfo->qi_gqoutaip;
> 	case XFS_DQ_PROJ:
> 		return dqp->q_mount->m_quotainfo->qi_pquotaip;
> 	}

Doesn't work because dq_flags can have other fields set in it (e.g
XFS_DQ_DIRTY). It would need to be:

	switch (dqp->dq_flags & XFS_DQ_ALLTYPES) {
	....
	}

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 2/5] xfs: Add pquota fields where gquota is used.
  2013-05-10 21:21 ` [PATCH v8 2/5] xfs: Add pquota fields where gquota is used Chandra Seetharaman
  2013-05-13  3:59   ` Jeff Liu
@ 2013-05-17  4:23   ` Dave Chinner
  2013-05-24 21:57     ` Chandra Seetharaman
  1 sibling, 1 reply; 29+ messages in thread
From: Dave Chinner @ 2013-05-17  4:23 UTC (permalink / raw)
  To: Chandra Seetharaman; +Cc: xfs

On Fri, May 10, 2013 at 04:21:26PM -0500, Chandra Seetharaman wrote:
> Add project quota changes to all the places where group quota field
> is used:
>    * add separate project quota members into various structures
>    * split project quota and group quotas so that instead of overriding
>      the group quota members incore, the new project quota members are
>      used instead
>    * get rid of usage of the OQUOTA flag incore, in favor of separate
>    * group
>      and project quota flags.
>    * add a project dquot argument to various functions.
> 
> No externally visible interfaces changed.

Looks pretty good. Some relatively minor changes below.

> @@ -568,6 +567,17 @@ xfs_qm_dqrepair(
>  	return 0;
>  }
>  
> +struct xfs_inode *
> +xfs_dq_to_quota_inode(struct xfs_dquot *dqp)
> +{
> +	if (XFS_QM_ISUDQ(dqp))
> +		return dqp->q_mount->m_quotainfo->qi_uquotaip;
> +	if (XFS_QM_ISGDQ(dqp))
> +		return dqp->q_mount->m_quotainfo->qi_gquotaip;
> +	ASSERT(XFS_QM_ISPDQ(dqp));
> +	return dqp->q_mount->m_quotainfo->qi_pquotaip;
> +}

Consolidate this with xfs_dquot_tree() as a static inline function,
I think. Let's try and keep all these little helpers together so
they are easy to find ;)

> +
>  /*
>   * Maps a dquot to the buffer containing its on-disk version.
>   * This returns a ptr to the buffer containing the on-disk dquot
> @@ -584,7 +594,7 @@ xfs_qm_dqtobp(
>  	xfs_bmbt_irec_t map;
>  	int		nmaps = 1, error;
>  	xfs_buf_t	*bp;
> -	xfs_inode_t	*quotip = XFS_DQ_TO_QIP(dqp);
> +	xfs_inode_t	*quotip = xfs_dq_to_quota_inode(dqp);

convert to struct xfs_inode a the same time....

> @@ -52,7 +51,8 @@ typedef struct xfs_dquot {
> @@ -144,9 +146,6 @@ static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
>  #define XFS_QM_ISPDQ(dqp)	((dqp)->dq_flags & XFS_DQ_PROJ)
>  #define XFS_QM_ISGDQ(dqp)	((dqp)->dq_flags & XFS_DQ_GROUP)
>  #define XFS_DQ_TO_QINF(dqp)	((dqp)->q_mount->m_quotainfo)
> -#define XFS_DQ_TO_QIP(dqp)	(XFS_QM_ISUDQ(dqp) ? \
> -				 XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \
> -				 XFS_DQ_TO_QINF(dqp)->qi_gquotaip)

XFS_DQ_TO_QINF can go away, too.

> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -928,7 +928,7 @@ xfs_ioctl_setattr(
>  	struct xfs_trans	*tp;
>  	unsigned int		lock_flags = 0;
>  	struct xfs_dquot	*udqp = NULL;
> -	struct xfs_dquot	*gdqp = NULL;
> +	struct xfs_dquot	*pdqp = NULL;
>  	struct xfs_dquot	*olddquot = NULL;
>  	int			code;
>  
> @@ -957,7 +957,7 @@ xfs_ioctl_setattr(
>  	if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
>  		code = xfs_qm_vop_dqalloc(ip, ip->i_d.di_uid,
>  					 ip->i_d.di_gid, fa->fsx_projid,
> -					 XFS_QMOPT_PQUOTA, &udqp, &gdqp);
> +					 XFS_QMOPT_PQUOTA, &udqp, NULL, &pdqp);

We're only passing in XFS_QMOPT_PQUOTA, so we do not need to pass in
uid, gid, udqp or gdqp here....

Can you add a comment here that this may cause user/group quotas
to be allocated, but we don't need it here in this function because
we are only specifically changing the project quota via a chown
operation.

Indeed, the only reason a user quota is passed in is to make use of
the dquot hint that the udq might hold that points to the other
dquots on the inode....

>  		if (code)
>  			return code;
>  	}
> @@ -994,8 +994,8 @@ xfs_ioctl_setattr(
>  		    XFS_IS_PQUOTA_ON(mp) &&
>  		    xfs_get_projid(ip) != fa->fsx_projid) {
>  			ASSERT(tp);
> -			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
> -						capable(CAP_FOWNER) ?
> +			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL,
> +						pdqp, capable(CAP_FOWNER) ?
>  						XFS_QMOPT_FORCE_RES : 0);
> @@ -1113,7 +1113,7 @@ xfs_ioctl_setattr(
>  		if (xfs_get_projid(ip) != fa->fsx_projid) {
>  			if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
>  				olddquot = xfs_qm_vop_chown(tp, ip,
> -							&ip->i_gdquot, gdqp);
> +							&ip->i_pdquot, pdqp);

xfs_qm_vop_chown() is only called on one dquot at a time, so it can
only exchange one dquot at a time. and udqp is not used for hints,
so it looks to me like udqp and gdqp are wholly unnecessary in this
function....

> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index d82efaa..7c54ea4 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -517,7 +517,7 @@ xfs_setattr_nonsize(
>  		ASSERT(udqp == NULL);
>  		ASSERT(gdqp == NULL);
>  		error = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip),
> -					 qflags, &udqp, &gdqp);
> +					 qflags, &udqp, &gdqp, NULL);

Why is there no project quota support here, even though we pass in a
project ID? I know the answer, but please add a comment so that a
couple of years down the track I don't need to go remind myself of
why....

>  /*
> - * Given a udquot and gdquot, attach a ptr to the group dquot in the
> + * Given a udquot and gdquot, attach a ptr to the group/project dquot in the
>   * udquot as a hint for future lookups.
>   */
>  STATIC void
> -xfs_qm_dqattach_grouphint(
> -	xfs_dquot_t	*udq,
> -	xfs_dquot_t	*gdq)
> +xfs_qm_dqattach_grouphint(xfs_inode_t *ip, int type)

Wrong format for the function header And it's not longer just for
the group dquot, so I'd rename just to xfs_qm_dqattach_hint. i.e:

STATIC void
xfs_qm_dqattach_hint(
	struct xfs_inode	*ip,
	int			 type)

>  {
> -	xfs_dquot_t	*tmp;
> +	struct xfs_dquot **dqhint;
> +	struct xfs_dquot *gpdq;

not a group dquot. so perhaps just call it dqp?

> @@ -1395,19 +1453,27 @@ xfs_qm_init_quotainos(
>  		if (XFS_IS_UQUOTA_ON(mp) &&
>  		    mp->m_sb.sb_uquotino != NULLFSINO) {
>  			ASSERT(mp->m_sb.sb_uquotino > 0);
> -			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
> -					     0, 0, &uip)))
> +			error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
> +					     0, 0, &uip);
> +			if (error)
>  				return XFS_ERROR(error);
>  		}
> -		if (XFS_IS_OQUOTA_ON(mp) &&
> +		if (XFS_IS_GQUOTA_ON(mp) &&
>  		    mp->m_sb.sb_gquotino != NULLFSINO) {
>  			ASSERT(mp->m_sb.sb_gquotino > 0);
> -			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
> -					     0, 0, &gip))) {
> -				if (uip)
> -					IRELE(uip);
> -				return XFS_ERROR(error);
> -			}
> +			error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
> +					     0, 0, &gip);
> +			if (error)
> +				goto error_rele;
> +		}
> +		/* Use sb_gquotino for now */
> +		if (XFS_IS_PQUOTA_ON(mp) &&
> +		    mp->m_sb.sb_gquotino != NULLFSINO) {
> +			ASSERT(mp->m_sb.sb_gquotino > 0);
> +			error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
> +					     0, 0, &pip);
> +			if (error)
> +				goto error_rele;

There is no need for this trickery, right? All that is needed is:

			qino = xfs_sb_version_has_pquota(&mp->m_sb) ?
						mp->m_sb.sb_pquotino :
						mp->m_sb.sb_gquotino;

And the correct on-disk inode is read....


> @@ -1804,15 +1896,21 @@ xfs_qm_vop_chown(
>   */
>  int
>  xfs_qm_vop_chown_reserve(
> -	xfs_trans_t	*tp,
> -	xfs_inode_t	*ip,
> -	xfs_dquot_t	*udqp,
> -	xfs_dquot_t	*gdqp,
> -	uint		flags)
> +	xfs_trans_t		*tp,
> +	xfs_inode_t		*ip,

struct xfs_trans, struct xfs_inode.

> +	struct xfs_dquot	*udqp,
> +	struct xfs_dquot	*gdqp,
> +	struct xfs_dquot	*pdqp,
> +	uint			flags)
>  {
>  	xfs_mount_t	*mp = ip->i_mount;
>  	uint		delblks, blkflags, prjflags = 0;
> -	xfs_dquot_t	*unresudq, *unresgdq, *delblksudq, *delblksgdq;
> +	struct xfs_dquot	*unresudq = NULL;
> +	struct xfs_dquot	*unresgdq = NULL;
> +	struct xfs_dquot	*unrespdq = NULL;
> +	struct xfs_dquot	*delblksudq = NULL;
> +	struct xfs_dquot	*delblksgdq = NULL;
> +	struct xfs_dquot	*delblkspdq = NULL;
>  	int		error;

You may as well line up the other 3 declarations, and make is a
struct xfs_mount....

.... and I just realised that looking through this code reviewing
the xfs_ioctl_setattr() changes that I'd not read the existing
code correctly.

Why not? becuse unresudq and unresgdq are not very different. The
classic case of the brain not really seeing the difference between
single letters inside a larger word, and that's where the single
letter difference in the variables are. i.e: this phenomenon:

http://www.ecenglish.com/learnenglish/lessons/can-you-read

I can read that mess as fast as if it were spelt correctly, hence
the importance of the first/last letter of variable names...

So, can you rename these variables:

	udq_unres
	gdq_unres
	pdq_unres
	udq_delblks
	gdq_delblks
	pdq_delblks

so it's a little more obvious to my easily tricked brain that they
are different....

> @@ -1935,13 +2039,18 @@ xfs_qm_vop_create_dqattach(
>  	}
>  	if (gdqp) {
>  		ASSERT(ip->i_gdquot == NULL);
> -		ASSERT(XFS_IS_OQUOTA_ON(mp));
> -		ASSERT((XFS_IS_GQUOTA_ON(mp) ?
> -			ip->i_d.di_gid : xfs_get_projid(ip)) ==
> -				be32_to_cpu(gdqp->q_core.d_id));
> -
> +		ASSERT(XFS_IS_GQUOTA_ON(mp));
> +		ASSERT(ip->i_d.di_gid == be32_to_cpu(gdqp->q_core.d_id));
>  		ip->i_gdquot = xfs_qm_dqhold(gdqp);
>  		xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
>  	}
> +	if (pdqp) {
> +		ASSERT(ip->i_pdquot == NULL);
> +		ASSERT(XFS_IS_PQUOTA_ON(mp));
> +		ASSERT(xfs_get_projid(ip) == be32_to_cpu(pdqp->q_core.d_id));
> +
> +		ip->i_pdquot = xfs_qm_dqhold(pdqp);
> +		xfs_trans_mod_dquot(tp, pdqp, XFS_TRANS_DQ_ICOUNT, 1);
> +	}
>  }

Something this just triggered. All transaction reservations that
reserve space for dquots need to be upped from 2 to 3 dquots.

> -extern void	xfs_trans_mod_dquot(xfs_trans_t *, xfs_dquot_t *, uint, long);
> -extern int	xfs_trans_reserve_quota_bydquots(xfs_trans_t *, xfs_mount_t *,
> -			xfs_dquot_t *, xfs_dquot_t *, long, long, uint);
> -extern void	xfs_trans_dqjoin(xfs_trans_t *, xfs_dquot_t *);
> -extern void	xfs_trans_log_dquot(xfs_trans_t *, xfs_dquot_t *);
> +extern void	xfs_trans_mod_dquot(xfs_trans_t *, struct xfs_dquot *, uint, long);
> +extern void	xfs_trans_dqjoin(xfs_trans_t *, struct xfs_dquot *);
> +extern void	xfs_trans_log_dquot(xfs_trans_t *, struct xfs_dquot *);

Remove the typedefs at the same time.


>  /*
> - * We keep the usr and grp dquots separately so that locking will be easier
> - * to do at commit time. All transactions that we know of at this point
> + * We keep the usr, grp, and prj dquots separately so that locking will be
> + * easier to do at commit time. All transactions that we know of at this point
>   * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value.
>   */
> +enum {
> +	XFS_QM_TRANS_USR = 0,
> +	XFS_QM_TRANS_GRP,
> +	XFS_QM_TRANS_PROJ,
> +	XFS_QM_TRANS_DQTYPES
> +};
>  #define XFS_QM_TRANS_MAXDQS		2
> -typedef struct xfs_dquot_acct {
> -	xfs_dqtrx_t	dqa_usrdquots[XFS_QM_TRANS_MAXDQS];
> -	xfs_dqtrx_t	dqa_grpdquots[XFS_QM_TRANS_MAXDQS];
> -} xfs_dquot_acct_t;
> +struct xfs_dquot_acct {
> +	struct xfs_dqtrx dqs[XFS_QM_TRANS_DQTYPES][XFS_QM_TRANS_MAXDQS];
> +};
>  
>  /*
>   * Users are allowed to have a usage exceeding their softlimit for
> diff --git a/fs/xfs/xfs_qm_bhv.c b/fs/xfs/xfs_qm_bhv.c
> index 2d02eac..72a4fdd 100644
> --- a/fs/xfs/xfs_qm_bhv.c
> +++ b/fs/xfs/xfs_qm_bhv.c
> @@ -115,7 +115,7 @@ xfs_qm_newmount(
>  	     (pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
>  	    (!pquotaondisk &&  XFS_IS_PQUOTA_ON(mp)) ||
>  	     (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
> -	    (!gquotaondisk &&  XFS_IS_OQUOTA_ON(mp)))  &&
> +	    (!gquotaondisk &&  XFS_IS_GQUOTA_ON(mp)))  &&
>  	    xfs_dev_is_read_only(mp, "changing quota state")) {
>  		xfs_warn(mp, "please mount with%s%s%s%s.",
>  			(!quotaondisk ? "out quota" : ""),

Shouldn't this hunk be in the first patch?


> index 1501f4f..cd0d133 100644
> --- a/fs/xfs/xfs_vnodeops.c
> +++ b/fs/xfs/xfs_vnodeops.c
> @@ -498,6 +498,7 @@ xfs_create(
>  	prid_t			prid;
>  	struct xfs_dquot	*udqp = NULL;
>  	struct xfs_dquot	*gdqp = NULL;
> +	struct xfs_dquot	*pdqp = NULL;
>  	uint			resblks;
>  	uint			log_res;
>  	uint			log_count;
> @@ -516,7 +517,7 @@ xfs_create(
>  	 * Make sure that we have allocated dquot(s) on disk.
>  	 */
>  	error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
> -			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
> +		XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp);

break that into two lines.

				XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
				&udqp, &gdqp, &pdqp);

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 3/5] xfs: Start using pquotaino from the superblock
  2013-05-10 21:21 ` [PATCH v8 3/5] xfs: Start using pquotaino from the superblock Chandra Seetharaman
  2013-05-13  4:24   ` Jeff Liu
@ 2013-05-17  4:46   ` Dave Chinner
  2013-05-24 22:09     ` Chandra Seetharaman
  1 sibling, 1 reply; 29+ messages in thread
From: Dave Chinner @ 2013-05-17  4:46 UTC (permalink / raw)
  To: Chandra Seetharaman; +Cc: xfs

On Fri, May 10, 2013 at 04:21:27PM -0500, Chandra Seetharaman wrote:
> Define a macro to check if the superblock has pquotino.
> 
> Keep backward compatibilty by alowing mount of older superblock
> with no separate pquota inode.
....

> diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> index 1b79906..233f88e 100644
> --- a/fs/xfs/xfs_mount.c
> +++ b/fs/xfs/xfs_mount.c
> @@ -601,21 +601,6 @@ xfs_sb_from_disk(
>  	to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
>  	to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
>  	to->sb_qflags = be16_to_cpu(from->sb_qflags);
> -	if ((to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) &&
> -			(to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> -				XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))) {
> -		xfs_notice(NULL, "Super block has XFS_OQUOTA bits along with "
> -		    "XFS_PQUOTA and/or XFS_GQUOTA bits. Quota check forced.\n");
> -		force_quota_check = true;
> -	}
> -	if (to->sb_qflags & XFS_OQUOTA_ENFD)
> -		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> -					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
> -	if (to->sb_qflags & XFS_OQUOTA_CHKD)
> -		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> -					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
> -	to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> -
>  	to->sb_flags = from->sb_flags;
>  	to->sb_shared_vn = from->sb_shared_vn;
>  	to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
> @@ -636,6 +621,44 @@ xfs_sb_from_disk(
>  	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
>  	to->sb_lsn = be64_to_cpu(from->sb_lsn);
>  
> +	if (xfs_sb_version_has_pquota(to)) {
> +		if (to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) {
> +			xfs_notice(NULL, "Super block has XFS_OQUOTA bits "
> +			"with version PQUOTINO. Quota check forced.\n");
> +			to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> +			force_quota_check = true;
> +		}
> +		to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
> +	} else {
> +		if (to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> +					XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) {
> +			xfs_notice(NULL, "Super block has XFS_[G|P]UOTA "
> +				"bits in version older than PQUOTINO. "
> +				"Quota check forced.\n");
> +
> +			to->sb_qflags &= ~(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> +					XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD);
> +			force_quota_check = true;
> +		}
> +
> +		/*
> +		 * On disk superblock qflags uses XFS_OQUOTA.* to support
> +		 * either PQUOTA or GQUOTA. But, in memory qflags uses
> +		 * XFS_PQUOTA.* or XFS_GQUOTA.* depending on which quota
> +		 * is used.
> +		 * Following block translates XFS_OQUOTA.* to either
> +		 * GQUOTA or PQUOTA.
> +		 */
> +		if (to->sb_qflags & XFS_OQUOTA_ENFD)
> +			to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> +					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
> +		if (to->sb_qflags & XFS_OQUOTA_CHKD)
> +			to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> +					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
> +		to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> +
> +	}
> +
>  	if (force_quota_check)
>  		to->sb_qflags &= ~(XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD);
>  }

This all gets restructured here - as per my previous comments, this
probably should all be in xfs_readsb(), not here.

> @@ -657,27 +680,51 @@ xfs_sb_to_disk(
>  	int		first;
>  	int		size;
>  	__uint16_t	qflags = from->sb_qflags;
> +	xfs_ino_t	gquotino = from->sb_gquotino;
>  
>  	ASSERT(fields);
>  	if (!fields)
>  		return;
>  
> -	if (fields & XFS_SB_QFLAGS) {
> +	if (!xfs_sb_version_has_pquota(from)) {

This should be moved to a separate function, I think.

> +		if (fields & XFS_SB_QFLAGS) {
> +			/*
> +			 * The in-core version of sb_qflags do not have
> +			 * XFS_OQUOTA_* flags, whereas the on-disk version
> +			 * does.  So, convert incore XFS_{PG}QUOTA_* flags
> +			 * to on-disk XFS_OQUOTA_* flags.
> +			 */
> +			qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
> +					XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
> +
> +			if (from->sb_qflags &
> +					(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
> +				qflags |= XFS_OQUOTA_ENFD;
> +			if (from->sb_qflags &
> +					(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
> +				qflags |= XFS_OQUOTA_CHKD;

Now that we have the new flags set correct, write it directly to
to->sb_qflags and clear XFS_SB_QFLAGS from the fields varaible.

> +		}
> +
>  		/*
> -		 * The in-core version of sb_qflags do not have
> -		 * XFS_OQUOTA_* flags, whereas the on-disk version
> -		 * does.  So, convert incore XFS_{PG}QUOTA_* flags 
> -		 * to on-disk XFS_OQUOTA_* flags.
> +		 * On-disk version earlier than pquota doesn't have
> +		 * sb_pquotino. so, we need to copy the value to gquotino.
>  		 */
> -		qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
> -				XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
> +		if (fields & XFS_SB_PQUOTINO) {
> +			fields &= (__int64_t)~XFS_SB_PQUOTINO;
> +			fields |= (__int64_t)XFS_SB_GQUOTINO;
> +			gquotino = from->sb_pquotino;
> +		}

Same here - write the inode number directly to the to->sb_gquotino
field and clear the XFS_SB_PQUOTINO flag.

>  
> -		if (from->sb_qflags &
> -				(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
> -			qflags |= XFS_OQUOTA_ENFD;
> -		if (from->sb_qflags &
> -				(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
> -			qflags |= XFS_OQUOTA_CHKD;
> +		/* If any quota inodes are written, write all quota inodes */
> +		if (fields & (XFS_SB_UQUOTINO|XFS_SB_GQUOTINO))
> +			fields |= (XFS_SB_UQUOTINO|XFS_SB_GQUOTINO);

Why write things that haven't been modified?

> +
> +	} else {
> +		/* If any quota inodes are written, write all quota inodes */
> +		if (fields & (XFS_SB_UQUOTINO | XFS_SB_GQUOTINO
> +							| XFS_SB_PQUOTINO))
> +			fields |= (XFS_SB_UQUOTINO | XFS_SB_GQUOTINO
> +							| XFS_SB_PQUOTINO);

Same - the flags pssed in are supposed to document everything that
has been modified. If the flags passed in are wrong, then fix the
bad callers.....
>  	}

>  
>  	while (fields) {
> @@ -691,6 +738,8 @@ xfs_sb_to_disk(
>  			memcpy(to_ptr + first, from_ptr + first, size);
>  		} else if (f == XFS_SBS_QFLAGS) {
>  			*(__be16 *)(to_ptr + first) = cpu_to_be16(qflags);
> +		} else if (f == XFS_SBS_GQUOTINO) {
> +			*(__be64 *)(to_ptr + first) = cpu_to_be64(gquotino);

If we clear the XFS_SBS_GQUOTINO/XFS_SBS_QFLAGS flags like I
suggested above, this grot can go away and the loop remain
completely generic.

>  		} else {
>  			switch (size) {
>  			case 2:
> @@ -872,6 +921,18 @@ reread:
>  	 */
>  	xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
>  
> +	if (!xfs_sb_version_has_pquota(&mp->m_sb) && XFS_IS_PQUOTA_ON(mp)) {
> +		/*
> +		 * On disk superblock only has sb_gquotino, and in memory
> +		 * superblock has both sb_gquotino and sb_pquotino. But,
> +		 * only one them is supported at any point of time.
> +		 * So, if PQUOTA is set in disk superblock, copy over
> +		 * sb_gquotino to sb_pquotino.
> +		 */
> +		mp->m_sb.sb_pquotino = mp->m_sb.sb_gquotino;
> +		mp->m_sb.sb_gquotino = NULLFSINO;
> +	}

Yup, that's the right place for doing all this on-disk->incore
translation stuff at mount time ;)

> -	if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
> +	if (ino == mp->m_sb.sb_uquotino ||
> +	    ino == mp->m_sb.sb_gquotino ||
> +	    ino == mp->m_sb.sb_pquotino) {

Seeing how often this is repeated, perhaps we need a helper function
called "xfs_is_quota_inode(mp, ino)"?

> @@ -1505,7 +1506,7 @@ xfs_qm_init_quotainos(
>  	}
>  	if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
>  		error = xfs_qm_qino_alloc(mp, &pip,
> -					     sbflags | XFS_SB_GQUOTINO,
> +					     sbflags | XFS_SB_PQUOTINO,
>  					     flags | XFS_QMOPT_PQUOTA);

Isn't that fixing a bug in the previous patch?

> @@ -412,17 +413,20 @@ xfs_qm_scall_getqstat(
>  	struct fs_quota_stat	*out)
>  {
>  	struct xfs_quotainfo	*q = mp->m_quotainfo;
> -	struct xfs_inode	*uip, *gip;
> -	bool                    tempuqip, tempgqip;
> +	struct xfs_inode	*uip = NULL;
> +	struct xfs_inode	*gip = NULL;
> +	struct xfs_inode	*pip = NULL;
> +	bool                    tempuqip = false;
> +	bool                    tempgqip = false;
> +	bool                    temppqip = false;

See my previous comments about naming variables. At least
add an underscore into the name like temp_uqip....

> @@ -420,12 +420,6 @@ xfs_parseargs(
>  	}
>  #endif
>  
> -	if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
> -	    (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE))) {
> -		xfs_warn(mp, "cannot mount with both project and group quota");
> -		return EINVAL;
> -	}
> -
>  	if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
>  		xfs_warn(mp, "sunit and swidth must be specified together");
>  		return EINVAL;
> @@ -1388,6 +1382,14 @@ xfs_finish_flags(
>  		return XFS_ERROR(EROFS);
>  	}
>  
> +	if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
> +	    (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE)) &&
> +	    !xfs_sb_version_has_pquota(&mp->m_sb)) {
> +		xfs_warn(mp, "Super block does not support "
> +				 "project and group quota together");
> +		return XFS_ERROR(EINVAL);
> +	}

Why move this check? just leave it where it is and add the extra
check to it...

> @@ -157,7 +157,8 @@ xfs_trans_mod_dquot_byino(
>  	if (!XFS_IS_QUOTA_RUNNING(mp) ||
>  	    !XFS_IS_QUOTA_ON(mp) ||
>  	    ip->i_ino == mp->m_sb.sb_uquotino ||
> -	    ip->i_ino == mp->m_sb.sb_gquotino)
> +	    ip->i_ino == mp->m_sb.sb_gquotino ||
> +	    ip->i_ino == mp->m_sb.sb_pquotino)
>  		return;

I see a helper....

>  	if (tp->t_dqinfo == NULL)
> @@ -825,6 +826,7 @@ xfs_trans_reserve_quota_nblks(
>  
>  	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_pquotino);

And that becomes ASSERT(!xfs_is_quota_inode(mp, ip->i_ino))....

> diff --git a/include/uapi/linux/dqblk_xfs.h b/include/uapi/linux/dqblk_xfs.h
> index 8655280..f17e3bb 100644
> --- a/include/uapi/linux/dqblk_xfs.h
> +++ b/include/uapi/linux/dqblk_xfs.h
> @@ -155,6 +155,7 @@ typedef struct fs_quota_stat {
>  	__s8		qs_pad;		/* unused */
>  	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
>  	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
> +#define qs_pquota	qs_gquota
>  	__u32		qs_incoredqs;	/* number of dquots incore */
>  	__s32		qs_btimelimit;  /* limit for blks timer */	
>  	__s32		qs_itimelimit;  /* limit for inodes timer */	

Ugly, but will do until the next patch ;)

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 4/5] xfs: Add proper versioning support to fs_quota_stat
  2013-05-10 21:21 ` [PATCH v8 4/5] xfs: Add proper versioning support to fs_quota_stat Chandra Seetharaman
  2013-05-13  4:29   ` Jeff Liu
@ 2013-05-17  5:10   ` Dave Chinner
  2013-05-24 22:17     ` Chandra Seetharaman
  1 sibling, 1 reply; 29+ messages in thread
From: Dave Chinner @ 2013-05-17  5:10 UTC (permalink / raw)
  To: Chandra Seetharaman; +Cc: xfs

On Fri, May 10, 2013 at 04:21:28PM -0500, Chandra Seetharaman wrote:
> Added appropriate pads and code for backward compatibility.
> 
> Copied over the old version as it is different from the newer padded
> version.
> 
> New callers of the system call have to just set the version of the data
> structure being passed, and kernel will fill as much data as requested.
> 
> Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>

This needs to be cc'd to Steve Whitehouse so he's aware that we are
changing the quota interface...

> ---
>  fs/gfs2/quota.c                |    3 ---
>  fs/quota/quota.c               |   40 ++++++++++++++++++++++++++++++++++++++--
>  fs/xfs/xfs_qm_syscalls.c       |    4 ----
>  include/uapi/linux/dqblk_xfs.h |   38 ++++++++++++++++++++++++++++++++++++--
>  4 files changed, 74 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
> index c7c840e..ca0dccd 100644
> --- a/fs/gfs2/quota.c
> +++ b/fs/gfs2/quota.c
> @@ -1443,9 +1443,6 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
>  {
>  	struct gfs2_sbd *sdp = sb->s_fs_info;
>  
> -	memset(fqs, 0, sizeof(struct fs_quota_stat));
> -	fqs->qs_version = FS_QSTAT_VERSION;
> -
>  	switch (sdp->sd_args.ar_quota) {
>  	case GFS2_QUOTA_ON:
>  		fqs->qs_flags |= (FS_QUOTA_UDQ_ENFD | FS_QUOTA_GDQ_ENFD);
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index c7314f1..510464e 100644
> --- a/fs/quota/quota.c
> +++ b/fs/quota/quota.c
> @@ -207,12 +207,48 @@ static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
>  static int quota_getxstate(struct super_block *sb, void __user *addr)
>  {
>  	struct fs_quota_stat fqs;
> -	int ret;
> +	struct fs_quota_stat_v1 fqs_v1;
> +	int ret, size;
> +	void *cp = &fqs;

What's "cp" mean? Wouldn't fqsp be a better name? And initialise it
just before it gets used makes more sense, too.

>  
>  	if (!sb->s_qcop->get_xstate)
>  		return -ENOSYS;
> +
> +	memset(&fqs, 0, sizeof(struct fs_quota_stat));
> +	if (copy_from_user(&fqs, addr, 1)) /* just get the version */
> +		return -EFAULT;
> +
> +	switch (fqs.qs_version) {
> +	case FS_QSTAT_VERSION_2:
> +		size = FS_QSTAT_V2_SIZE;
> +		break;
> +	default:
> +		fqs.qs_version = FS_QSTAT_VERSION;
> +		/* fallthrough */
> +	case FS_QSTAT_VERSION:
> +		size = FS_QSTAT_V1_SIZE;
> +		cp = &fqs_v1;
> +	}

Missing a break on the last case there.

> +
>  	ret = sb->s_qcop->get_xstate(sb, &fqs);
> -	if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
> +	if (ret)
> +		return ret;
> +
> +	if (fqs.qs_version == FS_QSTAT_VERSION) {
> +		fqs_v1.qs_version = fqs.qs_version;
> +		fqs_v1.qs_flags = fqs.qs_flags;
> +		fqs_v1.qs_pad = 0;
> +		fqs_v1.qs_uquota = fqs.qs_uquota;
> +		fqs_v1.qs_gquota = fqs.qs_gquota;
> +		fqs_v1.qs_incoredqs = fqs.qs_incoredqs;
> +		fqs_v1.qs_btimelimit = fqs.qs_btimelimit;
> +		fqs_v1.qs_itimelimit = fqs.qs_itimelimit;
> +		fqs_v1.qs_rtbtimelimit = fqs.qs_rtbtimelimit;
> +		fqs_v1.qs_bwarnlimit = fqs.qs_bwarnlimit;
> +		fqs_v1.qs_iwarnlimit = fqs.qs_iwarnlimit;

		fsqp = &fsq_v1;
	} else {
		fsqp = &fsq_v2;
	}

> +
> +	if (copy_to_user(addr, &cp, size))
>  		return -EFAULT;
>  	return ret;
>  }
> diff --git a/include/uapi/linux/dqblk_xfs.h b/include/uapi/linux/dqblk_xfs.h
> index f17e3bb..d9629c1 100644
> --- a/include/uapi/linux/dqblk_xfs.h
> +++ b/include/uapi/linux/dqblk_xfs.h
> @@ -18,6 +18,7 @@
>  #define _LINUX_DQBLK_XFS_H
>  
>  #include <linux/types.h>
> +#include <linux/stddef.h>

Really? What's new that requires this include?

>  
>  /*
>   * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM).
> @@ -137,8 +138,12 @@ typedef struct fs_disk_quota {
>   * Provides a centralized way to get meta information about the quota subsystem.
>   * eg. space taken up for user and group quotas, number of dquots currently
>   * incore.
> + * User space caller should set qs_version to the appropriate version
> + * of the fs_quota_stat data structure they are providing. Not providing
> + * a version will be treated as FS_QSTAT_VERSION.
>   */
>  #define FS_QSTAT_VERSION	1	/* fs_quota_stat.qs_version */
> +#define FS_QSTAT_VERSION_2	2	/* new field qs_pquota */
>  
>  /*
>   * Some basic information about 'quota files'.
> @@ -149,19 +154,48 @@ typedef struct fs_qfilestat {
>  	__u32		qfs_nextents;	/* number of extents */
>  } fs_qfilestat_t;
>  
> +typedef struct fs_quota_stat_v1 {

Kill the typedef. Add a comment stating that this structure is
likely to have compatibility problems across architectures due to
implicit padding and offset alignment in the structure definition
and that the v2 structure should be used if these problems are being
seen.

> +	__s8		qs_version;	/* version number for future changes */
> +	__u16		qs_flags;	/* FS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
> +	__u8		qs_pad;		/* unused */
> +	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
> +	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
> +	__u32		qs_incoredqs;	/* number of dquots incore */
> +	__s32		qs_btimelimit;  /* limit for blks timer */	
> +	__s32		qs_itimelimit;  /* limit for inodes timer */	
> +	__s32		qs_rtbtimelimit;/* limit for rt blks timer */	
> +	__u16		qs_bwarnlimit;	/* limit for num warnings */
> +	__u16		qs_iwarnlimit;	/* limit for num warnings */
> +} fs_quota_stat_v1_t;
> +
>  typedef struct fs_quota_stat {

Kill the typedef.

>  	__s8		qs_version;	/* version number for future changes */
> +	__u8		qs_pad1;	/* unused */
>  	__u16		qs_flags;	/* FS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
> -	__s8		qs_pad;		/* unused */
> +	__u8		qs_pad2[4];	/* unused */
>  	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
>  	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
> -#define qs_pquota	qs_gquota
>  	__u32		qs_incoredqs;	/* number of dquots incore */
>  	__s32		qs_btimelimit;  /* limit for blks timer */	
>  	__s32		qs_itimelimit;  /* limit for inodes timer */	
>  	__s32		qs_rtbtimelimit;/* limit for rt blks timer */	
>  	__u16		qs_bwarnlimit;	/* limit for num warnings */
>  	__u16		qs_iwarnlimit;	/* limit for num warnings */
> +	__u8		qs_pad3[4];	/* unused */
> +	fs_qfilestat_t	qs_pquota;	/* project quota storage information */
> +	/* End of Data structure for FS_QSTAT_VERSION_2 */

No need for that comment.

>  } fs_quota_stat_t;

Use pahole on the built object file to determine if the end ofthe
structure is 64 bit aligned. If it isn't, please pad it to 64 bit
alignment.

Um. fs_qfilestat_t is { u64, u64, u32 }, and so there's going to be
alignment problems with that. We need a fs_qfilestat_v1 definition
and add padding to fs_qfilestat_t so that it is 64 bit aligned.....


>  
> +/*
> + * Since Version 1 did not have padding at appropriate places,
> + * a new data structure has been defined for the older version to
> + * provide backward compatibility.
> + * Future extentions of this data structure won't require new
> + * data structure definitions as the current one can be extended
> + * with the logic and padding in place now.
> + */
> +#define FS_QSTAT_V1_SIZE	(sizeof(struct fs_quota_stat_v1))
> +#define FS_QSTAT_V2_SIZE	(offsetof(struct fs_quota_stat, qs_pquota) + \
> +					sizeof(fs_qfilestat_t))

Just use sizeof(struct fs_quota_stat) as the size. Indeed, for
future enhancements, maybe we should add 64 bytes of empty space at
the end of the structure....

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 5/5] xfs: Use new qs_pquota field in fs_quota_stat for Q_XGETQSTAT
  2013-05-10 21:21 ` [PATCH v8 5/5] xfs: Use new qs_pquota field in fs_quota_stat for Q_XGETQSTAT Chandra Seetharaman
@ 2013-05-17  5:14   ` Dave Chinner
  2013-05-24 22:17     ` Chandra Seetharaman
  0 siblings, 1 reply; 29+ messages in thread
From: Dave Chinner @ 2013-05-17  5:14 UTC (permalink / raw)
  To: Chandra Seetharaman; +Cc: xfs

On Fri, May 10, 2013 at 04:21:29PM -0500, Chandra Seetharaman wrote:
> For the Q_XGETQSTAT quota command, if the new version of fs_quota_stat
> data structure is used, fill the project quota information.
> 
> Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
> ---
>  fs/xfs/xfs_qm_syscalls.c |   39 +++++++++++++++++++++++++--------------
>  1 files changed, 25 insertions(+), 14 deletions(-)
> 
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index c27b0e4..7c5876b 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -420,20 +420,14 @@ xfs_qm_scall_getqstat(
>  	bool                    tempgqip = false;
>  	bool                    temppqip = false;
>  
> -	if (!xfs_sb_version_hasquota(&mp->m_sb)) {
> -		out->qs_uquota.qfs_ino = NULLFSINO;
> -		out->qs_gquota.qfs_ino = NULLFSINO;
> -		out->qs_pquota.qfs_ino = NULLFSINO;
> +	out->qs_uquota.qfs_ino = NULLFSINO;
> +	out->qs_gquota.qfs_ino = NULLFSINO;
> +	out->qs_pquota.qfs_ino = NULLFSINO;
> +
> +	if (!xfs_sb_version_hasquota(&mp->m_sb))
>  		return (0);
> -	}
>  	out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
> -							(XFS_ALL_QUOTA_ACCT|
> -							 XFS_ALL_QUOTA_ENFD));
> -	out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
> -	out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
> -	if (&out->qs_gquota != &out->qs_pquota)
> -		out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino;
> -
> +				(XFS_ALL_QUOTA_ACCT| XFS_ALL_QUOTA_ENFD));
>  	if (q) {
>  		uip = q->qi_uquotaip;
>  		gip = q->qi_gquotaip;
> @@ -454,21 +448,38 @@ xfs_qm_scall_getqstat(
>  					0, 0, &pip) == 0)
>  			temppqip = true;
>  	}
> +
>  	if (uip) {
> +		out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
>  		out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
>  		out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
>  		if (tempuqip)
>  			IRELE(uip);
>  	}
>  	if (gip) {
> +		out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
>  		out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
>  		out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
>  		if (tempgqip)
>  			IRELE(gip);
>  	}
>  	if (pip) {
> -		out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks;
> -		out->qs_pquota.qfs_nextents = pip->i_d.di_nextents;
> +		if (out->qs_version >= FS_QSTAT_VERSION_2) {
> +			out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino;
> +			out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks;
> +			out->qs_pquota.qfs_nextents = pip->i_d.di_nextents;
> +		} else {
> +			/*
> +			 * In FS_QSTAT_VERSION version, there is no
> +			 * qs_pquota, and there is no combined support
> +			 * for gquota/pquota. qs_gquota is shared for
> +			 * providing the pquota/gquota information to
> +			 * the user space.
> +			 */

Move that comment to the head of the function. i.e.:

/*
 * We support two different versions of the fs_quota_stat structure
 * here. If the version is FS_QSTAT_VERSION, then there is no
 * separate project quota fields, and so we write project quota
 * information into the group quota fields. With FS_QSTAT_VERSION_2,
 * there is a separate project quota field so we can use that
 * instead to pass both group and project quota back to user space
 * in the one call.
 */

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 2/5] xfs: Add pquota fields where gquota is used.
  2013-05-17  3:01     ` Dave Chinner
@ 2013-05-17  5:40       ` Jeff Liu
  0 siblings, 0 replies; 29+ messages in thread
From: Jeff Liu @ 2013-05-17  5:40 UTC (permalink / raw)
  To: Dave Chinner; +Cc: Chandra Seetharaman, xfs

On 05/17/2013 11:01 AM, Dave Chinner wrote:
> On Mon, May 13, 2013 at 11:59:36AM +0800, Jeff Liu wrote:
>> Hi,
>>
>>> +struct xfs_inode *
>>> +xfs_dq_to_quota_inode(struct xfs_dquot *dqp)
>>> +{
>>> +	if (XFS_QM_ISUDQ(dqp))
>>> +		return dqp->q_mount->m_quotainfo->qi_uquotaip;
>>> +	if (XFS_QM_ISGDQ(dqp))
>>> +		return dqp->q_mount->m_quotainfo->qi_gquotaip;
>>> +	ASSERT(XFS_QM_ISPDQ(dqp));
>>> +	return dqp->q_mount->m_quotainfo->qi_pquotaip;
>>> +}
>> Is it better to replace above conditional judgment with 'switch...case'?
>> i.e.
>> static inline struct xfs_inode *
>> xfs_dq_to_qip(struct xfs_dquot *dqp)
>> {
>> 	switch (dqp->dq_flags) {
>> 	case XFS_DQ_USER:
>> 		return dqp->q_mount->m_quotainfo->qi_uquotaip;
>> 	case XFS_DQ_GROUP:
>> 		return dqp->q_mount->m_quotainfo->qi_gqoutaip;
>> 	case XFS_DQ_PROJ:
>> 		return dqp->q_mount->m_quotainfo->qi_pquotaip;
>> 	}
> 
> Doesn't work because dq_flags can have other fields set in it (e.g
> XFS_DQ_DIRTY). It would need to be:
> 
> 	switch (dqp->dq_flags & XFS_DQ_ALLTYPES) {
> 	....
> 	}
Ah, yep. thanks for the teaching. :)

Thanks,
-Jeff

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 2/5] xfs: Add pquota fields where gquota is used.
  2013-05-13  3:59   ` Jeff Liu
  2013-05-17  3:01     ` Dave Chinner
@ 2013-05-17 21:15     ` Chandra Seetharaman
  1 sibling, 0 replies; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-17 21:15 UTC (permalink / raw)
  To: Jeff Liu; +Cc: xfs

On Mon, 2013-05-13 at 11:59 +0800, Jeff Liu wrote:
> Hi,
> 
> On 05/11/2013 05:21 AM, Chandra Seetharaman wrote:
> > Add project quota changes to all the places where group quota field
> > is used:
> >    * add separate project quota members into various structures
> >    * split project quota and group quotas so that instead of overriding
> >      the group quota members incore, the new project quota members are
> >      used instead
> >    * get rid of usage of the OQUOTA flag incore, in favor of separate
> >    * group
> >      and project quota flags.
> >    * add a project dquot argument to various functions.
> > 
> > No externally visible interfaces changed.
> > 
> > Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>

<snip>

> > @@ -409,7 +421,10 @@ xfs_qm_dqattach_one(
> >  		 * be reclaimed as long as we have a ref from inode and we
> >  		 * hold the ilock.
> >  		 */
> > -		dqp = udqhint->q_gdquot;
> > +		if (type == XFS_DQ_GROUP)
> > +			dqp = udqhint->q_gdquot;
> > +		else
> > +			dqp = udqhint->q_pdquot;
> Maybe it's better to:
> dqp = "type == XFS_DQ_GROUP" ? udqhint->q_gdquot :
> 			       udqhint->q_pdquot;

Jeff,

"if else" construct is preferred for readability than "? :" construct.

So, I am leaving it as is.


<snip>

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 1/5] xfs: Remove incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD
  2013-05-17  2:55   ` Dave Chinner
@ 2013-05-24 21:45     ` Chandra Seetharaman
  0 siblings, 0 replies; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-24 21:45 UTC (permalink / raw)
  To: Dave Chinner; +Cc: xfs

On Fri, 2013-05-17 at 12:55 +1000, Dave Chinner wrote: 
> On Fri, May 10, 2013 at 04:21:25PM -0500, Chandra Seetharaman wrote:
> > Remove all incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD. Instead,
> > start using XFS_GQUOTA_.* XFS_PQUOTA_.* counterparts for GQUOTA and
> > PQUOTA respectively.
> > 
> > On-disk copy still uses XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD.
> > 
> > Read and write of the superblock does the conversion from *OQUOTA*
> > to *[PG]QUOTA*.
> > 
> > Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
> > Reviewed-by: Dave Chinner <dchinner@redhat.com>
> > ---
> >  fs/xfs/xfs_mount.c       |   41 +++++++++++++++++++++++++++++++++++++++++
> >  fs/xfs/xfs_qm.c          |    9 ++++++---
> >  fs/xfs/xfs_qm_syscalls.c |   39 +++++++++++++++++++++------------------
> >  fs/xfs/xfs_quota.h       |   42 ++++++++++++++++++++++++++++--------------
> >  fs/xfs/xfs_quotaops.c    |    6 ++++--
> >  fs/xfs/xfs_super.c       |   16 ++++++++--------
> >  fs/xfs/xfs_trans_dquot.c |    4 ++--
> >  7 files changed, 110 insertions(+), 47 deletions(-)
> > 
> > diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> > index f6bfbd7..1b79906 100644
> > --- a/fs/xfs/xfs_mount.c
> > +++ b/fs/xfs/xfs_mount.c
> > @@ -564,6 +564,8 @@ xfs_sb_from_disk(
> >  	struct xfs_sb	*to,
> >  	xfs_dsb_t	*from)
> >  {
> > +	bool force_quota_check = false;
> > +
> >  	to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
> >  	to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
> >  	to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
> > @@ -599,6 +601,21 @@ xfs_sb_from_disk(
> >  	to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
> >  	to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
> >  	to->sb_qflags = be16_to_cpu(from->sb_qflags);
> > +	if ((to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) &&
> > +			(to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> > +				XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))) {
> > +		xfs_notice(NULL, "Super block has XFS_OQUOTA bits along with "
> > +		    "XFS_PQUOTA and/or XFS_GQUOTA bits. Quota check forced.\n");
> > +		force_quota_check = true;
> > +	}
> 
> We can't do these quota check manipulations to the superblock quota
> flags during disk->incore translation anymore - there is more than
> one place that converts the superblock from on-disk to incore format
> (e.g.  the verification callbacks) and so emitting this message when
> we are *writing* the superblock is not good.
> 
> Also, if the XFS_PQUOTA_CHKD/XFS_PQUOTA_ENFD flags are set and
> the superblock is not a V5 superblock, then I think we should refuse
> to mount the filesystem because that is an invalid state - those
> flags should only be set now on a V5 superblock, and never at any
> other time. Hence this specific check should probably be moved to
> xfs_mount_validate_sb() and cause an EFSCORRUPTED return if it
> fails. That will catch something setting the flags incorrectly (i.e.
> at superblock write) as well as prevent mounting in this situation.
> 
> I know, this is different to what I've said in the past, but the
> on-disk format checking is now a lot stricter and so I think that if
> the filesystem is in some kind of wierd state we should just throw
> an error and let the administrator work out how this problem
> happened and how to resolve it.
> 

will do.

> > +	if (to->sb_qflags & XFS_OQUOTA_ENFD)
> > +		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> > +					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
> > +	if (to->sb_qflags & XFS_OQUOTA_CHKD)
> > +		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> > +					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
> > +	to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> > +
> 
> This translation of the quota flags needs to be external to
> this function, and then only called in the mount path where we are
> initially setting up the in-core superblock (i.e. in xfs_readsb())
> because that is the only place where the incore values are
> permanently stored.
> 
> > @@ -636,11 +656,30 @@ xfs_sb_to_disk(
> >  	xfs_sb_field_t	f;
> >  	int		first;
> >  	int		size;
> > +	__uint16_t	qflags = from->sb_qflags;
> >  
> >  	ASSERT(fields);
> >  	if (!fields)
> >  		return;
> >  
> > +	if (fields & XFS_SB_QFLAGS) {
> > +		/*
> > +		 * The in-core version of sb_qflags do not have
> > +		 * XFS_OQUOTA_* flags, whereas the on-disk version
> > +		 * does.  So, convert incore XFS_{PG}QUOTA_* flags 
> > +		 * to on-disk XFS_OQUOTA_* flags.
> > +		 */
> > +		qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
> > +				XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
> > +
> > +		if (from->sb_qflags &
> > +				(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
> > +			qflags |= XFS_OQUOTA_ENFD;
> > +		if (from->sb_qflags &
> > +				(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
> > +			qflags |= XFS_OQUOTA_CHKD;
> > +	}
> 
> Given that we have a new superblock version, we can write the new
> XFS_[PG]QUOTA_CHKD/XFS_[PG]QUOTA_ENFD flags directly into the
> sb_qflags knowing that we can't get an older kernel to interpret
> these new fields because they'll fail the superblck version test. So
> that would mean we only need to do this translation for filesystems
> for non-v5 superblock filesystems.
> 
> Ah, I see that in a later patch you introduce
> xfs_sb_version_has_pquota() and modify this code path to do
> something similar, and it becomes rather complex and nasty.
> 
> OK, I know this is a bit of work, but can you introduce
> xfs_sb_version_has_pquota() in this patch (as we already have the
> pquota inode defined in the on-disk format) as:
> 
> static inline int xfs_sb_version_haspquota(xfs_sb_t *sbp)
> {
>         return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
> }
> 
> and make these OQUOTA flag translations dependent on this not being
> set right from the start?

I am starting to use pquotino only in patch 3, and hence introduced the
above helper in that patch. IMO, it would be helpful w.r.t readability
and patch coherency, if I leave the introduction in patch 3.
> 
> Also, given how nasty this manipulation ends up, can you push it out
> into a function that is called from xfs_sb_to_disk(). That way
> xfs_sb_to_disk() doesn't end up mostly being 70% quota field
> manipulation code...

I will talk about this in patch 3. 
> 
> 
> >  /*
> > + * Start differentiating group quota and project quota in-core
> > + * using distinct flags, instead of using the combined OQUOTA flags.
> > + *
> > + * Conversion to and from the combined OQUOTA flag (if necessary)
> > + * is done only in xfs_sb_{to,from}_disk()
> > + */
> > +#define XFS_GQUOTA_ENFD	0x0080  /* group quota limits enforced */
> > +#define XFS_GQUOTA_CHKD	0x0100  /* quotacheck run on group quotas */
> > +#define XFS_PQUOTA_ENFD	0x0200  /* project quota limits enforced */
> > +#define XFS_PQUOTA_CHKD	0x0400  /* quotacheck run on project quotas */
> 
> These become new on-disk fields for xfs_sb_version_haspquota()
> filesystems, so they are not specifically in-core values.

will fix. 
> 
> Other than these to/from disk changes, the patch looks fine.
> 
> Cheers,
> 
> Dave.



_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 2/5] xfs: Add pquota fields where gquota is used.
  2013-05-17  4:23   ` Dave Chinner
@ 2013-05-24 21:57     ` Chandra Seetharaman
  2013-06-10 23:17       ` Dave Chinner
  0 siblings, 1 reply; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-24 21:57 UTC (permalink / raw)
  To: Dave Chinner; +Cc: xfs

On Fri, 2013-05-17 at 14:23 +1000, Dave Chinner wrote: 
> On Fri, May 10, 2013 at 04:21:26PM -0500, Chandra Seetharaman wrote:
> > Add project quota changes to all the places where group quota field
> > is used:
> >    * add separate project quota members into various structures
> >    * split project quota and group quotas so that instead of overriding
> >      the group quota members incore, the new project quota members are
> >      used instead
> >    * get rid of usage of the OQUOTA flag incore, in favor of separate
> >    * group
> >      and project quota flags.
> >    * add a project dquot argument to various functions.
> > 
> > No externally visible interfaces changed.
> 
> Looks pretty good. Some relatively minor changes below.
> 
> > @@ -568,6 +567,17 @@ xfs_qm_dqrepair(
> >  	return 0;
> >  }
> >  
> > +struct xfs_inode *
> > +xfs_dq_to_quota_inode(struct xfs_dquot *dqp)
> > +{
> > +	if (XFS_QM_ISUDQ(dqp))
> > +		return dqp->q_mount->m_quotainfo->qi_uquotaip;
> > +	if (XFS_QM_ISGDQ(dqp))
> > +		return dqp->q_mount->m_quotainfo->qi_gquotaip;
> > +	ASSERT(XFS_QM_ISPDQ(dqp));
> > +	return dqp->q_mount->m_quotainfo->qi_pquotaip;
> > +}
> 
> Consolidate this with xfs_dquot_tree() as a static inline function,
> I think. Let's try and keep all these little helpers together so
> they are easy to find ;)

will do. 
> 
> > +
> >  /*
> >   * Maps a dquot to the buffer containing its on-disk version.
> >   * This returns a ptr to the buffer containing the on-disk dquot
> > @@ -584,7 +594,7 @@ xfs_qm_dqtobp(
> >  	xfs_bmbt_irec_t map;
> >  	int		nmaps = 1, error;
> >  	xfs_buf_t	*bp;
> > -	xfs_inode_t	*quotip = XFS_DQ_TO_QIP(dqp);
> > +	xfs_inode_t	*quotip = xfs_dq_to_quota_inode(dqp);
> 
> convert to struct xfs_inode a the same time....

will do 
> 
> > @@ -52,7 +51,8 @@ typedef struct xfs_dquot {
> > @@ -144,9 +146,6 @@ static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
> >  #define XFS_QM_ISPDQ(dqp)	((dqp)->dq_flags & XFS_DQ_PROJ)
> >  #define XFS_QM_ISGDQ(dqp)	((dqp)->dq_flags & XFS_DQ_GROUP)
> >  #define XFS_DQ_TO_QINF(dqp)	((dqp)->q_mount->m_quotainfo)
> > -#define XFS_DQ_TO_QIP(dqp)	(XFS_QM_ISUDQ(dqp) ? \
> > -				 XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \
> > -				 XFS_DQ_TO_QINF(dqp)->qi_gquotaip)
> 
> XFS_DQ_TO_QINF can go away, too.

sure 
> 
> > --- a/fs/xfs/xfs_ioctl.c
> > +++ b/fs/xfs/xfs_ioctl.c
> > @@ -928,7 +928,7 @@ xfs_ioctl_setattr(
> >  	struct xfs_trans	*tp;
> >  	unsigned int		lock_flags = 0;
> >  	struct xfs_dquot	*udqp = NULL;
> > -	struct xfs_dquot	*gdqp = NULL;
> > +	struct xfs_dquot	*pdqp = NULL;
> >  	struct xfs_dquot	*olddquot = NULL;
> >  	int			code;
> >  
> > @@ -957,7 +957,7 @@ xfs_ioctl_setattr(
> >  	if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
> >  		code = xfs_qm_vop_dqalloc(ip, ip->i_d.di_uid,
> >  					 ip->i_d.di_gid, fa->fsx_projid,
> > -					 XFS_QMOPT_PQUOTA, &udqp, &gdqp);
> > +					 XFS_QMOPT_PQUOTA, &udqp, NULL, &pdqp);
> 
> We're only passing in XFS_QMOPT_PQUOTA, so we do not need to pass in
> uid, gid, udqp or gdqp here....
> 
> Can you add a comment here that this may cause user/group quotas
> to be allocated, but we don't need it here in this function because
> we are only specifically changing the project quota via a chown
> operation.
> 
> Indeed, the only reason a user quota is passed in is to make use of
> the dquot hint that the udq might hold that points to the other
> dquots on the inode....

will do 
> 
> >  		if (code)
> >  			return code;
> >  	}
> > @@ -994,8 +994,8 @@ xfs_ioctl_setattr(
> >  		    XFS_IS_PQUOTA_ON(mp) &&
> >  		    xfs_get_projid(ip) != fa->fsx_projid) {
> >  			ASSERT(tp);
> > -			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
> > -						capable(CAP_FOWNER) ?
> > +			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL,
> > +						pdqp, capable(CAP_FOWNER) ?
> >  						XFS_QMOPT_FORCE_RES : 0);
> > @@ -1113,7 +1113,7 @@ xfs_ioctl_setattr(
> >  		if (xfs_get_projid(ip) != fa->fsx_projid) {
> >  			if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
> >  				olddquot = xfs_qm_vop_chown(tp, ip,
> > -							&ip->i_gdquot, gdqp);
> > +							&ip->i_pdquot, pdqp);
> 
> xfs_qm_vop_chown() is only called on one dquot at a time, so it can
> only exchange one dquot at a time. and udqp is not used for hints,
> so it looks to me like udqp and gdqp are wholly unnecessary in this
> function....

Did not fully understand this comment. Can you please elaborate ?

> 
> > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> > index d82efaa..7c54ea4 100644
> > --- a/fs/xfs/xfs_iops.c
> > +++ b/fs/xfs/xfs_iops.c
> > @@ -517,7 +517,7 @@ xfs_setattr_nonsize(
> >  		ASSERT(udqp == NULL);
> >  		ASSERT(gdqp == NULL);
> >  		error = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip),
> > -					 qflags, &udqp, &gdqp);
> > +					 qflags, &udqp, &gdqp, NULL);
> 
> Why is there no project quota support here, even though we pass in a
> project ID? I know the answer, but please add a comment so that a
> couple of years down the track I don't need to go remind myself of
> why....

Not clear what you are expecting here.

> 
> >  /*
> > - * Given a udquot and gdquot, attach a ptr to the group dquot in the
> > + * Given a udquot and gdquot, attach a ptr to the group/project dquot in the
> >   * udquot as a hint for future lookups.
> >   */
> >  STATIC void
> > -xfs_qm_dqattach_grouphint(
> > -	xfs_dquot_t	*udq,
> > -	xfs_dquot_t	*gdq)
> > +xfs_qm_dqattach_grouphint(xfs_inode_t *ip, int type)
> 
> Wrong format for the function header And it's not longer just for
> the group dquot, so I'd rename just to xfs_qm_dqattach_hint. i.e:

will fix.

> 
> STATIC void
> xfs_qm_dqattach_hint(
> 	struct xfs_inode	*ip,
> 	int			 type)
> 
> >  {
> > -	xfs_dquot_t	*tmp;
> > +	struct xfs_dquot **dqhint;
> > +	struct xfs_dquot *gpdq;
> 
> not a group dquot. so perhaps just call it dqp?

sure. 
> 
> > @@ -1395,19 +1453,27 @@ xfs_qm_init_quotainos(
> >  		if (XFS_IS_UQUOTA_ON(mp) &&
> >  		    mp->m_sb.sb_uquotino != NULLFSINO) {
> >  			ASSERT(mp->m_sb.sb_uquotino > 0);
> > -			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
> > -					     0, 0, &uip)))
> > +			error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
> > +					     0, 0, &uip);
> > +			if (error)
> >  				return XFS_ERROR(error);
> >  		}
> > -		if (XFS_IS_OQUOTA_ON(mp) &&
> > +		if (XFS_IS_GQUOTA_ON(mp) &&
> >  		    mp->m_sb.sb_gquotino != NULLFSINO) {
> >  			ASSERT(mp->m_sb.sb_gquotino > 0);
> > -			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
> > -					     0, 0, &gip))) {
> > -				if (uip)
> > -					IRELE(uip);
> > -				return XFS_ERROR(error);
> > -			}
> > +			error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
> > +					     0, 0, &gip);
> > +			if (error)
> > +				goto error_rele;
> > +		}
> > +		/* Use sb_gquotino for now */
> > +		if (XFS_IS_PQUOTA_ON(mp) &&
> > +		    mp->m_sb.sb_gquotino != NULLFSINO) {
> > +			ASSERT(mp->m_sb.sb_gquotino > 0);
> > +			error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
> > +					     0, 0, &pip);
> > +			if (error)
> > +				goto error_rele;
> 
> There is no need for this trickery, right? All that is needed is:
> 
Will be taken care of in the next patch.

> 
> 
> 			qino = xfs_sb_version_has_pquota(&mp->m_sb) ?
> 						mp->m_sb.sb_pquotino :
> 						mp->m_sb.sb_gquotino;
> 
> And the correct on-disk inode is read....
> 
The object of this patch is to replace all gquota with pquota stuff. I
am not using the pquotino or xfs_sb_version_has_pquota() until patch 3.

If I get the change forward, I have to merge patch 3 and part of this
patch into patch 1, which adds up lots of work.

The way the patches are split now, IMO, is easy to follow and works
independently.
> 
> > @@ -1804,15 +1896,21 @@ xfs_qm_vop_chown(
> >   */
> >  int
> >  xfs_qm_vop_chown_reserve(
> > -	xfs_trans_t	*tp,
> > -	xfs_inode_t	*ip,
> > -	xfs_dquot_t	*udqp,
> > -	xfs_dquot_t	*gdqp,
> > -	uint		flags)
> > +	xfs_trans_t		*tp,
> > +	xfs_inode_t		*ip,
> 
> struct xfs_trans, struct xfs_inode.
> 
> > +	struct xfs_dquot	*udqp,
> > +	struct xfs_dquot	*gdqp,
> > +	struct xfs_dquot	*pdqp,
> > +	uint			flags)
> >  {
> >  	xfs_mount_t	*mp = ip->i_mount;
> >  	uint		delblks, blkflags, prjflags = 0;
> > -	xfs_dquot_t	*unresudq, *unresgdq, *delblksudq, *delblksgdq;
> > +	struct xfs_dquot	*unresudq = NULL;
> > +	struct xfs_dquot	*unresgdq = NULL;
> > +	struct xfs_dquot	*unrespdq = NULL;
> > +	struct xfs_dquot	*delblksudq = NULL;
> > +	struct xfs_dquot	*delblksgdq = NULL;
> > +	struct xfs_dquot	*delblkspdq = NULL;
> >  	int		error;
> 
> You may as well line up the other 3 declarations, and make is a
> struct xfs_mount....
> 
> .... and I just realised that looking through this code reviewing
> the xfs_ioctl_setattr() changes that I'd not read the existing
> code correctly.
> 
> Why not? becuse unresudq and unresgdq are not very different. The
> classic case of the brain not really seeing the difference between
> single letters inside a larger word, and that's where the single
> letter difference in the variables are. i.e: this phenomenon:
> 
> http://www.ecenglish.com/learnenglish/lessons/can-you-read
> 
> I can read that mess as fast as if it were spelt correctly, hence
> the importance of the first/last letter of variable names...
> 
> So, can you rename these variables:
> 
> 	udq_unres
> 	gdq_unres
> 	pdq_unres
> 	udq_delblks
> 	gdq_delblks
> 	pdq_delblks
> 
> so it's a little more obvious to my easily tricked brain that they
> are different....
> 
Why not :)

> 
> > @@ -1935,13 +2039,18 @@ xfs_qm_vop_create_dqattach(
> >  	}
> >  	if (gdqp) {
> >  		ASSERT(ip->i_gdquot == NULL);
> > -		ASSERT(XFS_IS_OQUOTA_ON(mp));
> > -		ASSERT((XFS_IS_GQUOTA_ON(mp) ?
> > -			ip->i_d.di_gid : xfs_get_projid(ip)) ==
> > -				be32_to_cpu(gdqp->q_core.d_id));
> > -
> > +		ASSERT(XFS_IS_GQUOTA_ON(mp));
> > +		ASSERT(ip->i_d.di_gid == be32_to_cpu(gdqp->q_core.d_id));
> >  		ip->i_gdquot = xfs_qm_dqhold(gdqp);
> >  		xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
> >  	}
> > +	if (pdqp) {
> > +		ASSERT(ip->i_pdquot == NULL);
> > +		ASSERT(XFS_IS_PQUOTA_ON(mp));
> > +		ASSERT(xfs_get_projid(ip) == be32_to_cpu(pdqp->q_core.d_id));
> > +
> > +		ip->i_pdquot = xfs_qm_dqhold(pdqp);
> > +		xfs_trans_mod_dquot(tp, pdqp, XFS_TRANS_DQ_ICOUNT, 1);
> > +	}
> >  }
> 
> Something this just triggered. All transaction reservations that
> reserve space for dquots need to be upped from 2 to 3 dquots.

Can you elaborate please.

> 
> > -extern void	xfs_trans_mod_dquot(xfs_trans_t *, xfs_dquot_t *, uint, long);
> > -extern int	xfs_trans_reserve_quota_bydquots(xfs_trans_t *, xfs_mount_t *,
> > -			xfs_dquot_t *, xfs_dquot_t *, long, long, uint);
> > -extern void	xfs_trans_dqjoin(xfs_trans_t *, xfs_dquot_t *);
> > -extern void	xfs_trans_log_dquot(xfs_trans_t *, xfs_dquot_t *);
> > +extern void	xfs_trans_mod_dquot(xfs_trans_t *, struct xfs_dquot *, uint, long);
> > +extern void	xfs_trans_dqjoin(xfs_trans_t *, struct xfs_dquot *);
> > +extern void	xfs_trans_log_dquot(xfs_trans_t *, struct xfs_dquot *);
> 
> Remove the typedefs at the same time.

sure
> 
> 
> >  /*
> > - * We keep the usr and grp dquots separately so that locking will be easier
> > - * to do at commit time. All transactions that we know of at this point
> > + * We keep the usr, grp, and prj dquots separately so that locking will be
> > + * easier to do at commit time. All transactions that we know of at this point
> >   * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value.
> >   */
> > +enum {
> > +	XFS_QM_TRANS_USR = 0,
> > +	XFS_QM_TRANS_GRP,
> > +	XFS_QM_TRANS_PROJ,
> > +	XFS_QM_TRANS_DQTYPES
> > +};
> >  #define XFS_QM_TRANS_MAXDQS		2
> > -typedef struct xfs_dquot_acct {
> > -	xfs_dqtrx_t	dqa_usrdquots[XFS_QM_TRANS_MAXDQS];
> > -	xfs_dqtrx_t	dqa_grpdquots[XFS_QM_TRANS_MAXDQS];
> > -} xfs_dquot_acct_t;
> > +struct xfs_dquot_acct {
> > +	struct xfs_dqtrx dqs[XFS_QM_TRANS_DQTYPES][XFS_QM_TRANS_MAXDQS];
> > +};
> >  
> >  /*
> >   * Users are allowed to have a usage exceeding their softlimit for
> > diff --git a/fs/xfs/xfs_qm_bhv.c b/fs/xfs/xfs_qm_bhv.c
> > index 2d02eac..72a4fdd 100644
> > --- a/fs/xfs/xfs_qm_bhv.c
> > +++ b/fs/xfs/xfs_qm_bhv.c
> > @@ -115,7 +115,7 @@ xfs_qm_newmount(
> >  	     (pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
> >  	    (!pquotaondisk &&  XFS_IS_PQUOTA_ON(mp)) ||
> >  	     (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
> > -	    (!gquotaondisk &&  XFS_IS_OQUOTA_ON(mp)))  &&
> > +	    (!gquotaondisk &&  XFS_IS_GQUOTA_ON(mp)))  &&
> >  	    xfs_dev_is_read_only(mp, "changing quota state")) {
> >  		xfs_warn(mp, "please mount with%s%s%s%s.",
> >  			(!quotaondisk ? "out quota" : ""),
> 
> Shouldn't this hunk be in the first patch?

No, the object of the first patch is to just handle on disk .*OQUOTA.*
flags in the sb_flags.

In this patch I replace the rest of OQUOTA
> 
> 
> > index 1501f4f..cd0d133 100644
> > --- a/fs/xfs/xfs_vnodeops.c
> > +++ b/fs/xfs/xfs_vnodeops.c
> > @@ -498,6 +498,7 @@ xfs_create(
> >  	prid_t			prid;
> >  	struct xfs_dquot	*udqp = NULL;
> >  	struct xfs_dquot	*gdqp = NULL;
> > +	struct xfs_dquot	*pdqp = NULL;
> >  	uint			resblks;
> >  	uint			log_res;
> >  	uint			log_count;
> > @@ -516,7 +517,7 @@ xfs_create(
> >  	 * Make sure that we have allocated dquot(s) on disk.
> >  	 */
> >  	error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
> > -			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
> > +		XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp);
> 
> break that into two lines.
> 
> 				XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
> 				&udqp, &gdqp, &pdqp);
> 
will do
> Cheers,
> 
> Dave.



_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 3/5] xfs: Start using pquotaino from the superblock
  2013-05-17  4:46   ` Dave Chinner
@ 2013-05-24 22:09     ` Chandra Seetharaman
  2013-06-10 23:20       ` Dave Chinner
  0 siblings, 1 reply; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-24 22:09 UTC (permalink / raw)
  To: Dave Chinner; +Cc: xfs

On Fri, 2013-05-17 at 14:46 +1000, Dave Chinner wrote:
> On Fri, May 10, 2013 at 04:21:27PM -0500, Chandra Seetharaman wrote:
> > Define a macro to check if the superblock has pquotino.
> > 
> > Keep backward compatibilty by alowing mount of older superblock
> > with no separate pquota inode.
> ....
> 
> > diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> > index 1b79906..233f88e 100644
> > --- a/fs/xfs/xfs_mount.c
> > +++ b/fs/xfs/xfs_mount.c
> > @@ -601,21 +601,6 @@ xfs_sb_from_disk(
> >  	to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
> >  	to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
> >  	to->sb_qflags = be16_to_cpu(from->sb_qflags);
> > -	if ((to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) &&
> > -			(to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> > -				XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))) {
> > -		xfs_notice(NULL, "Super block has XFS_OQUOTA bits along with "
> > -		    "XFS_PQUOTA and/or XFS_GQUOTA bits. Quota check forced.\n");
> > -		force_quota_check = true;
> > -	}
> > -	if (to->sb_qflags & XFS_OQUOTA_ENFD)
> > -		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> > -					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
> > -	if (to->sb_qflags & XFS_OQUOTA_CHKD)
> > -		to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> > -					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
> > -	to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> > -
> >  	to->sb_flags = from->sb_flags;
> >  	to->sb_shared_vn = from->sb_shared_vn;
> >  	to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
> > @@ -636,6 +621,44 @@ xfs_sb_from_disk(
> >  	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
> >  	to->sb_lsn = be64_to_cpu(from->sb_lsn);
> >  
> > +	if (xfs_sb_version_has_pquota(to)) {
> > +		if (to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) {
> > +			xfs_notice(NULL, "Super block has XFS_OQUOTA bits "
> > +			"with version PQUOTINO. Quota check forced.\n");
> > +			to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> > +			force_quota_check = true;
> > +		}
> > +		to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
> > +	} else {
> > +		if (to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> > +					XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) {
> > +			xfs_notice(NULL, "Super block has XFS_[G|P]UOTA "
> > +				"bits in version older than PQUOTINO. "
> > +				"Quota check forced.\n");
> > +
> > +			to->sb_qflags &= ~(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
> > +					XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD);
> > +			force_quota_check = true;
> > +		}
> > +
> > +		/*
> > +		 * On disk superblock qflags uses XFS_OQUOTA.* to support
> > +		 * either PQUOTA or GQUOTA. But, in memory qflags uses
> > +		 * XFS_PQUOTA.* or XFS_GQUOTA.* depending on which quota
> > +		 * is used.
> > +		 * Following block translates XFS_OQUOTA.* to either
> > +		 * GQUOTA or PQUOTA.
> > +		 */
> > +		if (to->sb_qflags & XFS_OQUOTA_ENFD)
> > +			to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> > +					XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
> > +		if (to->sb_qflags & XFS_OQUOTA_CHKD)
> > +			to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
> > +					XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
> > +		to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
> > +
> > +	}
> > +
> >  	if (force_quota_check)
> >  		to->sb_qflags &= ~(XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD);
> >  }
> 
> This all gets restructured here - as per my previous comments, this
> probably should all be in xfs_readsb(), not here.
> 
> > @@ -657,27 +680,51 @@ xfs_sb_to_disk(
> >  	int		first;
> >  	int		size;
> >  	__uint16_t	qflags = from->sb_qflags;
> > +	xfs_ino_t	gquotino = from->sb_gquotino;
> >  
> >  	ASSERT(fields);
> >  	if (!fields)
> >  		return;
> >  
> > -	if (fields & XFS_SB_QFLAGS) {
> > +	if (!xfs_sb_version_has_pquota(from)) {
> 
> This should be moved to a separate function, I think.
> 
> > +		if (fields & XFS_SB_QFLAGS) {
> > +			/*
> > +			 * The in-core version of sb_qflags do not have
> > +			 * XFS_OQUOTA_* flags, whereas the on-disk version
> > +			 * does.  So, convert incore XFS_{PG}QUOTA_* flags
> > +			 * to on-disk XFS_OQUOTA_* flags.
> > +			 */
> > +			qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
> > +					XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
> > +
> > +			if (from->sb_qflags &
> > +					(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
> > +				qflags |= XFS_OQUOTA_ENFD;
> > +			if (from->sb_qflags &
> > +					(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
> > +				qflags |= XFS_OQUOTA_CHKD;
> 
> Now that we have the new flags set correct, write it directly to
> to->sb_qflags and clear XFS_SB_QFLAGS from the fields varaible.

So, you are suggesting to move this block of functionality to a new
function, and set the fields in the "to" data structure in that function
and clear the appropriate bits in the same function ?
  
> 
> > +		}
> > +
> >  		/*
> > -		 * The in-core version of sb_qflags do not have
> > -		 * XFS_OQUOTA_* flags, whereas the on-disk version
> > -		 * does.  So, convert incore XFS_{PG}QUOTA_* flags 
> > -		 * to on-disk XFS_OQUOTA_* flags.
> > +		 * On-disk version earlier than pquota doesn't have
> > +		 * sb_pquotino. so, we need to copy the value to gquotino.
> >  		 */
> > -		qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
> > -				XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
> > +		if (fields & XFS_SB_PQUOTINO) {
> > +			fields &= (__int64_t)~XFS_SB_PQUOTINO;
> > +			fields |= (__int64_t)XFS_SB_GQUOTINO;
> > +			gquotino = from->sb_pquotino;
> > +		}
> 
> Same here - write the inode number directly to the to->sb_gquotino
> field and clear the XFS_SB_PQUOTINO flag.
> 
> >  
> > -		if (from->sb_qflags &
> > -				(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
> > -			qflags |= XFS_OQUOTA_ENFD;
> > -		if (from->sb_qflags &
> > -				(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
> > -			qflags |= XFS_OQUOTA_CHKD;
> > +		/* If any quota inodes are written, write all quota inodes */
> > +		if (fields & (XFS_SB_UQUOTINO|XFS_SB_GQUOTINO))
> > +			fields |= (XFS_SB_UQUOTINO|XFS_SB_GQUOTINO);
> 
> Why write things that haven't been modified?

fixed it
> 
> > +
> > +	} else {
> > +		/* If any quota inodes are written, write all quota inodes */
> > +		if (fields & (XFS_SB_UQUOTINO | XFS_SB_GQUOTINO
> > +							| XFS_SB_PQUOTINO))
> > +			fields |= (XFS_SB_UQUOTINO | XFS_SB_GQUOTINO
> > +							| XFS_SB_PQUOTINO);
> 
> Same - the flags pssed in are supposed to document everything that
> has been modified. If the flags passed in are wrong, then fix the
> bad callers.....

fixed it.
> >  	}
> 
> >  
> >  	while (fields) {
> > @@ -691,6 +738,8 @@ xfs_sb_to_disk(
> >  			memcpy(to_ptr + first, from_ptr + first, size);
> >  		} else if (f == XFS_SBS_QFLAGS) {
> >  			*(__be16 *)(to_ptr + first) = cpu_to_be16(qflags);
> > +		} else if (f == XFS_SBS_GQUOTINO) {
> > +			*(__be64 *)(to_ptr + first) = cpu_to_be64(gquotino);
> 
> If we clear the XFS_SBS_GQUOTINO/XFS_SBS_QFLAGS flags like I
> suggested above, this grot can go away and the loop remain
> completely generic.

sure.
> 
> >  		} else {
> >  			switch (size) {
> >  			case 2:
> > @@ -872,6 +921,18 @@ reread:
> >  	 */
> >  	xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
> >  
> > +	if (!xfs_sb_version_has_pquota(&mp->m_sb) && XFS_IS_PQUOTA_ON(mp)) {
> > +		/*
> > +		 * On disk superblock only has sb_gquotino, and in memory
> > +		 * superblock has both sb_gquotino and sb_pquotino. But,
> > +		 * only one them is supported at any point of time.
> > +		 * So, if PQUOTA is set in disk superblock, copy over
> > +		 * sb_gquotino to sb_pquotino.
> > +		 */
> > +		mp->m_sb.sb_pquotino = mp->m_sb.sb_gquotino;
> > +		mp->m_sb.sb_gquotino = NULLFSINO;
> > +	}
> 
> Yup, that's the right place for doing all this on-disk->incore
> translation stuff at mount time ;)
> 
> > -	if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
> > +	if (ino == mp->m_sb.sb_uquotino ||
> > +	    ino == mp->m_sb.sb_gquotino ||
> > +	    ino == mp->m_sb.sb_pquotino) {
> 
> Seeing how often this is repeated, perhaps we need a helper function
> called "xfs_is_quota_inode(mp, ino)"?

will do.
> 
> > @@ -1505,7 +1506,7 @@ xfs_qm_init_quotainos(
> >  	}
> >  	if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
> >  		error = xfs_qm_qino_alloc(mp, &pip,
> > -					     sbflags | XFS_SB_GQUOTINO,
> > +					     sbflags | XFS_SB_PQUOTINO,
> >  					     flags | XFS_QMOPT_PQUOTA);
> 
> Isn't that fixing a bug in the previous patch?

No, pquotino is not being used until this function.

> 
> > @@ -412,17 +413,20 @@ xfs_qm_scall_getqstat(
> >  	struct fs_quota_stat	*out)
> >  {
> >  	struct xfs_quotainfo	*q = mp->m_quotainfo;
> > -	struct xfs_inode	*uip, *gip;
> > -	bool                    tempuqip, tempgqip;
> > +	struct xfs_inode	*uip = NULL;
> > +	struct xfs_inode	*gip = NULL;
> > +	struct xfs_inode	*pip = NULL;
> > +	bool                    tempuqip = false;
> > +	bool                    tempgqip = false;
> > +	bool                    temppqip = false;
> 
> See my previous comments about naming variables. At least
> add an underscore into the name like temp_uqip....
> 

why not.

> > @@ -420,12 +420,6 @@ xfs_parseargs(
> >  	}
> >  #endif
> >  
> > -	if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
> > -	    (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE))) {
> > -		xfs_warn(mp, "cannot mount with both project and group quota");
> > -		return EINVAL;
> > -	}
> > -
> >  	if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
> >  		xfs_warn(mp, "sunit and swidth must be specified together");
> >  		return EINVAL;
> > @@ -1388,6 +1382,14 @@ xfs_finish_flags(
> >  		return XFS_ERROR(EROFS);
> >  	}
> >  
> > +	if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
> > +	    (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE)) &&
> > +	    !xfs_sb_version_has_pquota(&mp->m_sb)) {
> > +		xfs_warn(mp, "Super block does not support "
> > +				 "project and group quota together");
> > +		return XFS_ERROR(EINVAL);
> > +	}
> 
> Why move this check? just leave it where it is and add the extra
> check to it...

Superblock hasn't been read yet at the old place. So, this block has to
be moved to a place after superblock is read.

> 
> > @@ -157,7 +157,8 @@ xfs_trans_mod_dquot_byino(
> >  	if (!XFS_IS_QUOTA_RUNNING(mp) ||
> >  	    !XFS_IS_QUOTA_ON(mp) ||
> >  	    ip->i_ino == mp->m_sb.sb_uquotino ||
> > -	    ip->i_ino == mp->m_sb.sb_gquotino)
> > +	    ip->i_ino == mp->m_sb.sb_gquotino ||
> > +	    ip->i_ino == mp->m_sb.sb_pquotino)
> >  		return;
> 
> I see a helper....
> 
> >  	if (tp->t_dqinfo == NULL)
> > @@ -825,6 +826,7 @@ xfs_trans_reserve_quota_nblks(
> >  
> >  	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_pquotino);
> 
> And that becomes ASSERT(!xfs_is_quota_inode(mp, ip->i_ino))....
> 
> > diff --git a/include/uapi/linux/dqblk_xfs.h b/include/uapi/linux/dqblk_xfs.h
> > index 8655280..f17e3bb 100644
> > --- a/include/uapi/linux/dqblk_xfs.h
> > +++ b/include/uapi/linux/dqblk_xfs.h
> > @@ -155,6 +155,7 @@ typedef struct fs_quota_stat {
> >  	__s8		qs_pad;		/* unused */
> >  	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
> >  	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
> > +#define qs_pquota	qs_gquota
> >  	__u32		qs_incoredqs;	/* number of dquots incore */
> >  	__s32		qs_btimelimit;  /* limit for blks timer */	
> >  	__s32		qs_itimelimit;  /* limit for inodes timer */	
> 
> Ugly, but will do until the next patch ;)
> 
> Cheers,
> 
> Dave.


_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 4/5] xfs: Add proper versioning support to fs_quota_stat
  2013-05-17  5:10   ` Dave Chinner
@ 2013-05-24 22:17     ` Chandra Seetharaman
  2013-06-10 23:27       ` Dave Chinner
  0 siblings, 1 reply; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-24 22:17 UTC (permalink / raw)
  To: Dave Chinner; +Cc: xfs

On Fri, 2013-05-17 at 15:10 +1000, Dave Chinner wrote:
> On Fri, May 10, 2013 at 04:21:28PM -0500, Chandra Seetharaman wrote:
> > Added appropriate pads and code for backward compatibility.
> > 
> > Copied over the old version as it is different from the newer padded
> > version.
> > 
> > New callers of the system call have to just set the version of the data
> > structure being passed, and kernel will fill as much data as requested.
> > 
> > Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
> 
> This needs to be cc'd to Steve Whitehouse so he's aware that we are
> changing the quota interface...

Will do.

> 
> > ---
> >  fs/gfs2/quota.c                |    3 ---
> >  fs/quota/quota.c               |   40 ++++++++++++++++++++++++++++++++++++++--
> >  fs/xfs/xfs_qm_syscalls.c       |    4 ----
> >  include/uapi/linux/dqblk_xfs.h |   38 ++++++++++++++++++++++++++++++++++++--
> >  4 files changed, 74 insertions(+), 11 deletions(-)
> > 
> > diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
> > index c7c840e..ca0dccd 100644
> > --- a/fs/gfs2/quota.c
> > +++ b/fs/gfs2/quota.c
> > @@ -1443,9 +1443,6 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
> >  {
> >  	struct gfs2_sbd *sdp = sb->s_fs_info;
> >  
> > -	memset(fqs, 0, sizeof(struct fs_quota_stat));
> > -	fqs->qs_version = FS_QSTAT_VERSION;
> > -
> >  	switch (sdp->sd_args.ar_quota) {
> >  	case GFS2_QUOTA_ON:
> >  		fqs->qs_flags |= (FS_QUOTA_UDQ_ENFD | FS_QUOTA_GDQ_ENFD);
> > diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> > index c7314f1..510464e 100644
> > --- a/fs/quota/quota.c
> > +++ b/fs/quota/quota.c
> > @@ -207,12 +207,48 @@ static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
> >  static int quota_getxstate(struct super_block *sb, void __user *addr)
> >  {
> >  	struct fs_quota_stat fqs;
> > -	int ret;
> > +	struct fs_quota_stat_v1 fqs_v1;
> > +	int ret, size;
> > +	void *cp = &fqs;
> 
> What's "cp" mean? Wouldn't fqsp be a better name? And initialise it
> just before it gets used makes more sense, too.
> 
will do

> >  
> >  	if (!sb->s_qcop->get_xstate)
> >  		return -ENOSYS;
> > +
> > +	memset(&fqs, 0, sizeof(struct fs_quota_stat));
> > +	if (copy_from_user(&fqs, addr, 1)) /* just get the version */
> > +		return -EFAULT;
> > +
> > +	switch (fqs.qs_version) {
> > +	case FS_QSTAT_VERSION_2:
> > +		size = FS_QSTAT_V2_SIZE;
> > +		break;
> > +	default:
> > +		fqs.qs_version = FS_QSTAT_VERSION;
> > +		/* fallthrough */
> > +	case FS_QSTAT_VERSION:
> > +		size = FS_QSTAT_V1_SIZE;
> > +		cp = &fqs_v1;
> > +	}
> 
> Missing a break on the last case there.
will add.

> 
> > +
> >  	ret = sb->s_qcop->get_xstate(sb, &fqs);
> > -	if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
> > +	if (ret)
> > +		return ret;
> > +
> > +	if (fqs.qs_version == FS_QSTAT_VERSION) {
> > +		fqs_v1.qs_version = fqs.qs_version;
> > +		fqs_v1.qs_flags = fqs.qs_flags;
> > +		fqs_v1.qs_pad = 0;
> > +		fqs_v1.qs_uquota = fqs.qs_uquota;
> > +		fqs_v1.qs_gquota = fqs.qs_gquota;
> > +		fqs_v1.qs_incoredqs = fqs.qs_incoredqs;
> > +		fqs_v1.qs_btimelimit = fqs.qs_btimelimit;
> > +		fqs_v1.qs_itimelimit = fqs.qs_itimelimit;
> > +		fqs_v1.qs_rtbtimelimit = fqs.qs_rtbtimelimit;
> > +		fqs_v1.qs_bwarnlimit = fqs.qs_bwarnlimit;
> > +		fqs_v1.qs_iwarnlimit = fqs.qs_iwarnlimit;
> 
> 		fsqp = &fsq_v1;
> 	} else {
> 		fsqp = &fsq_v2;
> 	}
> 
sure

> > +
> > +	if (copy_to_user(addr, &cp, size))
> >  		return -EFAULT;
> >  	return ret;
> >  }
> > diff --git a/include/uapi/linux/dqblk_xfs.h b/include/uapi/linux/dqblk_xfs.h
> > index f17e3bb..d9629c1 100644
> > --- a/include/uapi/linux/dqblk_xfs.h
> > +++ b/include/uapi/linux/dqblk_xfs.h
> > @@ -18,6 +18,7 @@
> >  #define _LINUX_DQBLK_XFS_H
> >  
> >  #include <linux/types.h>
> > +#include <linux/stddef.h>
> 
> Really? What's new that requires this include?

will fix.

> 
> >  
> >  /*
> >   * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM).
> > @@ -137,8 +138,12 @@ typedef struct fs_disk_quota {
> >   * Provides a centralized way to get meta information about the quota subsystem.
> >   * eg. space taken up for user and group quotas, number of dquots currently
> >   * incore.
> > + * User space caller should set qs_version to the appropriate version
> > + * of the fs_quota_stat data structure they are providing. Not providing
> > + * a version will be treated as FS_QSTAT_VERSION.
> >   */
> >  #define FS_QSTAT_VERSION	1	/* fs_quota_stat.qs_version */
> > +#define FS_QSTAT_VERSION_2	2	/* new field qs_pquota */
> >  
> >  /*
> >   * Some basic information about 'quota files'.
> > @@ -149,19 +154,48 @@ typedef struct fs_qfilestat {
> >  	__u32		qfs_nextents;	/* number of extents */
> >  } fs_qfilestat_t;
> >  
> > +typedef struct fs_quota_stat_v1 {
> 
> Kill the typedef. Add a comment stating that this structure is
> likely to have compatibility problems across architectures due to
> implicit padding and offset alignment in the structure definition
> and that the v2 structure should be used if these problems are being
> seen.

will do
> 
> > +	__s8		qs_version;	/* version number for future changes */
> > +	__u16		qs_flags;	/* FS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
> > +	__u8		qs_pad;		/* unused */
> > +	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
> > +	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
> > +	__u32		qs_incoredqs;	/* number of dquots incore */
> > +	__s32		qs_btimelimit;  /* limit for blks timer */	
> > +	__s32		qs_itimelimit;  /* limit for inodes timer */	
> > +	__s32		qs_rtbtimelimit;/* limit for rt blks timer */	
> > +	__u16		qs_bwarnlimit;	/* limit for num warnings */
> > +	__u16		qs_iwarnlimit;	/* limit for num warnings */
> > +} fs_quota_stat_v1_t;
> > +
> >  typedef struct fs_quota_stat {
> 
> Kill the typedef.
> 
> >  	__s8		qs_version;	/* version number for future changes */
> > +	__u8		qs_pad1;	/* unused */
> >  	__u16		qs_flags;	/* FS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
> > -	__s8		qs_pad;		/* unused */
> > +	__u8		qs_pad2[4];	/* unused */
> >  	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
> >  	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
> > -#define qs_pquota	qs_gquota
> >  	__u32		qs_incoredqs;	/* number of dquots incore */
> >  	__s32		qs_btimelimit;  /* limit for blks timer */	
> >  	__s32		qs_itimelimit;  /* limit for inodes timer */	
> >  	__s32		qs_rtbtimelimit;/* limit for rt blks timer */	
> >  	__u16		qs_bwarnlimit;	/* limit for num warnings */
> >  	__u16		qs_iwarnlimit;	/* limit for num warnings */
> > +	__u8		qs_pad3[4];	/* unused */
> > +	fs_qfilestat_t	qs_pquota;	/* project quota storage information */
> > +	/* End of Data structure for FS_QSTAT_VERSION_2 */
> 
> No need for that comment.
> 
> >  } fs_quota_stat_t;
> 
> Use pahole on the built object file to determine if the end ofthe
> structure is 64 bit aligned. If it isn't, please pad it to 64 bit
> alignment.

sure.
> 
> Um. fs_qfilestat_t is { u64, u64, u32 }, and so there's going to be
> alignment problems with that. We need a fs_qfilestat_v1 definition
> and add padding to fs_qfilestat_t so that it is 64 bit aligned.....
> 

will do.

> 
> >  
> > +/*
> > + * Since Version 1 did not have padding at appropriate places,
> > + * a new data structure has been defined for the older version to
> > + * provide backward compatibility.
> > + * Future extentions of this data structure won't require new
> > + * data structure definitions as the current one can be extended
> > + * with the logic and padding in place now.
> > + */
> > +#define FS_QSTAT_V1_SIZE	(sizeof(struct fs_quota_stat_v1))
> > +#define FS_QSTAT_V2_SIZE	(offsetof(struct fs_quota_stat, qs_pquota) + \
> > +					sizeof(fs_qfilestat_t))
> 
> Just use sizeof(struct fs_quota_stat) as the size. Indeed, for

My thinking w.r.t not making it sizeof (fs_quota_stat) is ...future
changes doesn't have to touch the macro definitions of earlier versions,
they can define a new macro just by copying the last V?_SIZE macro and
changing the last field name.

> future enhancements, maybe we should add 64 bytes of empty space at
> the end of the structure....

Since this version is fully backward compatible, I didn't think a future
pad was needed. Do you want me to add ?
> Cheers,
> 
> Dave.


_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 5/5] xfs: Use new qs_pquota field in fs_quota_stat for Q_XGETQSTAT
  2013-05-17  5:14   ` Dave Chinner
@ 2013-05-24 22:17     ` Chandra Seetharaman
  0 siblings, 0 replies; 29+ messages in thread
From: Chandra Seetharaman @ 2013-05-24 22:17 UTC (permalink / raw)
  To: Dave Chinner; +Cc: xfs

On Fri, 2013-05-17 at 15:14 +1000, Dave Chinner wrote:
> On Fri, May 10, 2013 at 04:21:29PM -0500, Chandra Seetharaman wrote:
> > For the Q_XGETQSTAT quota command, if the new version of fs_quota_stat
> > data structure is used, fill the project quota information.
> > 
> > Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
> > ---
> >  fs/xfs/xfs_qm_syscalls.c |   39 +++++++++++++++++++++++++--------------
> >  1 files changed, 25 insertions(+), 14 deletions(-)
> > 
> > diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> > index c27b0e4..7c5876b 100644
> > --- a/fs/xfs/xfs_qm_syscalls.c
> > +++ b/fs/xfs/xfs_qm_syscalls.c
> > @@ -420,20 +420,14 @@ xfs_qm_scall_getqstat(
> >  	bool                    tempgqip = false;
> >  	bool                    temppqip = false;
> >  
> > -	if (!xfs_sb_version_hasquota(&mp->m_sb)) {
> > -		out->qs_uquota.qfs_ino = NULLFSINO;
> > -		out->qs_gquota.qfs_ino = NULLFSINO;
> > -		out->qs_pquota.qfs_ino = NULLFSINO;
> > +	out->qs_uquota.qfs_ino = NULLFSINO;
> > +	out->qs_gquota.qfs_ino = NULLFSINO;
> > +	out->qs_pquota.qfs_ino = NULLFSINO;
> > +
> > +	if (!xfs_sb_version_hasquota(&mp->m_sb))
> >  		return (0);
> > -	}
> >  	out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
> > -							(XFS_ALL_QUOTA_ACCT|
> > -							 XFS_ALL_QUOTA_ENFD));
> > -	out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
> > -	out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
> > -	if (&out->qs_gquota != &out->qs_pquota)
> > -		out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino;
> > -
> > +				(XFS_ALL_QUOTA_ACCT| XFS_ALL_QUOTA_ENFD));
> >  	if (q) {
> >  		uip = q->qi_uquotaip;
> >  		gip = q->qi_gquotaip;
> > @@ -454,21 +448,38 @@ xfs_qm_scall_getqstat(
> >  					0, 0, &pip) == 0)
> >  			temppqip = true;
> >  	}
> > +
> >  	if (uip) {
> > +		out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
> >  		out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
> >  		out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
> >  		if (tempuqip)
> >  			IRELE(uip);
> >  	}
> >  	if (gip) {
> > +		out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
> >  		out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
> >  		out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
> >  		if (tempgqip)
> >  			IRELE(gip);
> >  	}
> >  	if (pip) {
> > -		out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks;
> > -		out->qs_pquota.qfs_nextents = pip->i_d.di_nextents;
> > +		if (out->qs_version >= FS_QSTAT_VERSION_2) {
> > +			out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino;
> > +			out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks;
> > +			out->qs_pquota.qfs_nextents = pip->i_d.di_nextents;
> > +		} else {
> > +			/*
> > +			 * In FS_QSTAT_VERSION version, there is no
> > +			 * qs_pquota, and there is no combined support
> > +			 * for gquota/pquota. qs_gquota is shared for
> > +			 * providing the pquota/gquota information to
> > +			 * the user space.
> > +			 */
> 
> Move that comment to the head of the function. i.e.:
> 
> /*
>  * We support two different versions of the fs_quota_stat structure
>  * here. If the version is FS_QSTAT_VERSION, then there is no
>  * separate project quota fields, and so we write project quota
>  * information into the group quota fields. With FS_QSTAT_VERSION_2,
>  * there is a separate project quota field so we can use that
>  * instead to pass both group and project quota back to user space
>  * in the one call.
>  */
> 
sure
> Cheers,
> 
> Dave.


_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 2/5] xfs: Add pquota fields where gquota is used.
  2013-05-24 21:57     ` Chandra Seetharaman
@ 2013-06-10 23:17       ` Dave Chinner
  2013-06-11 23:08         ` Chandra Seetharaman
  0 siblings, 1 reply; 29+ messages in thread
From: Dave Chinner @ 2013-06-10 23:17 UTC (permalink / raw)
  To: Chandra Seetharaman; +Cc: xfs

On Fri, May 24, 2013 at 04:57:05PM -0500, Chandra Seetharaman wrote:
> On Fri, 2013-05-17 at 14:23 +1000, Dave Chinner wrote: 
> > On Fri, May 10, 2013 at 04:21:26PM -0500, Chandra Seetharaman wrote:
> > > Add project quota changes to all the places where group quota field
> > > is used:
> > >    * add separate project quota members into various structures
> > >    * split project quota and group quotas so that instead of overriding
> > >      the group quota members incore, the new project quota members are
> > >      used instead
> > >    * get rid of usage of the OQUOTA flag incore, in favor of separate
> > >    * group
> > >      and project quota flags.
> > >    * add a project dquot argument to various functions.
> > > 
> > > No externally visible interfaces changed.
> > 
> > Looks pretty good. Some relatively minor changes below.
.....
> > >  		if (code)
> > >  			return code;
> > >  	}
> > > @@ -994,8 +994,8 @@ xfs_ioctl_setattr(
> > >  		    XFS_IS_PQUOTA_ON(mp) &&
> > >  		    xfs_get_projid(ip) != fa->fsx_projid) {
> > >  			ASSERT(tp);
> > > -			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
> > > -						capable(CAP_FOWNER) ?
> > > +			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL,
> > > +						pdqp, capable(CAP_FOWNER) ?
> > >  						XFS_QMOPT_FORCE_RES : 0);
> > > @@ -1113,7 +1113,7 @@ xfs_ioctl_setattr(
> > >  		if (xfs_get_projid(ip) != fa->fsx_projid) {
> > >  			if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
> > >  				olddquot = xfs_qm_vop_chown(tp, ip,
> > > -							&ip->i_gdquot, gdqp);
> > > +							&ip->i_pdquot, pdqp);
> > 
> > xfs_qm_vop_chown() is only called on one dquot at a time, so it can
> > only exchange one dquot at a time. and udqp is not used for hints,
> > so it looks to me like udqp and gdqp are wholly unnecessary in this
> > function....
> 
> Did not fully understand this comment. Can you please elaborate ?

What I was saying here is that throughout the function udqp and gdqp
are passed to the various quota functions, but they are not used at
all by the functions being called. i.e. you could pass NULL instead,
and the code would still function identically. IOWs, we don't
actually need to define anything other than the project quota
related variables...

> > > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> > > index d82efaa..7c54ea4 100644
> > > --- a/fs/xfs/xfs_iops.c
> > > +++ b/fs/xfs/xfs_iops.c
> > > @@ -517,7 +517,7 @@ xfs_setattr_nonsize(
> > >  		ASSERT(udqp == NULL);
> > >  		ASSERT(gdqp == NULL);
> > >  		error = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip),
> > > -					 qflags, &udqp, &gdqp);
> > > +					 qflags, &udqp, &gdqp, NULL);
> > 
> > Why is there no project quota support here, even though we pass in a
> > project ID? I know the answer, but please add a comment so that a
> > couple of years down the track I don't need to go remind myself of
> > why....
> 
> Not clear what you are expecting here.

I'm expecting you to write a comment explaining why we pass
uid/gid/projid to the xfs_qm_vop_dqalloc() function, but then only
pass udqp and gdqp but NULL instead of a project quota dquot
pointer. Indeed, I already don't remember why this is a valid, so it
clearly needs a comment explaining it....


> > 
> > 
> > 			qino = xfs_sb_version_has_pquota(&mp->m_sb) ?
> > 						mp->m_sb.sb_pquotino :
> > 						mp->m_sb.sb_gquotino;
> > 
> > And the correct on-disk inode is read....
> > 
> The object of this patch is to replace all gquota with pquota stuff. I
> am not using the pquotino or xfs_sb_version_has_pquota() until patch 3.
> 
> If I get the change forward, I have to merge patch 3 and part of this
> patch into patch 1, which adds up lots of work.
> 
> The way the patches are split now, IMO, is easy to follow and works
> independently.

That's fine. I review the patches one by one, so I make comments
that are relevant to the current patch context. It may be that you
changed it in a later patch and that often is fine - comments like
this indicate that perhaps the commit message hasn't quite described
the full context of the patch within the series correctly...

> > > +	if (pdqp) {
> > > +		ASSERT(ip->i_pdquot == NULL);
> > > +		ASSERT(XFS_IS_PQUOTA_ON(mp));
> > > +		ASSERT(xfs_get_projid(ip) == be32_to_cpu(pdqp->q_core.d_id));
> > > +
> > > +		ip->i_pdquot = xfs_qm_dqhold(pdqp);
> > > +		xfs_trans_mod_dquot(tp, pdqp, XFS_TRANS_DQ_ICOUNT, 1);
> > > +	}
> > >  }
> > 
> > Something this just triggered. All transaction reservations that
> > reserve space for dquots need to be upped from 2 to 3 dquots.
> 
> Can you elaborate please.

A transaction ithat modifies space can now modify 3 dquots (u+g+p)
instead of only 2 (u+(g or p)), and so the log space for any such 
transaction goes up. It may be that you've already handled this, but
if you're asking for an explanation then maybe not :/

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 3/5] xfs: Start using pquotaino from the superblock
  2013-05-24 22:09     ` Chandra Seetharaman
@ 2013-06-10 23:20       ` Dave Chinner
  0 siblings, 0 replies; 29+ messages in thread
From: Dave Chinner @ 2013-06-10 23:20 UTC (permalink / raw)
  To: Chandra Seetharaman; +Cc: xfs

On Fri, May 24, 2013 at 05:09:03PM -0500, Chandra Seetharaman wrote:
> On Fri, 2013-05-17 at 14:46 +1000, Dave Chinner wrote:
> > On Fri, May 10, 2013 at 04:21:27PM -0500, Chandra Seetharaman wrote:
> > > Define a macro to check if the superblock has pquotino.
> > > 
> > > Keep backward compatibilty by alowing mount of older superblock
> > > with no separate pquota inode.
> > ....
> > 
> > > @@ -657,27 +680,51 @@ xfs_sb_to_disk(
> > >  	int		first;
> > >  	int		size;
> > >  	__uint16_t	qflags = from->sb_qflags;
> > > +	xfs_ino_t	gquotino = from->sb_gquotino;
> > >  
> > >  	ASSERT(fields);
> > >  	if (!fields)
> > >  		return;
> > >  
> > > -	if (fields & XFS_SB_QFLAGS) {
> > > +	if (!xfs_sb_version_has_pquota(from)) {
> > 
> > This should be moved to a separate function, I think.
> > 
> > > +		if (fields & XFS_SB_QFLAGS) {
> > > +			/*
> > > +			 * The in-core version of sb_qflags do not have
> > > +			 * XFS_OQUOTA_* flags, whereas the on-disk version
> > > +			 * does.  So, convert incore XFS_{PG}QUOTA_* flags
> > > +			 * to on-disk XFS_OQUOTA_* flags.
> > > +			 */
> > > +			qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
> > > +					XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
> > > +
> > > +			if (from->sb_qflags &
> > > +					(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
> > > +				qflags |= XFS_OQUOTA_ENFD;
> > > +			if (from->sb_qflags &
> > > +					(XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
> > > +				qflags |= XFS_OQUOTA_CHKD;
> > 
> > Now that we have the new flags set correct, write it directly to
> > to->sb_qflags and clear XFS_SB_QFLAGS from the fields varaible.
> 
> So, you are suggesting to move this block of functionality to a new
> function, and set the fields in the "to" data structure in that function
> and clear the appropriate bits in the same function ?

Yes.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 4/5] xfs: Add proper versioning support to fs_quota_stat
  2013-05-24 22:17     ` Chandra Seetharaman
@ 2013-06-10 23:27       ` Dave Chinner
  2013-06-11 23:13         ` Chandra Seetharaman
  0 siblings, 1 reply; 29+ messages in thread
From: Dave Chinner @ 2013-06-10 23:27 UTC (permalink / raw)
  To: Chandra Seetharaman; +Cc: xfs

On Fri, May 24, 2013 at 05:17:22PM -0500, Chandra Seetharaman wrote:
> On Fri, 2013-05-17 at 15:10 +1000, Dave Chinner wrote:
> > On Fri, May 10, 2013 at 04:21:28PM -0500, Chandra Seetharaman wrote:
> > > Added appropriate pads and code for backward compatibility.
> > > 
> > > Copied over the old version as it is different from the newer padded
> > > version.
> > > 
> > > New callers of the system call have to just set the version of the data
> > > structure being passed, and kernel will fill as much data as requested.
> > > 
> > > Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
> > 
> > This needs to be cc'd to Steve Whitehouse so he's aware that we are
> > changing the quota interface...

> > > +/*
> > > + * Since Version 1 did not have padding at appropriate places,
> > > + * a new data structure has been defined for the older version to
> > > + * provide backward compatibility.
> > > + * Future extentions of this data structure won't require new
> > > + * data structure definitions as the current one can be extended
> > > + * with the logic and padding in place now.
> > > + */
> > > +#define FS_QSTAT_V1_SIZE	(sizeof(struct fs_quota_stat_v1))
> > > +#define FS_QSTAT_V2_SIZE	(offsetof(struct fs_quota_stat, qs_pquota) + \
> > > +					sizeof(fs_qfilestat_t))
> > 
> > Just use sizeof(struct fs_quota_stat) as the size. Indeed, for
> 
> My thinking w.r.t not making it sizeof (fs_quota_stat) is ...future
> changes doesn't have to touch the macro definitions of earlier versions,
> they can define a new macro just by copying the last V?_SIZE macro and
> changing the last field name.

If we need a future revision, we can deal with the structure
differences and versions at that point in time. Second guessing
unknown future requirements is not necessary. ;)

> > future enhancements, maybe we should add 64 bytes of empty space at
> > the end of the structure....
> 
> Since this version is fully backward compatible, I didn't think a future
> pad was needed. Do you want me to add ?

We only really need to change the structure version when we change
input parameters, the size or the shape of the structure being
passed in from userspace. If we add padding now, then we can expand
output of the call without needing to bump the version of the
structure. Old code simply won't know (or care) about the new output
in the region of the structure it considers empty padding....

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 2/5] xfs: Add pquota fields where gquota is used.
  2013-06-10 23:17       ` Dave Chinner
@ 2013-06-11 23:08         ` Chandra Seetharaman
  0 siblings, 0 replies; 29+ messages in thread
From: Chandra Seetharaman @ 2013-06-11 23:08 UTC (permalink / raw)
  To: Dave Chinner; +Cc: xfs

On Tue, 2013-06-11 at 09:17 +1000, Dave Chinner wrote:
> On Fri, May 24, 2013 at 04:57:05PM -0500, Chandra Seetharaman wrote:
> > On Fri, 2013-05-17 at 14:23 +1000, Dave Chinner wrote: 
> > > On Fri, May 10, 2013 at 04:21:26PM -0500, Chandra Seetharaman wrote:
> > > > Add project quota changes to all the places where group quota field
> > > > is used:
> > > >    * add separate project quota members into various structures
> > > >    * split project quota and group quotas so that instead of overriding
> > > >      the group quota members incore, the new project quota members are
> > > >      used instead
> > > >    * get rid of usage of the OQUOTA flag incore, in favor of separate
> > > >    * group
> > > >      and project quota flags.
> > > >    * add a project dquot argument to various functions.
> > > > 
> > > > No externally visible interfaces changed.
> > > 
> > > Looks pretty good. Some relatively minor changes below.
> .....
> > > >  		if (code)
> > > >  			return code;
> > > >  	}
> > > > @@ -994,8 +994,8 @@ xfs_ioctl_setattr(
> > > >  		    XFS_IS_PQUOTA_ON(mp) &&
> > > >  		    xfs_get_projid(ip) != fa->fsx_projid) {
> > > >  			ASSERT(tp);
> > > > -			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
> > > > -						capable(CAP_FOWNER) ?
> > > > +			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL,
> > > > +						pdqp, capable(CAP_FOWNER) ?
> > > >  						XFS_QMOPT_FORCE_RES : 0);
> > > > @@ -1113,7 +1113,7 @@ xfs_ioctl_setattr(
> > > >  		if (xfs_get_projid(ip) != fa->fsx_projid) {
> > > >  			if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
> > > >  				olddquot = xfs_qm_vop_chown(tp, ip,
> > > > -							&ip->i_gdquot, gdqp);
> > > > +							&ip->i_pdquot, pdqp);
> > > 
> > > xfs_qm_vop_chown() is only called on one dquot at a time, so it can
> > > only exchange one dquot at a time. and udqp is not used for hints,
> > > so it looks to me like udqp and gdqp are wholly unnecessary in this
> > > function....
> > 
> > Did not fully understand this comment. Can you please elaborate ?
> 
> What I was saying here is that throughout the function udqp and gdqp
> are passed to the various quota functions, but they are not used at
> all by the functions being called. i.e. you could pass NULL instead,
> and the code would still function identically. IOWs, we don't
> actually need to define anything other than the project quota
> related variables...

I see...
You want me to get rid of uid/gid usages from this context ? and pid
information from xfs_setattr_nonsize() function ?

> 
> > > > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> > > > index d82efaa..7c54ea4 100644
> > > > --- a/fs/xfs/xfs_iops.c
> > > > +++ b/fs/xfs/xfs_iops.c
> > > > @@ -517,7 +517,7 @@ xfs_setattr_nonsize(
> > > >  		ASSERT(udqp == NULL);
> > > >  		ASSERT(gdqp == NULL);
> > > >  		error = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip),
> > > > -					 qflags, &udqp, &gdqp);
> > > > +					 qflags, &udqp, &gdqp, NULL);
> > > 
> > > Why is there no project quota support here, even though we pass in a
> > > project ID? I know the answer, but please add a comment so that a
> > > couple of years down the track I don't need to go remind myself of
> > > why....
> > 
> > Not clear what you are expecting here.
> 
> I'm expecting you to write a comment explaining why we pass
> uid/gid/projid to the xfs_qm_vop_dqalloc() function, but then only
> pass udqp and gdqp but NULL instead of a project quota dquot
> pointer. Indeed, I already don't remember why this is a valid, so it
> clearly needs a comment explaining it....

>From what I see, we don't even have to send projid information in this
context. Do you want me to get rid of that (as mentioned above) ?

Does this comment sound correct ?
/*
 * Since no project related information is being changed, we do not
 * have to handle project quota information here.
 */

> 
> > > 
> > > 
> > > 			qino = xfs_sb_version_has_pquota(&mp->m_sb) ?
> > > 						mp->m_sb.sb_pquotino :
> > > 						mp->m_sb.sb_gquotino;
> > > 
> > > And the correct on-disk inode is read....
> > > 
> > The object of this patch is to replace all gquota with pquota stuff. I
> > am not using the pquotino or xfs_sb_version_has_pquota() until patch 3.
> > 
> > If I get the change forward, I have to merge patch 3 and part of this
> > patch into patch 1, which adds up lots of work.
> > 
> > The way the patches are split now, IMO, is easy to follow and works
> > independently.
> 
> That's fine. I review the patches one by one, so I make comments
> that are relevant to the current patch context. It may be that you
> changed it in a later patch and that often is fine - comments like
> this indicate that perhaps the commit message hasn't quite described
> the full context of the patch within the series correctly...
> 
> > > > +	if (pdqp) {
> > > > +		ASSERT(ip->i_pdquot == NULL);
> > > > +		ASSERT(XFS_IS_PQUOTA_ON(mp));
> > > > +		ASSERT(xfs_get_projid(ip) == be32_to_cpu(pdqp->q_core.d_id));
> > > > +
> > > > +		ip->i_pdquot = xfs_qm_dqhold(pdqp);
> > > > +		xfs_trans_mod_dquot(tp, pdqp, XFS_TRANS_DQ_ICOUNT, 1);
> > > > +	}
> > > >  }
> > > 
> > > Something this just triggered. All transaction reservations that
> > > reserve space for dquots need to be upped from 2 to 3 dquots.
> > 
> > Can you elaborate please.
> 
> A transaction ithat modifies space can now modify 3 dquots (u+g+p)
> instead of only 2 (u+(g or p)), and so the log space for any such 
> transaction goes up. It may be that you've already handled this, but
> if you're asking for an explanation then maybe not :/

IIUC, I am handling it by increasing the number of array elements in the
data structure xfs_dquot_acct. Let me know if it is incorrect.

> 
> Cheers,
> 
> Dave.


_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v8 4/5] xfs: Add proper versioning support to fs_quota_stat
  2013-06-10 23:27       ` Dave Chinner
@ 2013-06-11 23:13         ` Chandra Seetharaman
  0 siblings, 0 replies; 29+ messages in thread
From: Chandra Seetharaman @ 2013-06-11 23:13 UTC (permalink / raw)
  To: Dave Chinner; +Cc: xfs

On Tue, 2013-06-11 at 09:27 +1000, Dave Chinner wrote:
> On Fri, May 24, 2013 at 05:17:22PM -0500, Chandra Seetharaman wrote:
> > On Fri, 2013-05-17 at 15:10 +1000, Dave Chinner wrote:
> > > On Fri, May 10, 2013 at 04:21:28PM -0500, Chandra Seetharaman wrote:
> > > > Added appropriate pads and code for backward compatibility.
> > > > 
> > > > Copied over the old version as it is different from the newer padded
> > > > version.
> > > > 
> > > > New callers of the system call have to just set the version of the data
> > > > structure being passed, and kernel will fill as much data as requested.
> > > > 
> > > > Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
> > > 
> > > This needs to be cc'd to Steve Whitehouse so he's aware that we are
> > > changing the quota interface...
> 
> > > > +/*
> > > > + * Since Version 1 did not have padding at appropriate places,
> > > > + * a new data structure has been defined for the older version to
> > > > + * provide backward compatibility.
> > > > + * Future extentions of this data structure won't require new
> > > > + * data structure definitions as the current one can be extended
> > > > + * with the logic and padding in place now.
> > > > + */
> > > > +#define FS_QSTAT_V1_SIZE	(sizeof(struct fs_quota_stat_v1))
> > > > +#define FS_QSTAT_V2_SIZE	(offsetof(struct fs_quota_stat, qs_pquota) + \
> > > > +					sizeof(fs_qfilestat_t))
> > > 
> > > Just use sizeof(struct fs_quota_stat) as the size. Indeed, for
> > 
> > My thinking w.r.t not making it sizeof (fs_quota_stat) is ...future
> > changes doesn't have to touch the macro definitions of earlier versions,
> > they can define a new macro just by copying the last V?_SIZE macro and
> > changing the last field name.
> 
> If we need a future revision, we can deal with the structure
> differences and versions at that point in time. Second guessing
> unknown future requirements is not necessary. ;)

sure.
> 
> > > future enhancements, maybe we should add 64 bytes of empty space at
> > > the end of the structure....
> > 
> > Since this version is fully backward compatible, I didn't think a future
> > pad was needed. Do you want me to add ?
> 
> We only really need to change the structure version when we change
> input parameters, the size or the shape of the structure being
> passed in from userspace. If we add padding now, then we can expand
> output of the call without needing to bump the version of the
> structure. Old code simply won't know (or care) about the new output
> in the region of the structure it considers empty padding....

Ok. I will all 64 bytes of additional padding at the end.

> 
> Cheers,
> 
> Dave.


_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2013-06-11 23:13 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-10 21:21 [PATCH v8 0/5] xfs: Allow pquota and gquota to be used together Chandra Seetharaman
2013-05-10 21:21 ` [PATCH v8 1/5] xfs: Remove incore use of XFS_OQUOTA_ENFD and XFS_OQUOTA_CHKD Chandra Seetharaman
2013-05-13  3:15   ` Jeff Liu
2013-05-14 22:19     ` Chandra Seetharaman
2013-05-17  2:55   ` Dave Chinner
2013-05-24 21:45     ` Chandra Seetharaman
2013-05-10 21:21 ` [PATCH v8 2/5] xfs: Add pquota fields where gquota is used Chandra Seetharaman
2013-05-13  3:59   ` Jeff Liu
2013-05-17  3:01     ` Dave Chinner
2013-05-17  5:40       ` Jeff Liu
2013-05-17 21:15     ` Chandra Seetharaman
2013-05-17  4:23   ` Dave Chinner
2013-05-24 21:57     ` Chandra Seetharaman
2013-06-10 23:17       ` Dave Chinner
2013-06-11 23:08         ` Chandra Seetharaman
2013-05-10 21:21 ` [PATCH v8 3/5] xfs: Start using pquotaino from the superblock Chandra Seetharaman
2013-05-13  4:24   ` Jeff Liu
2013-05-17  4:46   ` Dave Chinner
2013-05-24 22:09     ` Chandra Seetharaman
2013-06-10 23:20       ` Dave Chinner
2013-05-10 21:21 ` [PATCH v8 4/5] xfs: Add proper versioning support to fs_quota_stat Chandra Seetharaman
2013-05-13  4:29   ` Jeff Liu
2013-05-17  5:10   ` Dave Chinner
2013-05-24 22:17     ` Chandra Seetharaman
2013-06-10 23:27       ` Dave Chinner
2013-06-11 23:13         ` Chandra Seetharaman
2013-05-10 21:21 ` [PATCH v8 5/5] xfs: Use new qs_pquota field in fs_quota_stat for Q_XGETQSTAT Chandra Seetharaman
2013-05-17  5:14   ` Dave Chinner
2013-05-24 22:17     ` Chandra Seetharaman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.