xfs: convert kuid_t to/from uid_t for internal structures
[platform/adaptation/renesas_rcar/renesas_kernel.git] / fs / xfs / xfs_qm.c
index b75c9bb..6218a0a 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_format.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
@@ -37,7 +38,6 @@
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_space.h"
-#include "xfs_utils.h"
 #include "xfs_qm.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
@@ -70,7 +70,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;
@@ -137,6 +137,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) {
@@ -145,8 +146,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) {
@@ -154,6 +154,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);
@@ -189,7 +195,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--;
 
@@ -208,6 +214,8 @@ xfs_qm_dqpurge(
 
        if (gdqp)
                xfs_qm_dqput(gdqp);
+       if (pdqp)
+               xfs_qm_dqput(pdqp);
        return 0;
 }
 
@@ -299,8 +307,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:
        /*
@@ -362,6 +372,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;
+               }
        }
 }
 
@@ -408,7 +422,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);
 
@@ -451,28 +468,42 @@ xfs_qm_dqattach_one(
 
 
 /*
- * Given a udquot and gdquot, attach a ptr to the group dquot in the
- * udquot as a hint for future lookups.
+ * Given a udquot and group/project type, attach the group/project
+ * dquot pointer to 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_hint(
+       struct xfs_inode        *ip,
+       int                     type)
 {
-       xfs_dquot_t     *tmp;
+       struct xfs_dquot **dqhintp;
+       struct xfs_dquot *dqp;
+       struct xfs_dquot *udq = ip->i_udquot;
+
+       ASSERT(type == XFS_DQ_GROUP || type == XFS_DQ_PROJ);
 
        xfs_dqlock(udq);
 
-       tmp = udq->q_gdquot;
-       if (tmp) {
-               if (tmp == gdq)
+       if (type == XFS_DQ_GROUP) {
+               dqp = ip->i_gdquot;
+               dqhintp = &udq->q_gdquot;
+       } else {
+               dqp = ip->i_pdquot;
+               dqhintp = &udq->q_pdquot;
+       }
+
+       if (*dqhintp) {
+               struct xfs_dquot *tmp;
+
+               if (*dqhintp == dqp)
                        goto done;
 
-               udq->q_gdquot = NULL;
+               tmp = *dqhintp;
+               *dqhintp = NULL;
                xfs_qm_dqrele(tmp);
        }
 
-       udq->q_gdquot = xfs_qm_dqhold(gdq);
+       *dqhintp = xfs_qm_dqhold(dqp);
 done:
        xfs_dqunlock(udq);
 }
@@ -489,8 +520,7 @@ xfs_qm_need_dqattach(
                return false;
        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)
+       if (xfs_is_quota_inode(&mp->m_sb, ip->i_ino))
                return false;
        return true;
 }
@@ -526,12 +556,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);
                /*
@@ -543,14 +569,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,7 +599,10 @@ xfs_qm_dqattach_locked(
                 * succeed in general.
                 */
                if (ip->i_udquot->q_gdquot != ip->i_gdquot)
-                       xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot);
+                       xfs_qm_dqattach_hint(ip, XFS_DQ_GROUP);
+
+               if (ip->i_udquot->q_pdquot != ip->i_pdquot)
+                       xfs_qm_dqattach_hint(ip, XFS_DQ_PROJ);
        }
 
  done:
@@ -567,8 +610,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
@@ -601,13 +646,12 @@ 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);
 
-       ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino);
-       ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino);
+       ASSERT(!xfs_is_quota_inode(&ip->i_mount->m_sb, ip->i_ino));
        if (ip->i_udquot) {
                xfs_qm_dqrele(ip->i_udquot);
                ip->i_udquot = NULL;
@@ -616,6 +660,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
@@ -660,6 +708,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);
@@ -761,6 +810,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;
@@ -781,21 +834,52 @@ xfs_qm_qino_alloc(
        int             error;
        int             committed;
 
+       *ip = NULL;
+       /*
+        * With superblock that doesn't have separate pquotino, we
+        * share an inode between gquota and pquota. If the on-disk
+        * superblock has GQUOTA and the filesystem is now mounted
+        * with PQUOTA, just use sb_gquotino for sb_pquotino and
+        * vice-versa.
+        */
+       if (!xfs_sb_version_has_pquotino(&mp->m_sb) &&
+                       (flags & (XFS_QMOPT_PQUOTA|XFS_QMOPT_GQUOTA))) {
+               xfs_ino_t ino = NULLFSINO;
+
+               if ((flags & XFS_QMOPT_PQUOTA) &&
+                            (mp->m_sb.sb_gquotino != NULLFSINO)) {
+                       ino = mp->m_sb.sb_gquotino;
+                       ASSERT(mp->m_sb.sb_pquotino == NULLFSINO);
+               } else if ((flags & XFS_QMOPT_GQUOTA) &&
+                            (mp->m_sb.sb_pquotino != NULLFSINO)) {
+                       ino = mp->m_sb.sb_pquotino;
+                       ASSERT(mp->m_sb.sb_gquotino == NULLFSINO);
+               }
+               if (ino != NULLFSINO) {
+                       error = xfs_iget(mp, NULL, ino, 0, 0, ip);
+                       if (error)
+                               return error;
+                       mp->m_sb.sb_gquotino = NULLFSINO;
+                       mp->m_sb.sb_pquotino = NULLFSINO;
+               }
+       }
+
        tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QINOCREATE);
