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@xxxxxxxxxx> > --- > 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@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs