xfs
[Top] [All Lists]

[RFC v2 PATCH 4/5] xfs: Add pquotaino to on-disk super block

To: xfs@xxxxxxxxxxx
Subject: [RFC v2 PATCH 4/5] xfs: Add pquotaino to on-disk super block
From: Chandra Seetharaman <sekharan@xxxxxxxxxx>
Date: Wed, 26 Oct 2011 16:22:15 -0500
Cc: Chandra Seetharaman <sekharan@xxxxxxxxxx>
In-reply-to: <20111026212150.6513.38058.sendpatchset@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>
References: <20111026212150.6513.38058.sendpatchset@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>
Add a new field to the superblock to add support for seperate pquota
with a specific version.

No change made yet to gather both project and group quota with quotactl.

Signed-off-by: Chandra Seetharaman <sekharan@xxxxxxxxxx>
---
 fs/xfs/xfs_itable.c       |    3 +-
 fs/xfs/xfs_mount.c        |  101 ++++++++++++++++++++++++++++++++------------
 fs/xfs/xfs_qm.c           |   18 +++++---
 fs/xfs/xfs_qm_syscalls.c  |   30 ++++++++++---
 fs/xfs/xfs_quota.h        |    8 ----
 fs/xfs/xfs_sb.h           |   20 +++++++--
 fs/xfs/xfs_super.c        |   15 ++++---
 fs/xfs/xfs_trans_dquot.c  |    4 +-
 include/linux/dqblk_xfs.h |    1 +
 9 files changed, 139 insertions(+), 61 deletions(-)

diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 751e94f..0ea4361 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 8e6c128..1dc022c 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -108,6 +108,7 @@ static const struct {
     { offsetof(xfs_sb_t, sb_logsunit),  0 },
     { offsetof(xfs_sb_t, sb_features2),         0 },
     { offsetof(xfs_sb_t, sb_bad_features2), 0 },
+    { offsetof(xfs_sb_t, sb_pquotino), 0 },
     { sizeof(xfs_sb_t),                         0 }
 };
 
@@ -593,20 +594,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(mp, "Super block has XFS_OQUOTA bits along with "
-                       "XFS_PQUOTA and/or XFS_GQUOTA bits. Fixing it.\n");
-       }
-       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 +605,33 @@ xfs_sb_from_disk(
        to->sb_logsunit = be32_to_cpu(from->sb_logsunit);
        to->sb_features2 = be32_to_cpu(from->sb_features2);
        to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2);
+
+       if (xfs_sb_version_has_no_oquota(to)) {
+               if (to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) {
+                       xfs_notice(mp, "Super block has XFS_OQUOTA bits with "
+                       "version NO_OQUOTA. Fixing it.\n");
+                       to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
+               }
+               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(mp, "Super block has XFS_[G|P]UOTA bits in "
+                               "older version. Fixing it.\n");
+                       to->sb_qflags &= ~(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
+                                       XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD);
+               }
+               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 (to->sb_qflags & XFS_PQUOTA_ACCT)
+                       to->sb_pquotino = to->sb_gquotino;
+       }
 }
 
 /*
@@ -636,26 +650,37 @@ xfs_sb_to_disk(
        xfs_sb_field_t  f;
        int             first;
        int             size;
-       __be16          saved_qflags;
+       __be16          saved_qflags = 0;
 
        ASSERT(fields);
        if (!fields)
                return;
 
-       /*
-        * in-core version of qflags do not have XFS_OQUOTA.*, whereas the
-        * on-disk version does. So, save the in-core sb_qflags and restore
-        * it after we modify and copy it to the buffer to be copied to
-        * disk.
-        */
-       saved_qflags = from->sb_qflags;
 
-       if (from->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
-               from->sb_qflags |= XFS_OQUOTA_ENFD;
-       if (from->sb_qflags & (XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
-               from->sb_qflags |= XFS_OQUOTA_CHKD;
-       from->sb_qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
+       if (!xfs_sb_version_has_no_oquota(from) &&
+                   (from->sb_qflags & (XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
+                                       XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD))) {
+
+               if (from->sb_qflags & (XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD)) {
+                       from->sb_gquotino = from->sb_pquotino;
+                       from->sb_pquotino = 0;
+               }
+               /*
+                * in-core version of qflags do not have XFS_OQUOTA.*, whereas
+                * the on-disk version does. So, save the in-core sb_qflags
+                * and restore it after we modify and copy it to the buffer
+                * to be copied to disk.
+                */
+               saved_qflags = from->sb_qflags;
+
+               if (from->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
+                       from->sb_qflags |= XFS_OQUOTA_ENFD;
+               if (from->sb_qflags & (XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
+                       from->sb_qflags |= XFS_OQUOTA_CHKD;
+               from->sb_qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
                                        XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
+       }
+
        while (fields) {
                f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
                first = xfs_sb_info[f].offset;
@@ -686,7 +711,15 @@ xfs_sb_to_disk(
 
                fields &= ~(1LL << f);
        }
-       from->sb_qflags = saved_qflags;
+
+       /* Revert to the old saved values */
+       if (saved_qflags) {
+               from->sb_qflags = saved_qflags;
+               if (from->sb_qflags & (XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD)) {
+                       from->sb_pquotino = from->sb_gquotino;
+                       from->sb_gquotino = NULLFSINO;
+               }
+       }
 }
 
 /*
@@ -754,6 +787,12 @@ reread:
                goto reread;
        }
 
+       if (!xfs_sb_version_has_no_oquota(&mp->m_sb) &&
+                       XFS_IS_PQUOTA_ON(mp)) {
+               mp->m_sb.sb_pquotino = mp->m_sb.sb_gquotino;
+               mp->m_sb.sb_gquotino = NULLFSINO;
+       }
+
        /* Initialize per-cpu counters */
        xfs_icsb_reinit_counters(mp);
 
@@ -1672,6 +1711,12 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields)
        first = sizeof(xfs_sb_t);
        last = 0;
 
+       if (!xfs_sb_version_has_no_oquota(&mp->m_sb) &&
+                       XFS_IS_PQUOTA_ON(mp)) {
+               fields &= (__int64_t)~XFS_SB_PQUOTINO;
+               fields |= (__int64_t)XFS_SB_GQUOTINO;
+       }
+
        /* translate/copy */
 
        xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, fields);
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 2315e70..7b2411e 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -777,7 +777,8 @@ xfs_qm_dqattach_locked(
            !XFS_IS_QUOTA_ON(mp) ||
            !XFS_NOT_DQATTACHED(mp, ip) ||
            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 0;
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
@@ -897,6 +898,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;
@@ -1232,19 +1234,22 @@ xfs_qm_qino_alloc(
                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_GQUOTINO | XFS_SB_PQUOTINO | 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);
 
@@ -1551,7 +1556,8 @@ 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);
        }
@@ -1810,7 +1816,7 @@ xfs_qm_init_quotainos(
        } else {
                flags |= XFS_QMOPT_SBVERSION;
                sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-                           XFS_SB_GQUOTINO | XFS_SB_QFLAGS);
+                           XFS_SB_GQUOTINO | XFS_SB_PQUOTINO | XFS_SB_QFLAGS);
        }
 
        /*
@@ -1840,7 +1846,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) {
                        if (uip)
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index fe9afcb..7ce4034 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -209,8 +209,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);
@@ -300,8 +299,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;
 }
@@ -417,17 +418,18 @@ xfs_qm_scall_getqstat(
        struct fs_quota_stat    *out)
 {
        struct xfs_quotainfo    *q = mp->m_quotainfo;
-       struct xfs_inode        *uip, *gip;
-       boolean_t               tempuqip, tempgqip;
+       struct xfs_inode        *uip, *gip, *pip;
+       boolean_t               tempuqip, tempgqip, temppqip;
 
-       uip = gip = NULL;
-       tempuqip = tempgqip = B_FALSE;
+       uip = gip = pip = NULL;
+       tempuqip = tempgqip = temppqip = B_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 &
@@ -436,10 +438,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,
@@ -451,6 +456,11 @@ xfs_qm_scall_getqstat(
                                        0, 0, &gip) == 0)
                        tempgqip = B_TRUE;
        }
+       if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) {
+               if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
+                                       0, 0, &pip) == 0)
+                       temppqip = B_TRUE;
+       }
        if (uip) {
                out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
                out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
@@ -463,6 +473,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 46225bb..6968bfb 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -281,14 +281,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 5242512..55f63ed 100644
--- a/fs/xfs/xfs_sb.h
+++ b/fs/xfs/xfs_sb.h
@@ -81,11 +81,15 @@ struct xfs_mount;
 #define XFS_SB_VERSION2_ATTR2BIT       0x00000008      /* Inline attr rework */
 #define XFS_SB_VERSION2_PARENTBIT      0x00000010      /* parent pointers */
 #define XFS_SB_VERSION2_PROJID32BIT    0x00000080      /* 32 bit project id */
+#define XFS_SB_VERSION2_NO_OQUOTA      0x00000100      /* No OQUOTA and     *
+                                                        * separate project  *
+                                                        * quota field       */
 
 #define        XFS_SB_VERSION2_OKREALFBITS     \
        (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
         XFS_SB_VERSION2_ATTR2BIT       | \
-        XFS_SB_VERSION2_PROJID32BIT)
+        XFS_SB_VERSION2_PROJID32BIT    | \
+        XFS_SB_VERSION2_NO_OQUOTA)
 #define        XFS_SB_VERSION2_OKSASHFBITS     \
        (0)
 #define XFS_SB_VERSION2_OKREALBITS     \
@@ -140,7 +144,6 @@ typedef struct xfs_sb {
         */
        xfs_ino_t       sb_uquotino;    /* user quota inode */
        xfs_ino_t       sb_gquotino;    /* group quota inode */
-#define sb_pquotino    sb_gquotino
        __uint16_t      sb_qflags;      /* quota flags */
        __uint8_t       sb_flags;       /* misc. flags */
        __uint8_t       sb_shared_vn;   /* shared version number */
@@ -160,6 +163,7 @@ typedef struct xfs_sb {
         * it for anything else.
         */
        __uint32_t      sb_bad_features2;
+       xfs_ino_t       sb_pquotino;    /* project quota inode */
 
        /* must be padded to 64 bit alignment */
 } xfs_sb_t;
@@ -230,6 +234,7 @@ typedef struct xfs_dsb {
         * it for anything else.
         */
        __be32  sb_bad_features2;
+       __be64          sb_pquotino;    /* project quota inode */
 
        /* must be padded to 64 bit alignment */
 } xfs_dsb_t;
@@ -250,7 +255,7 @@ typedef enum {
        XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
        XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
        XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
-       XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2,
+       XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2, XFS_SBS_PQUOTINO,
        XFS_SBS_FIELDCOUNT
 } xfs_sb_field_t;
 
@@ -276,6 +281,7 @@ typedef enum {
 #define XFS_SB_FDBLOCKS                XFS_SB_MVAL(FDBLOCKS)
 #define XFS_SB_FEATURES2       XFS_SB_MVAL(FEATURES2)
 #define XFS_SB_BAD_FEATURES2   XFS_SB_MVAL(BAD_FEATURES2)
+#define XFS_SB_PQUOTINO                XFS_SB_MVAL(PQUOTINO)
 #define        XFS_SB_NUM_BITS         ((int)XFS_SBS_FIELDCOUNT)
 #define        XFS_SB_ALL_BITS         ((1LL << XFS_SB_NUM_BITS) - 1)
 #define        XFS_SB_MOD_BITS         \
@@ -283,7 +289,7 @@ typedef enum {
         XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
         XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
         XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \
-        XFS_SB_BAD_FEATURES2)
+        XFS_SB_BAD_FEATURES2 | XFS_SB_PQUOTINO)
 
 
 /*
@@ -504,6 +510,12 @@ static inline int xfs_sb_version_hasprojid32bit(xfs_sb_t 
*sbp)
                (sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT);
 }
 
+static inline int xfs_sb_version_has_no_oquota(xfs_sb_t *sbp)
+{
+       return xfs_sb_version_hasmorebits(sbp) &&
+               (sbp->sb_features2 & XFS_SB_VERSION2_NO_OQUOTA);
+}
+
 /*
  * end of superblock version macros
  */
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 14facbd..dc78d3e 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -408,12 +408,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;
@@ -1359,6 +1353,15 @@ xfs_fs_fill_super(
        if (error)
                goto out_destroy_counters;
 
+       if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
+           (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE)) &&
+           !xfs_sb_version_has_no_oquota(&mp->m_sb)) {
+               xfs_warn(mp, "Super block does not support "
+                                "project and group quota together");
+               error = EINVAL;
+               goto out_free_sb;
+       }
+
        error = xfs_finish_flags(mp);
        if (error)
                goto out_free_sb;
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index 8c4338f..83f98cd 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -165,7 +165,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)
@@ -858,6 +859,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/linux/dqblk_xfs.h b/include/linux/dqblk_xfs.h
index 8655280..f17e3bb 100644
--- a/include/linux/dqblk_xfs.h
+++ b/include/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

<Prev in Thread] Current Thread [Next in Thread>