-       if ((error = xfs_trans_reserve(tp,
-                                     XFS_QM_QINOCREATE_SPACE_RES(mp),
-                                     XFS_CREATE_LOG_RES(mp), 0,
-                                     XFS_TRANS_PERM_LOG_RES,
-                                     XFS_CREATE_LOG_COUNT))) {
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_create,
+                                 XFS_QM_QINOCREATE_SPACE_RES(mp), 0);
+       if (error) {
                xfs_trans_cancel(tp, 0);
                return error;
        }
 
-       error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, 1, ip, &committed);
-       if (error) {
-               xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
-                                XFS_TRANS_ABORT);
-               return error;
+       if (!*ip) {
+               error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, 1, ip,
+                                                               &committed);
+               if (error) {
+                       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
+                                        XFS_TRANS_ABORT);
+                       return error;
+               }
        }
 
        /*
@@ -807,21 +891,25 @@ xfs_qm_qino_alloc(
        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_GQUOTINO | XFS_SB_PQUOTINO | XFS_SB_QFLAGS)) ==
+                               (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
+                                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;
+               /* qflags will get updated fully _after_ quotacheck */
+               mp->m_sb.sb_qflags = mp->m_qflags & XFS_ALL_QUOTA_ACCT;
        }
        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);
 
@@ -1152,7 +1240,7 @@ 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 (xfs_is_quota_inode(&mp->m_sb, ino)) {
                *res = BULKSTAT_RV_NOTHING;
                return XFS_ERROR(EINVAL);
        }
@@ -1262,19 +1350,21 @@ int
 xfs_qm_quotacheck(
        xfs_mount_t     *mp)
 {
-       int             done, count, error, error2;
-       xfs_ino_t       lastino;
-       size_t          structsz;
-       xfs_inode_t     *uip, *gip;
-       uint            flags;
-       LIST_HEAD       (buffer_list);
+       int                     done, count, error, error2;
+       xfs_ino_t               lastino;
+       size_t                  structsz;
+       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.");
@@ -1284,7 +1374,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);
@@ -1293,14 +1382,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_OQUOTA_CHKD;
+               flags |= XFS_PQUOTA_CHKD;
        }
 
        do {
@@ -1395,15 +1490,14 @@ STATIC int
 xfs_qm_init_quotainos(
        xfs_mount_t     *mp)
 {
-       xfs_inode_t     *uip, *gip;
-       int             error;
-       __int64_t       sbflags;
-       uint            flags;
+       struct xfs_inode        *uip = NULL;
+       struct xfs_inode        *gip = NULL;
+       struct xfs_inode        *pip = NULL;
+       int                     error;
+       __int64_t               sbflags = 0;
+       uint                    flags = 0;
 
        ASSERT(mp->m_quotainfo);
-       uip = gip = NULL;
-       sbflags = 0;
-       flags = 0;
 
        /*
         * Get the uquota and gquota inodes
@@ -1412,57 +1506,80 @@ 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;
+               }
+               if (XFS_IS_PQUOTA_ON(mp) &&
+                   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);
+                           XFS_SB_GQUOTINO | XFS_SB_PQUOTINO |
+                           XFS_SB_QFLAGS);
        }
 
        /*
-        * 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)))
-                       return XFS_ERROR(error);
+                                             flags | XFS_QMOPT_UQUOTA);
+               if (error)
+                       goto error_rele;
 
                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);
+                                         sbflags | XFS_SB_GQUOTINO,
+                                         flags | XFS_QMOPT_GQUOTA);
+               if (error)
+                       goto error_rele;
 
-                       return XFS_ERROR(error);
-               }
+               flags &= ~XFS_QMOPT_SBVERSION;
+       }
+       if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
+               error = xfs_qm_qino_alloc(mp, &pip,
+                                         sbflags | XFS_SB_PQUOTINO,
+                                         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
@@ -1473,7 +1590,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--;
@@ -1621,8 +1738,7 @@ xfs_qm_write_sb_changes(
        int             error;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
-       error = xfs_trans_reserve(tp, 0, XFS_QM_SBCHANGE_LOG_RES(mp),
-                                 0, 0, XFS_DEFAULT_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_qm_sbchange, 0, 0);
        if (error) {
                xfs_trans_cancel(tp, 0);
                return error;
@@ -1651,15 +1767,18 @@ xfs_qm_write_sb_changes(
 int
 xfs_qm_vop_dqalloc(
        struct xfs_inode        *ip,
-       uid_t                   uid,
-       gid_t                   gid,
+       xfs_dqid_t              uid,
+       xfs_dqid_t              gid,
        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;
 
@@ -1684,7 +1803,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) {
                        /*
@@ -1697,11 +1815,12 @@ 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, uid,
                                                 XFS_DQ_USER,
                                                 XFS_QMOPT_DQALLOC |
                                                 XFS_QMOPT_DOWARN,
-                                                &uq))) {
+                                                &uq);
+                       if (error) {
                                ASSERT(error != ENOENT);
                                return error;
                        }
@@ -1723,15 +1842,14 @@ 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, gid,
                                                 XFS_DQ_GROUP,
                                                 XFS_QMOPT_DQALLOC |
                                                 XFS_QMOPT_DOWARN,
-                                                &gq))) {
-                               if (uq)
-                                       xfs_qm_dqrele(uq);
+                                                &gq);
+                       if (error) {
                                ASSERT(error != ENOENT);
-                               return error;
+                               goto error_rele;
                        }
                        xfs_dqunlock(gq);
                        lockflags = XFS_ILOCK_SHARED;
@@ -1740,25 +1858,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);
+                                                &pq);
+                       if (error) {
                                ASSERT(error != ENOENT);
-                               return (error);
+                               goto error_rele;
                        }
-                       xfs_dqunlock(gq);
+                       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)
@@ -1773,7 +1891,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 (gq)
+               xfs_qm_dqrele(gq);
+       if (uq)
+               xfs_qm_dqrele(uq);
+       return error;
 }
 
 /*
@@ -1821,29 +1950,34 @@ 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)
+       struct xfs_trans        *tp,
+       struct xfs_inode        *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;
-       int             error;
+       struct xfs_mount        *mp = ip->i_mount;
+       uint                    delblks, blkflags, prjflags = 0;
+       struct xfs_dquot        *udq_unres = NULL;
+       struct xfs_dquot        *gdq_unres = NULL;
+       struct xfs_dquot        *pdq_unres = NULL;
+       struct xfs_dquot        *udq_delblks = NULL;
+       struct xfs_dquot        *gdq_delblks = NULL;
+       struct xfs_dquot        *pdq_delblks = NULL;
+       int                     error;
 
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
        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;
 
        if (XFS_IS_UQUOTA_ON(mp) && udqp &&
-           ip->i_d.di_uid != (uid_t)be32_to_cpu(udqp->q_core.d_id)) {
-               delblksudq = udqp;
+           ip->i_d.di_uid != be32_to_cpu(udqp->q_core.d_id)) {
+               udq_delblks = udqp;
                /*
                 * If there are delayed allocation blocks, then we have to
                 * unreserve those from the old dquot, and add them to the
@@ -1851,29 +1985,34 @@ xfs_qm_vop_chown_reserve(
                 */
                if (delblks) {
                        ASSERT(ip->i_udquot);
-                       unresudq = ip->i_udquot;
+                       udq_unres = 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)) {
+               gdq_delblks = gdqp;
+               if (delblks) {
+                       ASSERT(ip->i_gdquot);
+                       gdq_unres = 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;
+               pdq_delblks = pdqp;
+               if (delblks) {
+                       ASSERT(ip->i_pdquot);
+                       pdq_unres = 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)))
-               return (error);
+       error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
+                               udq_delblks, gdq_delblks, pdq_delblks,
+                               ip->i_d.di_nblocks, 1,
+                               flags | blkflags | prjflags);
+       if (error)
+               return error;
 
        /*
         * Do the delayed blks reservations/unreservations now. Since, these
@@ -1885,15 +2024,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)))
-                       return (error);
+               ASSERT(udq_delblks || gdq_delblks || pdq_delblks);
+               ASSERT(udq_unres || gdq_unres || pdq_unres);
+               error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
+                           udq_delblks, gdq_delblks, pdq_delblks,
+                           (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);
+                               udq_unres, gdq_unres, pdq_unres,
+                               -((xfs_qcnt_t)delblks), 0, blkflags);
        }
 
        return (0);
@@ -1932,7 +2073,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;
 
@@ -1952,13 +2094,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);
+       }
 }