|
@@ -134,8 +134,6 @@ 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) {
|
|
@@ -143,21 +141,6 @@ xfs_qm_dqpurge(
|
|
|
return EAGAIN;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * If this quota has a hint attached, prepare for releasing it now.
|
|
|
- */
|
|
|
- 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;
|
|
|
- }
|
|
|
-
|
|
|
dqp->dq_flags |= XFS_DQ_FREEING;
|
|
|
|
|
|
xfs_dqflock(dqp);
|
|
@@ -206,11 +189,47 @@ xfs_qm_dqpurge(
|
|
|
XFS_STATS_DEC(xs_qm_dquot_unused);
|
|
|
|
|
|
xfs_qm_dqdestroy(dqp);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Release the group or project dquot pointers the user dquots maybe carrying
|
|
|
+ * around as a hint, and proceed to purge the user dquot cache if requested.
|
|
|
+*/
|
|
|
+STATIC int
|
|
|
+xfs_qm_dqpurge_hints(
|
|
|
+ struct xfs_dquot *dqp,
|
|
|
+ void *data)
|
|
|
+{
|
|
|
+ struct xfs_dquot *gdqp = NULL;
|
|
|
+ struct xfs_dquot *pdqp = NULL;
|
|
|
+ uint flags = *((uint *)data);
|
|
|
+
|
|
|
+ xfs_dqlock(dqp);
|
|
|
+ if (dqp->dq_flags & XFS_DQ_FREEING) {
|
|
|
+ xfs_dqunlock(dqp);
|
|
|
+ return EAGAIN;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If this quota has a hint attached, prepare for releasing it now */
|
|
|
+ gdqp = dqp->q_gdquot;
|
|
|
+ if (gdqp)
|
|
|
+ dqp->q_gdquot = NULL;
|
|
|
+
|
|
|
+ pdqp = dqp->q_pdquot;
|
|
|
+ if (pdqp)
|
|
|
+ dqp->q_pdquot = NULL;
|
|
|
+
|
|
|
+ xfs_dqunlock(dqp);
|
|
|
|
|
|
if (gdqp)
|
|
|
- xfs_qm_dqput(gdqp);
|
|
|
+ xfs_qm_dqrele(gdqp);
|
|
|
if (pdqp)
|
|
|
- xfs_qm_dqput(pdqp);
|
|
|
+ xfs_qm_dqrele(pdqp);
|
|
|
+
|
|
|
+ if (flags & XFS_QMOPT_UQUOTA)
|
|
|
+ return xfs_qm_dqpurge(dqp, NULL);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -222,8 +241,18 @@ xfs_qm_dqpurge_all(
|
|
|
struct xfs_mount *mp,
|
|
|
uint flags)
|
|
|
{
|
|
|
- if (flags & XFS_QMOPT_UQUOTA)
|
|
|
- xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge, NULL);
|
|
|
+ /*
|
|
|
+ * We have to release group/project dquot hint(s) from the user dquot
|
|
|
+ * at first if they are there, otherwise we would run into an infinite
|
|
|
+ * loop while walking through radix tree to purge other type of dquots
|
|
|
+ * since their refcount is not zero if the user dquot refers to them
|
|
|
+ * as hint.
|
|
|
+ *
|
|
|
+ * Call the special xfs_qm_dqpurge_hints() will end up go through the
|
|
|
+ * general xfs_qm_dqpurge() against user dquot cache if requested.
|
|
|
+ */
|
|
|
+ xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge_hints, &flags);
|
|
|
+
|
|
|
if (flags & XFS_QMOPT_GQUOTA)
|
|
|
xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_dqpurge, NULL);
|
|
|
if (flags & XFS_QMOPT_PQUOTA)
|