Commit 92f8ff73 authored by Chandra Seetharaman's avatar Chandra Seetharaman Committed by Ben Myers

xfs: Add pquota fields where gquota is used.

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.

Not using the pquotino field from superblock yet.
Signed-off-by: default avatarChandra Seetharaman <sekharan@us.ibm.com>
Reviewed-by: default avatarBen Myers <bpm@sgi.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent 42c49d7f
...@@ -936,6 +936,7 @@ xfs_qm_dqput_final( ...@@ -936,6 +936,7 @@ xfs_qm_dqput_final(
{ {
struct xfs_quotainfo *qi = dqp->q_mount->m_quotainfo; struct xfs_quotainfo *qi = dqp->q_mount->m_quotainfo;
struct xfs_dquot *gdqp; struct xfs_dquot *gdqp;
struct xfs_dquot *pdqp;
trace_xfs_dqput_free(dqp); trace_xfs_dqput_free(dqp);
...@@ -949,21 +950,29 @@ xfs_qm_dqput_final( ...@@ -949,21 +950,29 @@ xfs_qm_dqput_final(
/* /*
* If we just added a udquot to the freelist, then we want to release * 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/pdquot reference that it (probably) has. Otherwise it'll
* the gdquot from getting reclaimed. * keep the gdquot/pdquot from getting reclaimed.
*/ */
gdqp = dqp->q_gdquot; gdqp = dqp->q_gdquot;
if (gdqp) { if (gdqp) {
xfs_dqlock(gdqp); xfs_dqlock(gdqp);
dqp->q_gdquot = NULL; dqp->q_gdquot = NULL;
} }
pdqp = dqp->q_pdquot;
if (pdqp) {
xfs_dqlock(pdqp);
dqp->q_pdquot = NULL;
}
xfs_dqunlock(dqp); 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) if (gdqp)
xfs_qm_dqput(gdqp); xfs_qm_dqput(gdqp);
if (pdqp)
xfs_qm_dqput(pdqp);
} }
/* /*
......
...@@ -53,6 +53,7 @@ typedef struct xfs_dquot { ...@@ -53,6 +53,7 @@ typedef struct xfs_dquot {
xfs_fileoff_t q_fileoffset; /* offset in quotas file */ 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_disk_dquot_t q_core; /* actual usage & quotas */
xfs_dq_logitem_t q_logitem; /* dquot log item */ xfs_dq_logitem_t q_logitem; /* dquot log item */
xfs_qcnt_t q_res_bcount; /* total regular nblks used+reserved */ xfs_qcnt_t q_res_bcount; /* total regular nblks used+reserved */
...@@ -118,8 +119,9 @@ static inline int xfs_this_quota_on(struct xfs_mount *mp, int type) ...@@ -118,8 +119,9 @@ static inline int xfs_this_quota_on(struct xfs_mount *mp, int type)
case XFS_DQ_USER: case XFS_DQ_USER:
return XFS_IS_UQUOTA_ON(mp); return XFS_IS_UQUOTA_ON(mp);
case XFS_DQ_GROUP: case XFS_DQ_GROUP:
return XFS_IS_GQUOTA_ON(mp);
case XFS_DQ_PROJ: case XFS_DQ_PROJ:
return XFS_IS_OQUOTA_ON(mp); return XFS_IS_PQUOTA_ON(mp);
default: default:
return 0; return 0;
} }
...@@ -131,8 +133,9 @@ static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type) ...@@ -131,8 +133,9 @@ static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
case XFS_DQ_USER: case XFS_DQ_USER:
return ip->i_udquot; return ip->i_udquot;
case XFS_DQ_GROUP: case XFS_DQ_GROUP:
case XFS_DQ_PROJ:
return ip->i_gdquot; return ip->i_gdquot;
case XFS_DQ_PROJ:
return ip->i_pdquot;
default: default:
return NULL; return NULL;
} }
......
...@@ -337,6 +337,7 @@ xfs_iget_cache_miss( ...@@ -337,6 +337,7 @@ xfs_iget_cache_miss(
iflags |= XFS_IDONTCACHE; iflags |= XFS_IDONTCACHE;
ip->i_udquot = NULL; ip->i_udquot = NULL;
ip->i_gdquot = NULL; ip->i_gdquot = NULL;
ip->i_pdquot = NULL;
xfs_iflags_set(ip, iflags); xfs_iflags_set(ip, iflags);
/* insert the new inode */ /* insert the new inode */
......
...@@ -250,6 +250,7 @@ typedef struct xfs_inode { ...@@ -250,6 +250,7 @@ typedef struct xfs_inode {
struct xfs_mount *i_mount; /* fs mount struct ptr */ struct xfs_mount *i_mount; /* fs mount struct ptr */
struct xfs_dquot *i_udquot; /* user dquot */ struct xfs_dquot *i_udquot; /* user dquot */
struct xfs_dquot *i_gdquot; /* group dquot */ struct xfs_dquot *i_gdquot; /* group dquot */
struct xfs_dquot *i_pdquot; /* project dquot */
/* Inode location stuff */ /* Inode location stuff */
xfs_ino_t i_ino; /* inode number (agno/agino)*/ xfs_ino_t i_ino; /* inode number (agno/agino)*/
......
...@@ -928,7 +928,7 @@ xfs_ioctl_setattr( ...@@ -928,7 +928,7 @@ xfs_ioctl_setattr(
struct xfs_trans *tp; struct xfs_trans *tp;
unsigned int lock_flags = 0; unsigned int lock_flags = 0;
struct xfs_dquot *udqp = NULL; struct xfs_dquot *udqp = NULL;
struct xfs_dquot *gdqp = NULL; struct xfs_dquot *pdqp = NULL;
struct xfs_dquot *olddquot = NULL; struct xfs_dquot *olddquot = NULL;
int code; int code;
...@@ -957,7 +957,7 @@ xfs_ioctl_setattr( ...@@ -957,7 +957,7 @@ xfs_ioctl_setattr(
if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) { if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
code = xfs_qm_vop_dqalloc(ip, ip->i_d.di_uid, code = xfs_qm_vop_dqalloc(ip, ip->i_d.di_uid,
ip->i_d.di_gid, fa->fsx_projid, ip->i_d.di_gid, fa->fsx_projid,
XFS_QMOPT_PQUOTA, &udqp, &gdqp); XFS_QMOPT_PQUOTA, &udqp, NULL, &pdqp);
if (code) if (code)
return code; return code;
} }
...@@ -994,8 +994,8 @@ xfs_ioctl_setattr( ...@@ -994,8 +994,8 @@ xfs_ioctl_setattr(
XFS_IS_PQUOTA_ON(mp) && XFS_IS_PQUOTA_ON(mp) &&
xfs_get_projid(ip) != fa->fsx_projid) { xfs_get_projid(ip) != fa->fsx_projid) {
ASSERT(tp); ASSERT(tp);
code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp, code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL,
capable(CAP_FOWNER) ? pdqp, capable(CAP_FOWNER) ?
XFS_QMOPT_FORCE_RES : 0); XFS_QMOPT_FORCE_RES : 0);
if (code) /* out of quota */ if (code) /* out of quota */
goto error_return; goto error_return;
...@@ -1113,7 +1113,7 @@ xfs_ioctl_setattr( ...@@ -1113,7 +1113,7 @@ xfs_ioctl_setattr(
if (xfs_get_projid(ip) != fa->fsx_projid) { if (xfs_get_projid(ip) != fa->fsx_projid) {
if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) { if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
olddquot = xfs_qm_vop_chown(tp, ip, olddquot = xfs_qm_vop_chown(tp, ip,
&ip->i_gdquot, gdqp); &ip->i_pdquot, pdqp);
} }
xfs_set_projid(ip, fa->fsx_projid); xfs_set_projid(ip, fa->fsx_projid);
...@@ -1160,13 +1160,13 @@ xfs_ioctl_setattr( ...@@ -1160,13 +1160,13 @@ xfs_ioctl_setattr(
*/ */
xfs_qm_dqrele(olddquot); xfs_qm_dqrele(olddquot);
xfs_qm_dqrele(udqp); xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp); xfs_qm_dqrele(pdqp);
return code; return code;
error_return: error_return:
xfs_qm_dqrele(udqp); xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp); xfs_qm_dqrele(pdqp);
xfs_trans_cancel(tp, 0); xfs_trans_cancel(tp, 0);
if (lock_flags) if (lock_flags)
xfs_iunlock(ip, lock_flags); xfs_iunlock(ip, lock_flags);
......
...@@ -539,7 +539,7 @@ xfs_setattr_nonsize( ...@@ -539,7 +539,7 @@ xfs_setattr_nonsize(
ASSERT(udqp == NULL); ASSERT(udqp == NULL);
ASSERT(gdqp == NULL); ASSERT(gdqp == NULL);
error = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip), error = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip),
qflags, &udqp, &gdqp); qflags, &udqp, &gdqp, NULL);
if (error) if (error)
return error; return error;
} }
...@@ -575,7 +575,7 @@ xfs_setattr_nonsize( ...@@ -575,7 +575,7 @@ xfs_setattr_nonsize(
(XFS_IS_GQUOTA_ON(mp) && igid != gid))) { (XFS_IS_GQUOTA_ON(mp) && igid != gid))) {
ASSERT(tp); ASSERT(tp);
error = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp, error = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
capable(CAP_FOWNER) ? NULL, capable(CAP_FOWNER) ?
XFS_QMOPT_FORCE_RES : 0); XFS_QMOPT_FORCE_RES : 0);
if (error) /* out of quota */ if (error) /* out of quota */
goto out_trans_cancel; goto out_trans_cancel;
......
...@@ -137,6 +137,7 @@ xfs_qm_dqpurge( ...@@ -137,6 +137,7 @@ xfs_qm_dqpurge(
struct xfs_mount *mp = dqp->q_mount; struct xfs_mount *mp = dqp->q_mount;
struct xfs_quotainfo *qi = mp->m_quotainfo; struct xfs_quotainfo *qi = mp->m_quotainfo;
struct xfs_dquot *gdqp = NULL; struct xfs_dquot *gdqp = NULL;
struct xfs_dquot *pdqp = NULL;
xfs_dqlock(dqp); xfs_dqlock(dqp);
if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) { if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) {
...@@ -145,8 +146,7 @@ xfs_qm_dqpurge( ...@@ -145,8 +146,7 @@ xfs_qm_dqpurge(
} }
/* /*
* If this quota has a group hint attached, prepare for releasing it * If this quota has a hint attached, prepare for releasing it now.
* now.
*/ */
gdqp = dqp->q_gdquot; gdqp = dqp->q_gdquot;
if (gdqp) { if (gdqp) {
...@@ -154,6 +154,12 @@ xfs_qm_dqpurge( ...@@ -154,6 +154,12 @@ xfs_qm_dqpurge(
dqp->q_gdquot = NULL; dqp->q_gdquot = NULL;
} }
pdqp = dqp->q_pdquot;
if (pdqp) {
xfs_dqlock(pdqp);
dqp->q_pdquot = NULL;
}
dqp->dq_flags |= XFS_DQ_FREEING; dqp->dq_flags |= XFS_DQ_FREEING;
xfs_dqflock(dqp); xfs_dqflock(dqp);
...@@ -208,6 +214,8 @@ xfs_qm_dqpurge( ...@@ -208,6 +214,8 @@ xfs_qm_dqpurge(
if (gdqp) if (gdqp)
xfs_qm_dqput(gdqp); xfs_qm_dqput(gdqp);
if (pdqp)
xfs_qm_dqput(pdqp);
return 0; return 0;
} }
...@@ -364,6 +372,10 @@ xfs_qm_unmount_quotas( ...@@ -364,6 +372,10 @@ xfs_qm_unmount_quotas(
IRELE(mp->m_quotainfo->qi_gquotaip); IRELE(mp->m_quotainfo->qi_gquotaip);
mp->m_quotainfo->qi_gquotaip = NULL; mp->m_quotainfo->qi_gquotaip = NULL;
} }
if (mp->m_quotainfo->qi_pquotaip) {
IRELE(mp->m_quotainfo->qi_pquotaip);
mp->m_quotainfo->qi_pquotaip = NULL;
}
} }
} }
...@@ -410,7 +422,10 @@ xfs_qm_dqattach_one( ...@@ -410,7 +422,10 @@ xfs_qm_dqattach_one(
* be reclaimed as long as we have a ref from inode and we * be reclaimed as long as we have a ref from inode and we
* hold the ilock. * hold the ilock.
*/ */
if (type == XFS_DQ_GROUP)
dqp = udqhint->q_gdquot; dqp = udqhint->q_gdquot;
else
dqp = udqhint->q_pdquot;
if (dqp && be32_to_cpu(dqp->q_core.d_id) == id) { if (dqp && be32_to_cpu(dqp->q_core.d_id) == id) {
ASSERT(*IO_idqpp == NULL); ASSERT(*IO_idqpp == NULL);
...@@ -453,28 +468,42 @@ xfs_qm_dqattach_one( ...@@ -453,28 +468,42 @@ xfs_qm_dqattach_one(
/* /*
* Given a udquot and gdquot, attach a ptr to the group dquot in the * Given a udquot and group/project type, attach the group/project
* udquot as a hint for future lookups. * dquot pointer to the udquot as a hint for future lookups.
*/ */
STATIC void STATIC void
xfs_qm_dqattach_grouphint( xfs_qm_dqattach_hint(
xfs_dquot_t *udq, struct xfs_inode *ip,
xfs_dquot_t *gdq) 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); xfs_dqlock(udq);
tmp = udq->q_gdquot; if (type == XFS_DQ_GROUP) {
if (tmp) { dqp = ip->i_gdquot;
if (tmp == gdq) dqhintp = &udq->q_gdquot;
} else {
dqp = ip->i_pdquot;
dqhintp = &udq->q_pdquot;
}
if (*dqhintp) {
struct xfs_dquot *tmp;
if (*dqhintp == dqp)
goto done; goto done;
udq->q_gdquot = NULL; tmp = *dqhintp;
*dqhintp = NULL;
xfs_qm_dqrele(tmp); xfs_qm_dqrele(tmp);
} }
udq->q_gdquot = xfs_qm_dqhold(gdq); *dqhintp = xfs_qm_dqhold(dqp);
done: done:
xfs_dqunlock(udq); xfs_dqunlock(udq);
} }
...@@ -527,12 +556,8 @@ xfs_qm_dqattach_locked( ...@@ -527,12 +556,8 @@ xfs_qm_dqattach_locked(
} }
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
if (XFS_IS_OQUOTA_ON(mp)) { if (XFS_IS_GQUOTA_ON(mp)) {
error = XFS_IS_GQUOTA_ON(mp) ? error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
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,
flags & XFS_QMOPT_DQALLOC, flags & XFS_QMOPT_DQALLOC,
ip->i_udquot, &ip->i_gdquot); ip->i_udquot, &ip->i_gdquot);
/* /*
...@@ -544,14 +569,28 @@ xfs_qm_dqattach_locked( ...@@ -544,14 +569,28 @@ xfs_qm_dqattach_locked(
nquotas++; 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. * 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(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(ip->i_udquot); ASSERT(ip->i_gdquot || !XFS_IS_GQUOTA_ON(mp));
ASSERT(ip->i_gdquot); ASSERT(ip->i_pdquot || !XFS_IS_PQUOTA_ON(mp));
/* /*
* We do not have i_udquot locked at this point, but this check * We do not have i_udquot locked at this point, but this check
...@@ -560,7 +599,10 @@ xfs_qm_dqattach_locked( ...@@ -560,7 +599,10 @@ xfs_qm_dqattach_locked(
* succeed in general. * succeed in general.
*/ */
if (ip->i_udquot->q_gdquot != ip->i_gdquot) 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: done:
...@@ -568,8 +610,10 @@ xfs_qm_dqattach_locked( ...@@ -568,8 +610,10 @@ xfs_qm_dqattach_locked(
if (!error) { if (!error) {
if (XFS_IS_UQUOTA_ON(mp)) if (XFS_IS_UQUOTA_ON(mp))
ASSERT(ip->i_udquot); ASSERT(ip->i_udquot);
if (XFS_IS_OQUOTA_ON(mp)) if (XFS_IS_GQUOTA_ON(mp))
ASSERT(ip->i_gdquot); ASSERT(ip->i_gdquot);
if (XFS_IS_PQUOTA_ON(mp))
ASSERT(ip->i_pdquot);
} }
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
#endif #endif
...@@ -602,7 +646,7 @@ void ...@@ -602,7 +646,7 @@ void
xfs_qm_dqdetach( xfs_qm_dqdetach(
xfs_inode_t *ip) xfs_inode_t *ip)
{ {
if (!(ip->i_udquot || ip->i_gdquot)) if (!(ip->i_udquot || ip->i_gdquot || ip->i_pdquot))
return; return;
trace_xfs_dquot_dqdetach(ip); trace_xfs_dquot_dqdetach(ip);
...@@ -616,6 +660,10 @@ xfs_qm_dqdetach( ...@@ -616,6 +660,10 @@ xfs_qm_dqdetach(
xfs_qm_dqrele(ip->i_gdquot); xfs_qm_dqrele(ip->i_gdquot);
ip->i_gdquot = NULL; ip->i_gdquot = NULL;
} }
if (ip->i_pdquot) {
xfs_qm_dqrele(ip->i_pdquot);
ip->i_pdquot = NULL;
}
} }
int int
...@@ -660,6 +708,7 @@ xfs_qm_init_quotainfo( ...@@ -660,6 +708,7 @@ xfs_qm_init_quotainfo(
INIT_RADIX_TREE(&qinf->qi_uquota_tree, GFP_NOFS); INIT_RADIX_TREE(&qinf->qi_uquota_tree, GFP_NOFS);
INIT_RADIX_TREE(&qinf->qi_gquota_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); mutex_init(&qinf->qi_tree_lock);
INIT_LIST_HEAD(&qinf->qi_lru_list); INIT_LIST_HEAD(&qinf->qi_lru_list);
...@@ -761,6 +810,10 @@ xfs_qm_destroy_quotainfo( ...@@ -761,6 +810,10 @@ xfs_qm_destroy_quotainfo(
IRELE(qi->qi_gquotaip); IRELE(qi->qi_gquotaip);
qi->qi_gquotaip = NULL; qi->qi_gquotaip = NULL;
} }
if (qi->qi_pquotaip) {
IRELE(qi->qi_pquotaip);
qi->qi_pquotaip = NULL;
}
mutex_destroy(&qi->qi_quotaofflock); mutex_destroy(&qi->qi_quotaofflock);
kmem_free(qi); kmem_free(qi);
mp->m_quotainfo = NULL; mp->m_quotainfo = NULL;
...@@ -1269,13 +1322,14 @@ xfs_qm_quotacheck( ...@@ -1269,13 +1322,14 @@ xfs_qm_quotacheck(
LIST_HEAD (buffer_list); LIST_HEAD (buffer_list);
struct xfs_inode *uip = mp->m_quotainfo->qi_uquotaip; struct xfs_inode *uip = mp->m_quotainfo->qi_uquotaip;
struct xfs_inode *gip = mp->m_quotainfo->qi_gquotaip; struct xfs_inode *gip = mp->m_quotainfo->qi_gquotaip;
struct xfs_inode *pip = mp->m_quotainfo->qi_pquotaip;
count = INT_MAX; count = INT_MAX;
structsz = 1; structsz = 1;
lastino = 0; lastino = 0;
flags = 0; flags = 0;
ASSERT(uip || gip); ASSERT(uip || gip || pip);
ASSERT(XFS_IS_QUOTA_RUNNING(mp)); ASSERT(XFS_IS_QUOTA_RUNNING(mp));
xfs_notice(mp, "Quotacheck needed: Please wait."); xfs_notice(mp, "Quotacheck needed: Please wait.");
...@@ -1294,13 +1348,19 @@ xfs_qm_quotacheck( ...@@ -1294,13 +1348,19 @@ xfs_qm_quotacheck(
} }
if (gip) { if (gip) {
error = xfs_qm_dqiterate(mp, gip, XFS_IS_GQUOTA_ON(mp) ? error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA,
XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA,
&buffer_list); &buffer_list);
if (error) if (error)
goto error_return; goto error_return;
flags |= XFS_IS_GQUOTA_ON(mp) ? flags |= XFS_GQUOTA_CHKD;
XFS_GQUOTA_CHKD : XFS_PQUOTA_CHKD; }
if (pip) {
error = xfs_qm_dqiterate(mp, pip, XFS_QMOPT_PQUOTA,
&buffer_list);
if (error)
goto error_return;
flags |= XFS_PQUOTA_CHKD;
} }
do { do {
...@@ -1397,6 +1457,7 @@ xfs_qm_init_quotainos( ...@@ -1397,6 +1457,7 @@ xfs_qm_init_quotainos(
{ {
struct xfs_inode *uip = NULL; struct xfs_inode *uip = NULL;
struct xfs_inode *gip = NULL; struct xfs_inode *gip = NULL;
struct xfs_inode *pip = NULL;
int error; int error;
__int64_t sbflags = 0; __int64_t sbflags = 0;
uint flags = 0; uint flags = 0;
...@@ -1415,7 +1476,7 @@ xfs_qm_init_quotainos( ...@@ -1415,7 +1476,7 @@ xfs_qm_init_quotainos(
if (error) if (error)
return XFS_ERROR(error); return XFS_ERROR(error);
} }
if (XFS_IS_OQUOTA_ON(mp) && if (XFS_IS_GQUOTA_ON(mp) &&
mp->m_sb.sb_gquotino != NULLFSINO) { mp->m_sb.sb_gquotino != NULLFSINO) {
ASSERT(mp->m_sb.sb_gquotino > 0); ASSERT(mp->m_sb.sb_gquotino > 0);
error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
...@@ -1423,6 +1484,15 @@ xfs_qm_init_quotainos( ...@@ -1423,6 +1484,15 @@ xfs_qm_init_quotainos(
if (error) if (error)
goto error_rele; goto error_rele;
} }
/* XXX: Use 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 { } else {
flags |= XFS_QMOPT_SBVERSION; flags |= XFS_QMOPT_SBVERSION;
sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
...@@ -1430,7 +1500,7 @@ xfs_qm_init_quotainos( ...@@ -1430,7 +1500,7 @@ 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 * made above will get added to a transaction and logged in one of
* the qino_alloc calls below. If the device is readonly, * the qino_alloc calls below. If the device is readonly,
* temporarily switch to read-write to do this. * temporarily switch to read-write to do this.
...@@ -1444,17 +1514,27 @@ xfs_qm_init_quotainos( ...@@ -1444,17 +1514,27 @@ xfs_qm_init_quotainos(
flags &= ~XFS_QMOPT_SBVERSION; flags &= ~XFS_QMOPT_SBVERSION;
} }
if (XFS_IS_OQUOTA_ON(mp) && gip == NULL) { if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
flags |= (XFS_IS_GQUOTA_ON(mp) ?
XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA);
error = xfs_qm_qino_alloc(mp, &gip, error = xfs_qm_qino_alloc(mp, &gip,
sbflags | XFS_SB_GQUOTINO, flags); sbflags | XFS_SB_GQUOTINO,
flags | XFS_QMOPT_GQUOTA);
if (error)
goto error_rele;
flags &= ~XFS_QMOPT_SBVERSION;
}
if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
/* XXX: Use XFS_SB_GQUOTINO for now */
error = xfs_qm_qino_alloc(mp, &pip,
sbflags | XFS_SB_GQUOTINO,
flags | XFS_QMOPT_PQUOTA);
if (error) if (error)
goto error_rele; goto error_rele;
} }
mp->m_quotainfo->qi_uquotaip = uip; mp->m_quotainfo->qi_uquotaip = uip;
mp->m_quotainfo->qi_gquotaip = gip; mp->m_quotainfo->qi_gquotaip = gip;
mp->m_quotainfo->qi_pquotaip = pip;
return 0; return 0;
...@@ -1463,6 +1543,8 @@ xfs_qm_init_quotainos( ...@@ -1463,6 +1543,8 @@ xfs_qm_init_quotainos(
IRELE(uip); IRELE(uip);
if (gip) if (gip)
IRELE(gip); IRELE(gip);
if (pip)
IRELE(pip);
return XFS_ERROR(error); return XFS_ERROR(error);
} }
...@@ -1657,11 +1739,13 @@ xfs_qm_vop_dqalloc( ...@@ -1657,11 +1739,13 @@ xfs_qm_vop_dqalloc(
prid_t prid, prid_t prid,
uint flags, uint flags,
struct xfs_dquot **O_udqpp, 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_mount *mp = ip->i_mount;
struct xfs_dquot *uq = NULL; struct xfs_dquot *uq = NULL;
struct xfs_dquot *gq = NULL; struct xfs_dquot *gq = NULL;
struct xfs_dquot *pq = NULL;
int error; int error;
uint lockflags; uint lockflags;
...@@ -1741,24 +1825,25 @@ xfs_qm_vop_dqalloc( ...@@ -1741,24 +1825,25 @@ xfs_qm_vop_dqalloc(
ASSERT(ip->i_gdquot); ASSERT(ip->i_gdquot);
gq = xfs_qm_dqhold(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) { if (xfs_get_projid(ip) != prid) {
xfs_iunlock(ip, lockflags); xfs_iunlock(ip, lockflags);
error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid, error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid,
XFS_DQ_PROJ, XFS_DQ_PROJ,
XFS_QMOPT_DQALLOC | XFS_QMOPT_DQALLOC |
XFS_QMOPT_DOWARN, XFS_QMOPT_DOWARN,
&gq); &pq);
if (error) { if (error) {
ASSERT(error != ENOENT); ASSERT(error != ENOENT);
goto error_rele; goto error_rele;
} }
xfs_dqunlock(gq); xfs_dqunlock(pq);
lockflags = XFS_ILOCK_SHARED; lockflags = XFS_ILOCK_SHARED;
xfs_ilock(ip, lockflags); xfs_ilock(ip, lockflags);
} else { } else {
ASSERT(ip->i_gdquot); ASSERT(ip->i_pdquot);
gq = xfs_qm_dqhold(ip->i_gdquot); pq = xfs_qm_dqhold(ip->i_pdquot);
} }
} }
if (uq) if (uq)
...@@ -1773,9 +1858,15 @@ xfs_qm_vop_dqalloc( ...@@ -1773,9 +1858,15 @@ xfs_qm_vop_dqalloc(
*O_gdqpp = gq; *O_gdqpp = gq;
else if (gq) else if (gq)
xfs_qm_dqrele(gq); xfs_qm_dqrele(gq);
if (O_pdqpp)
*O_pdqpp = pq;
else if (pq)
xfs_qm_dqrele(pq);
return 0; return 0;
error_rele: error_rele:
if (gq)
xfs_qm_dqrele(gq);
if (uq) if (uq)
xfs_qm_dqrele(uq); xfs_qm_dqrele(uq);
return error; return error;
...@@ -1830,14 +1921,17 @@ xfs_qm_vop_chown_reserve( ...@@ -1830,14 +1921,17 @@ xfs_qm_vop_chown_reserve(
struct xfs_inode *ip, struct xfs_inode *ip,
struct xfs_dquot *udqp, struct xfs_dquot *udqp,
struct xfs_dquot *gdqp, struct xfs_dquot *gdqp,
struct xfs_dquot *pdqp,
uint flags) uint flags)
{ {
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
uint delblks, blkflags, prjflags = 0; uint delblks, blkflags, prjflags = 0;
struct xfs_dquot *udq_unres = NULL; struct xfs_dquot *udq_unres = NULL;
struct xfs_dquot *gdq_unres = NULL; struct xfs_dquot *gdq_unres = NULL;
struct xfs_dquot *pdq_unres = NULL;
struct xfs_dquot *udq_delblks = NULL; struct xfs_dquot *udq_delblks = NULL;
struct xfs_dquot *gdq_delblks = NULL; struct xfs_dquot *gdq_delblks = NULL;
struct xfs_dquot *pdq_delblks = NULL;
int error; int error;
...@@ -1861,24 +1955,28 @@ xfs_qm_vop_chown_reserve( ...@@ -1861,24 +1955,28 @@ xfs_qm_vop_chown_reserve(
udq_unres = ip->i_udquot; udq_unres = ip->i_udquot;
} }
} }
if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) { if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp &&
if (XFS_IS_PQUOTA_ON(ip->i_mount) && ip->i_d.di_gid != be32_to_cpu(gdqp->q_core.d_id)) {
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))) {
gdq_delblks = gdqp; gdq_delblks = gdqp;
if (delblks) { if (delblks) {
ASSERT(ip->i_gdquot); ASSERT(ip->i_gdquot);
gdq_unres = 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;
}
} }
error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount, error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
udq_delblks, gdq_delblks, ip->i_d.di_nblocks, 1, udq_delblks, gdq_delblks, pdq_delblks,
ip->i_d.di_nblocks, 1,
flags | blkflags | prjflags); flags | blkflags | prjflags);
if (error) if (error)
return error; return error;
...@@ -1893,16 +1991,17 @@ xfs_qm_vop_chown_reserve( ...@@ -1893,16 +1991,17 @@ xfs_qm_vop_chown_reserve(
/* /*
* Do the reservations first. Unreservation can't fail. * Do the reservations first. Unreservation can't fail.
*/ */
ASSERT(udq_delblks || gdq_delblks); ASSERT(udq_delblks || gdq_delblks || pdq_delblks);
ASSERT(udq_unres || gdq_unres); ASSERT(udq_unres || gdq_unres || pdq_unres);
error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount, error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
udq_delblks, gdq_delblks, (xfs_qcnt_t)delblks, 0, udq_delblks, gdq_delblks, pdq_delblks,
(xfs_qcnt_t)delblks, 0,
flags | blkflags | prjflags); flags | blkflags | prjflags);
if (error) if (error)
return error; return error;
xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount, xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
udq_unres, gdq_unres, -((xfs_qcnt_t)delblks), 0, udq_unres, gdq_unres, pdq_unres,
blkflags); -((xfs_qcnt_t)delblks), 0, blkflags);
} }
return (0); return (0);
...@@ -1941,7 +2040,8 @@ xfs_qm_vop_create_dqattach( ...@@ -1941,7 +2040,8 @@ xfs_qm_vop_create_dqattach(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_inode *ip, struct xfs_inode *ip,
struct xfs_dquot *udqp, struct xfs_dquot *udqp,
struct xfs_dquot *gdqp) struct xfs_dquot *gdqp,
struct xfs_dquot *pdqp)
{ {
struct xfs_mount *mp = tp->t_mountp; struct xfs_mount *mp = tp->t_mountp;
...@@ -1961,13 +2061,18 @@ xfs_qm_vop_create_dqattach( ...@@ -1961,13 +2061,18 @@ xfs_qm_vop_create_dqattach(
} }
if (gdqp) { if (gdqp) {
ASSERT(ip->i_gdquot == NULL); ASSERT(ip->i_gdquot == NULL);
ASSERT(XFS_IS_OQUOTA_ON(mp)); ASSERT(XFS_IS_GQUOTA_ON(mp));
ASSERT((XFS_IS_GQUOTA_ON(mp) ? ASSERT(ip->i_d.di_gid == be32_to_cpu(gdqp->q_core.d_id));
ip->i_d.di_gid : xfs_get_projid(ip)) ==
be32_to_cpu(gdqp->q_core.d_id));
ip->i_gdquot = xfs_qm_dqhold(gdqp); ip->i_gdquot = xfs_qm_dqhold(gdqp);
xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1); 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);
}
} }
...@@ -44,9 +44,11 @@ extern struct kmem_zone *xfs_qm_dqtrxzone; ...@@ -44,9 +44,11 @@ extern struct kmem_zone *xfs_qm_dqtrxzone;
typedef struct xfs_quotainfo { typedef struct xfs_quotainfo {
struct radix_tree_root qi_uquota_tree; struct radix_tree_root qi_uquota_tree;
struct radix_tree_root qi_gquota_tree; struct radix_tree_root qi_gquota_tree;
struct radix_tree_root qi_pquota_tree;
struct mutex qi_tree_lock; struct mutex qi_tree_lock;
xfs_inode_t *qi_uquotaip; /* user quota inode */ struct xfs_inode *qi_uquotaip; /* user quota inode */
xfs_inode_t *qi_gquotaip; /* group 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 list_head qi_lru_list;
struct mutex qi_lru_lock; struct mutex qi_lru_lock;
int qi_lru_count; int qi_lru_count;
...@@ -78,8 +80,9 @@ xfs_dquot_tree( ...@@ -78,8 +80,9 @@ xfs_dquot_tree(
case XFS_DQ_USER: case XFS_DQ_USER:
return &qi->qi_uquota_tree; return &qi->qi_uquota_tree;
case XFS_DQ_GROUP: case XFS_DQ_GROUP:
case XFS_DQ_PROJ:
return &qi->qi_gquota_tree; return &qi->qi_gquota_tree;
case XFS_DQ_PROJ:
return &qi->qi_pquota_tree;
default: default:
ASSERT(0); ASSERT(0);
} }
...@@ -93,8 +96,9 @@ xfs_dq_to_quota_inode(struct xfs_dquot *dqp) ...@@ -93,8 +96,9 @@ xfs_dq_to_quota_inode(struct xfs_dquot *dqp)
case XFS_DQ_USER: case XFS_DQ_USER:
return dqp->q_mount->m_quotainfo->qi_uquotaip; return dqp->q_mount->m_quotainfo->qi_uquotaip;
case XFS_DQ_GROUP: case XFS_DQ_GROUP:
case XFS_DQ_PROJ:
return dqp->q_mount->m_quotainfo->qi_gquotaip; return dqp->q_mount->m_quotainfo->qi_gquotaip;
case XFS_DQ_PROJ:
return dqp->q_mount->m_quotainfo->qi_pquotaip;
default: default:
ASSERT(0); ASSERT(0);
} }
...@@ -107,18 +111,20 @@ extern void xfs_trans_mod_dquot(struct xfs_trans *, ...@@ -107,18 +111,20 @@ extern void xfs_trans_mod_dquot(struct xfs_trans *,
struct xfs_dquot *, uint, long); struct xfs_dquot *, uint, long);
extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *, extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *,
struct xfs_mount *, struct xfs_dquot *, struct xfs_mount *, struct xfs_dquot *,
struct xfs_dquot *, long, long, uint); struct xfs_dquot *, struct xfs_dquot *,
long, long, uint);
extern void xfs_trans_dqjoin(struct xfs_trans *, struct xfs_dquot *); extern void xfs_trans_dqjoin(struct xfs_trans *, struct xfs_dquot *);
extern void xfs_trans_log_dquot(struct xfs_trans *, struct xfs_dquot *); extern void xfs_trans_log_dquot(struct xfs_trans *, struct xfs_dquot *);
/* /*
* We keep the usr and grp dquots separately so that locking will be easier * We keep the usr, grp, and prj dquots separately so that locking will be
* to do at commit time. All transactions that we know of at this point * 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. * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value.
*/ */
enum { enum {
XFS_QM_TRANS_USR = 0, XFS_QM_TRANS_USR = 0,
XFS_QM_TRANS_GRP, XFS_QM_TRANS_GRP,
XFS_QM_TRANS_PRJ,
XFS_QM_TRANS_DQTYPES XFS_QM_TRANS_DQTYPES
}; };
#define XFS_QM_TRANS_MAXDQS 2 #define XFS_QM_TRANS_MAXDQS 2
......
...@@ -112,16 +112,16 @@ xfs_qm_newmount( ...@@ -112,16 +112,16 @@ xfs_qm_newmount(
if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) || if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
(!uquotaondisk && XFS_IS_UQUOTA_ON(mp)) || (!uquotaondisk && XFS_IS_UQUOTA_ON(mp)) ||
(pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
(!pquotaondisk && XFS_IS_PQUOTA_ON(mp)) ||
(gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) || (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
(!gquotaondisk && XFS_IS_OQUOTA_ON(mp))) && (!gquotaondisk && XFS_IS_GQUOTA_ON(mp)) ||
(pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
(!pquotaondisk && XFS_IS_PQUOTA_ON(mp))) &&
xfs_dev_is_read_only(mp, "changing quota state")) { xfs_dev_is_read_only(mp, "changing quota state")) {
xfs_warn(mp, "please mount with%s%s%s%s.", xfs_warn(mp, "please mount with%s%s%s%s.",
(!quotaondisk ? "out quota" : ""), (!quotaondisk ? "out quota" : ""),
(uquotaondisk ? " usrquota" : ""), (uquotaondisk ? " usrquota" : ""),
(pquotaondisk ? " prjquota" : ""), (gquotaondisk ? " grpquota" : ""),
(gquotaondisk ? " grpquota" : "")); (pquotaondisk ? " prjquota" : ""));
return XFS_ERROR(EPERM); return XFS_ERROR(EPERM);
} }
......
...@@ -119,7 +119,8 @@ xfs_qm_scall_quotaoff( ...@@ -119,7 +119,8 @@ xfs_qm_scall_quotaoff(
dqtype |= XFS_QMOPT_GQUOTA; dqtype |= XFS_QMOPT_GQUOTA;
flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD); flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
inactivate_flags |= XFS_GQUOTA_ACTIVE; inactivate_flags |= XFS_GQUOTA_ACTIVE;
} else if (flags & XFS_PQUOTA_ACCT) { }
if (flags & XFS_PQUOTA_ACCT) {
dqtype |= XFS_QMOPT_PQUOTA; dqtype |= XFS_QMOPT_PQUOTA;
flags |= (XFS_PQUOTA_CHKD | XFS_PQUOTA_ENFD); flags |= (XFS_PQUOTA_CHKD | XFS_PQUOTA_ENFD);
inactivate_flags |= XFS_PQUOTA_ACTIVE; inactivate_flags |= XFS_PQUOTA_ACTIVE;
...@@ -214,10 +215,14 @@ xfs_qm_scall_quotaoff( ...@@ -214,10 +215,14 @@ xfs_qm_scall_quotaoff(
IRELE(q->qi_uquotaip); IRELE(q->qi_uquotaip);
q->qi_uquotaip = NULL; 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); IRELE(q->qi_gquotaip);
q->qi_gquotaip = NULL; q->qi_gquotaip = NULL;
} }
if ((dqtype & XFS_QMOPT_PQUOTA) && q->qi_pquotaip) {
IRELE(q->qi_pquotaip);
q->qi_pquotaip = NULL;
}
out_unlock: out_unlock:
mutex_unlock(&q->qi_quotaofflock); mutex_unlock(&q->qi_quotaofflock);
...@@ -859,9 +864,11 @@ xfs_dqrele_inode( ...@@ -859,9 +864,11 @@ xfs_dqrele_inode(
{ {
/* skip quota inodes */ /* skip quota inodes */
if (ip == ip->i_mount->m_quotainfo->qi_uquotaip || 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_udquot == NULL);
ASSERT(ip->i_gdquot == NULL); ASSERT(ip->i_gdquot == NULL);
ASSERT(ip->i_pdquot == NULL);
return 0; return 0;
} }
...@@ -870,10 +877,14 @@ xfs_dqrele_inode( ...@@ -870,10 +877,14 @@ xfs_dqrele_inode(
xfs_qm_dqrele(ip->i_udquot); xfs_qm_dqrele(ip->i_udquot);
ip->i_udquot = NULL; 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); xfs_qm_dqrele(ip->i_gdquot);
ip->i_gdquot = NULL; 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); xfs_iunlock(ip, XFS_ILOCK_EXCL);
return 0; return 0;
} }
......
...@@ -288,10 +288,10 @@ typedef struct xfs_qoff_logformat { ...@@ -288,10 +288,10 @@ typedef struct xfs_qoff_logformat {
* we didn't have the inode locked, the appropriate dquot(s) will be * we didn't have the inode locked, the appropriate dquot(s) will be
* attached atomically. * attached atomically.
*/ */
#define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\ #define XFS_NOT_DQATTACHED(mp, ip) \
(ip)->i_udquot == NULL) || \ ((XFS_IS_UQUOTA_ON(mp) && (ip)->i_udquot == NULL) || \
(XFS_IS_OQUOTA_ON(mp) && \ (XFS_IS_GQUOTA_ON(mp) && (ip)->i_gdquot == NULL) || \
(ip)->i_gdquot == NULL)) (XFS_IS_PQUOTA_ON(mp) && (ip)->i_pdquot == NULL))
#define XFS_QM_NEED_QUOTACHECK(mp) \ #define XFS_QM_NEED_QUOTACHECK(mp) \
((XFS_IS_UQUOTA_ON(mp) && \ ((XFS_IS_UQUOTA_ON(mp) && \
...@@ -346,17 +346,18 @@ extern int xfs_trans_reserve_quota_nblks(struct xfs_trans *, ...@@ -346,17 +346,18 @@ extern int xfs_trans_reserve_quota_nblks(struct xfs_trans *,
struct xfs_inode *, long, long, uint); struct xfs_inode *, long, long, uint);
extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *, extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *,
struct xfs_mount *, struct xfs_dquot *, 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, 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 *, 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 int xfs_qm_vop_rename_dqattach(struct xfs_inode **);
extern struct xfs_dquot *xfs_qm_vop_chown(struct xfs_trans *, extern struct xfs_dquot *xfs_qm_vop_chown(struct xfs_trans *,
struct xfs_inode *, struct xfs_dquot **, struct xfs_dquot *); struct xfs_inode *, struct xfs_dquot **, struct xfs_dquot *);
extern int xfs_qm_vop_chown_reserve(struct xfs_trans *, struct xfs_inode *, 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(struct xfs_inode *, uint);
extern int xfs_qm_dqattach_locked(struct xfs_inode *, uint); extern int xfs_qm_dqattach_locked(struct xfs_inode *, uint);
extern void xfs_qm_dqdetach(struct xfs_inode *); extern void xfs_qm_dqdetach(struct xfs_inode *);
...@@ -370,10 +371,12 @@ extern void xfs_qm_unmount_quotas(struct xfs_mount *); ...@@ -370,10 +371,12 @@ extern void xfs_qm_unmount_quotas(struct xfs_mount *);
#else #else
static inline int static inline int
xfs_qm_vop_dqalloc(struct xfs_inode *ip, uid_t uid, gid_t gid, prid_t prid, 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; *udqp = NULL;
*gdqp = NULL; *gdqp = NULL;
*pdqp = NULL;
return 0; return 0;
} }
#define xfs_trans_dup_dqinfo(tp, tp2) #define xfs_trans_dup_dqinfo(tp, tp2)
...@@ -388,14 +391,15 @@ static inline int xfs_trans_reserve_quota_nblks(struct xfs_trans *tp, ...@@ -388,14 +391,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, static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp,
struct xfs_mount *mp, struct xfs_dquot *udqp, 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; 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_rename_dqattach(it) (0)
#define xfs_qm_vop_chown(tp, ip, old, new) (NULL) #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(ip, fl) (0)
#define xfs_qm_dqattach_locked(ip, fl) (0) #define xfs_qm_dqattach_locked(ip, fl) (0)
#define xfs_qm_dqdetach(ip) #define xfs_qm_dqdetach(ip)
...@@ -409,8 +413,8 @@ static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp, ...@@ -409,8 +413,8 @@ static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp,
#define xfs_trans_unreserve_quota_nblks(tp, ip, nblks, ninos, flags) \ #define xfs_trans_unreserve_quota_nblks(tp, ip, nblks, ninos, flags) \
xfs_trans_reserve_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) \ #define xfs_trans_reserve_quota(tp, mp, ud, gd, pd, nb, ni, f) \
xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, nb, ni, \ xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, pd, nb, ni, \
f | XFS_QMOPT_RES_REGBLKS) f | XFS_QMOPT_RES_REGBLKS)
extern int xfs_qm_dqcheck(struct xfs_mount *, xfs_disk_dquot_t *, extern int xfs_qm_dqcheck(struct xfs_mount *, xfs_disk_dquot_t *,
......
...@@ -360,6 +360,7 @@ xfs_symlink( ...@@ -360,6 +360,7 @@ xfs_symlink(
prid_t prid; prid_t prid;
struct xfs_dquot *udqp = NULL; struct xfs_dquot *udqp = NULL;
struct xfs_dquot *gdqp = NULL; struct xfs_dquot *gdqp = NULL;
struct xfs_dquot *pdqp = NULL;
uint resblks; uint resblks;
*ipp = NULL; *ipp = NULL;
...@@ -386,7 +387,7 @@ xfs_symlink( ...@@ -386,7 +387,7 @@ xfs_symlink(
* Make sure that we have allocated dquot(s) on disk. * Make sure that we have allocated dquot(s) on disk.
*/ */
error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid, 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) if (error)
goto std_return; goto std_return;
...@@ -427,7 +428,8 @@ xfs_symlink( ...@@ -427,7 +428,8 @@ xfs_symlink(
/* /*
* Reserve disk quota : blocks and inode. * 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) if (error)
goto error_return; goto error_return;
...@@ -465,7 +467,7 @@ xfs_symlink( ...@@ -465,7 +467,7 @@ xfs_symlink(
/* /*
* Also attach the dquot(s) to it, if applicable. * 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) if (resblks)
resblks -= XFS_IALLOC_SPACE_RES(mp); resblks -= XFS_IALLOC_SPACE_RES(mp);
...@@ -563,6 +565,7 @@ xfs_symlink( ...@@ -563,6 +565,7 @@ xfs_symlink(
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
xfs_qm_dqrele(udqp); xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp); xfs_qm_dqrele(gdqp);
xfs_qm_dqrele(pdqp);
*ipp = ip; *ipp = ip;
return 0; return 0;
...@@ -576,6 +579,7 @@ xfs_symlink( ...@@ -576,6 +579,7 @@ xfs_symlink(
xfs_trans_cancel(tp, cancel_flags); xfs_trans_cancel(tp, cancel_flags);
xfs_qm_dqrele(udqp); xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp); xfs_qm_dqrele(gdqp);
xfs_qm_dqrele(pdqp);
if (unlock_dp_on_error) if (unlock_dp_on_error)
xfs_iunlock(dp, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL);
......
...@@ -163,8 +163,10 @@ xfs_trans_mod_dquot_byino( ...@@ -163,8 +163,10 @@ xfs_trans_mod_dquot_byino(
if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot) if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot)
(void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta); (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); (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 struct xfs_dqtrx * STATIC struct xfs_dqtrx *
...@@ -177,8 +179,12 @@ xfs_trans_get_dqtrx( ...@@ -177,8 +179,12 @@ xfs_trans_get_dqtrx(
if (XFS_QM_ISUDQ(dqp)) if (XFS_QM_ISUDQ(dqp))
qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_USR]; qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_USR];
else else if (XFS_QM_ISGDQ(dqp))
qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_GRP]; qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_GRP];
else if (XFS_QM_ISPDQ(dqp))
qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_PRJ];
else
return NULL;
for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) { for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
if (qa[i].qt_dquot == NULL || if (qa[i].qt_dquot == NULL ||
...@@ -727,8 +733,8 @@ xfs_trans_dqresv( ...@@ -727,8 +733,8 @@ xfs_trans_dqresv(
/* /*
* Given dquot(s), make disk block and/or inode reservations against them. * Given dquot(s), make disk block and/or inode reservations against them.
* The fact that this does the reservation against both the usr and * The fact that this does the reservation against user, group and
* grp/prj quotas is important, because this follows a both-or-nothing * project quotas is important, because this follows a all-or-nothing
* approach. * approach.
* *
* flags = XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown. * flags = XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
...@@ -743,6 +749,7 @@ xfs_trans_reserve_quota_bydquots( ...@@ -743,6 +749,7 @@ xfs_trans_reserve_quota_bydquots(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_dquot *udqp, struct xfs_dquot *udqp,
struct xfs_dquot *gdqp, struct xfs_dquot *gdqp,
struct xfs_dquot *pdqp,
long nblks, long nblks,
long ninos, long ninos,
uint flags) uint flags)
...@@ -770,11 +777,21 @@ xfs_trans_reserve_quota_bydquots( ...@@ -770,11 +777,21 @@ xfs_trans_reserve_quota_bydquots(
goto unwind_usr; 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 * Didn't change anything critical, so, no need to log
*/ */
return 0; return 0;
unwind_grp:
flags |= XFS_QMOPT_FORCE_RES;
if (gdqp)
xfs_trans_dqresv(tp, mp, gdqp, -nblks, -ninos, flags);
unwind_usr: unwind_usr:
flags |= XFS_QMOPT_FORCE_RES; flags |= XFS_QMOPT_FORCE_RES;
if (udqp) if (udqp)
...@@ -816,6 +833,7 @@ xfs_trans_reserve_quota_nblks( ...@@ -816,6 +833,7 @@ xfs_trans_reserve_quota_nblks(
*/ */
return xfs_trans_reserve_quota_bydquots(tp, mp, return xfs_trans_reserve_quota_bydquots(tp, mp,
ip->i_udquot, ip->i_gdquot, ip->i_udquot, ip->i_gdquot,
ip->i_pdquot,
nblks, ninos, flags); nblks, ninos, flags);
} }
......
...@@ -489,6 +489,7 @@ xfs_create( ...@@ -489,6 +489,7 @@ xfs_create(
prid_t prid; prid_t prid;
struct xfs_dquot *udqp = NULL; struct xfs_dquot *udqp = NULL;
struct xfs_dquot *gdqp = NULL; struct xfs_dquot *gdqp = NULL;
struct xfs_dquot *pdqp = NULL;
uint resblks; uint resblks;
uint log_res; uint log_res;
uint log_count; uint log_count;
...@@ -507,7 +508,8 @@ xfs_create( ...@@ -507,7 +508,8 @@ xfs_create(
* Make sure that we have allocated dquot(s) on disk. * Make sure that we have allocated dquot(s) on disk.
*/ */
error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid, 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) if (error)
return error; return error;
...@@ -559,7 +561,8 @@ xfs_create( ...@@ -559,7 +561,8 @@ xfs_create(
/* /*
* Reserve disk quota and the inode. * 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) if (error)
goto out_trans_cancel; goto out_trans_cancel;
...@@ -623,7 +626,7 @@ xfs_create( ...@@ -623,7 +626,7 @@ xfs_create(
* These ids of the inode couldn't have changed since the new * These ids of the inode couldn't have changed since the new
* inode has been locked ever since it was created. * 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); error = xfs_bmap_finish(&tp, &free_list, &committed);
if (error) if (error)
...@@ -635,6 +638,7 @@ xfs_create( ...@@ -635,6 +638,7 @@ xfs_create(
xfs_qm_dqrele(udqp); xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp); xfs_qm_dqrele(gdqp);
xfs_qm_dqrele(pdqp);
*ipp = ip; *ipp = ip;
return 0; return 0;
...@@ -656,6 +660,7 @@ xfs_create( ...@@ -656,6 +660,7 @@ xfs_create(
xfs_qm_dqrele(udqp); xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp); xfs_qm_dqrele(gdqp);
xfs_qm_dqrele(pdqp);
if (unlock_dp_on_error) if (unlock_dp_on_error)
xfs_iunlock(dp, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL);
...@@ -1568,7 +1573,7 @@ xfs_free_file_space( ...@@ -1568,7 +1573,7 @@ xfs_free_file_space(
} }
xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_ilock(ip, XFS_ILOCK_EXCL);
error = xfs_trans_reserve_quota(tp, mp, 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); resblks, 0, XFS_QMOPT_RES_REGBLKS);
if (error) if (error)
goto error1; goto error1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment